// MIT License - Copyright (c) 2025 wallstop // Full license text: https://github.com/wallstop/unity-helpers/blob/main/LICENSE namespace WallstopStudios.UnityHelpers.Core.Attributes { using System; using System.Collections.Generic; using System.Reflection; using UnityEngine; /// /// Specifies the type of message displayed in the inspector when a field is null. /// public enum WNotNullMessageType { /// /// Displays as a warning (yellow) in the inspector. /// Warning = 0, /// /// Displays as an error (red) in the inspector. /// Error = 1, } /// /// Validates that a field is not null. Displays a warning or error in the inspector when the field is null, /// and throws an when /// is called on an object containing a null field marked with this attribute. /// /// /// /// public class PlayerController : MonoBehaviour /// { /// [WNotNull] /// public Rigidbody2D rb; /// /// [WNotNull(WNotNullMessageType.Error, "Audio source is required for sound effects")] /// public AudioSource audioSource; /// /// private void Awake() /// { /// this.CheckForNulls(); /// } /// } /// /// [AttributeUsage(AttributeTargets.Field)] public sealed class WNotNullAttribute : PropertyAttribute { /// /// The type of message to display in the inspector when the field is null. /// public WNotNullMessageType MessageType { get; } /// /// An optional custom message to display in the inspector when the field is null. /// If null or empty, a default message will be generated based on the field name. /// public string CustomMessage { get; } /// /// Creates a new WNotNull attribute with default settings (warning message type, auto-generated message). /// public WNotNullAttribute() : this(WNotNullMessageType.Warning, null) { } /// /// Creates a new WNotNull attribute with the specified message type and auto-generated message. /// /// The type of message to display when null. public WNotNullAttribute(WNotNullMessageType messageType) : this(messageType, null) { } /// /// Creates a new WNotNull attribute with default message type (warning) and a custom message. /// /// The custom message to display when null. public WNotNullAttribute(string customMessage) : this(WNotNullMessageType.Warning, customMessage) { } /// /// Creates a new WNotNull attribute with the specified message type and custom message. /// /// The type of message to display when null. /// The custom message to display when null. public WNotNullAttribute(WNotNullMessageType messageType, string customMessage) { MessageType = messageType; CustomMessage = customMessage; } } public static class WNotNullAttributeExtensions { public static void CheckForNulls(this object o) { #if UNITY_EDITOR if (o == null || (o is UnityEngine.Object unityObj && unityObj == null)) { return; } IEnumerable properties = Helper.ReflectionHelpers.GetFieldsWithAttribute(o.GetType()); foreach (FieldInfo field in properties) { object fieldValue = field.GetValue(o); switch (fieldValue) { case UnityEngine.Object unityObject when unityObject == null: throw new ArgumentNullException(field.Name); case null: throw new ArgumentNullException(field.Name); } } #endif } } }