A PropertyAttribute/PropertyDrawer combination that allows for properties in Unity

https://github.com/LMNRY/SetProperty

// Copyright (c) 2014 Luminary LLC
// Licensed under The MIT License (See LICENSE for full text)
using UnityEngine;
using UnityEditor;
using System;
using System.Collections;
using System.Reflection;

[CustomPropertyDrawer(typeof(SetPropertyAttribute))]
public class SetPropertyDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        // Rely on the default inspector GUI
        EditorGUI.BeginChangeCheck ();
        EditorGUI.PropertyField(position, property, label);

        // Update only when necessary
        SetPropertyAttribute setProperty = attribute as SetPropertyAttribute;
        if (EditorGUI.EndChangeCheck())
        {
            // When a SerializedProperty is modified the actual field does not have the current value set (i.e.  
            // FieldInfo.GetValue() will return the prior value that was set) until after this OnGUI call has completed. 
            // Therefore, we need to mark this property as dirty, so that it can be updated with a subsequent OnGUI event 
            // (e.g. Repaint)
            setProperty.IsDirty = true;
        } 
        else if (setProperty.IsDirty)
        {
            // The propertyPath may reference something that is a child field of a field on this Object, so it is necessary
            // to find which object is the actual parent before attempting to set the property with the current value.
            object parent = GetParentObjectOfProperty(property.propertyPath, property.serializedObject.targetObject);
            Type type = parent.GetType();
            PropertyInfo pi = type.GetProperty(setProperty.Name);
            if (pi == null)
            {
                Debug.LogError("Invalid property name: " + setProperty.Name + "\nCheck your [SetProperty] attribute");
            }
            else
            {
                // Use FieldInfo instead of the SerializedProperty accessors as we'd have to deal with every 
                // SerializedPropertyType and use the correct accessor
                pi.SetValue(parent, fieldInfo.GetValue(parent), null);
            }
            setProperty.IsDirty = false;
        }
    }
    
    private object GetParentObjectOfProperty(string path, object obj)
    {
        string[] fields = path.Split('.');

        // We've finally arrived at the final object that contains the property
        if (fields.Length == 1)
        {
            return obj;
        }

        // We may have to walk public or private fields along the chain to finding our container object, so we have to allow for both
        FieldInfo fi = obj.GetType().GetField(fields[0], BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
        obj = fi.GetValue(obj);

        // Keep searching for our object that contains the property
        return GetParentObjectOfProperty(string.Join(".", fields, 1, fields.Length - 1), obj);
    }
}
// Copyright (c) 2014 Luminary LLC
// Licensed under The MIT License (See LICENSE for full text)
using UnityEngine;
using System.Collections;

public class SetPropertyAttribute : PropertyAttribute
{
    public string Name { get; private set; }
    public bool IsDirty { get; set; }

    public SetPropertyAttribute(string name)
    {
        this.Name = name;
    }
}
// Copyright (c) 2014 Luminary LLC
// Licensed under The MIT License (See LICENSE for full text)
using UnityEngine;
using System.Collections;

public class SetPropertyExample : MonoBehaviour 
{
    [System.Serializable]
    public class VanillaClass
    {
        public enum ExtraType
        {
            None,
            HotFudge,
            Mint,
        }

        [SerializeField, SetProperty("Extra")]
        private ExtraType extra;
        public ExtraType Extra
        {
            get
            {
                return extra;
            }
            set
            {
                extra = value;

                // For illustrative purposes
                if (value == ExtraType.None)
                {
                    Debug.Log("Simple!");
                }
                else
                {
                    Debug.Log ("Yummy!");
                }
            }
        }
    }

    [SerializeField, SetProperty("Number")]
    private float number;
    public float Number
    {
        get
        {
            return number;
        }
        private set
        {
            number = Mathf.Clamp01(value);
        }
    }

    [SerializeField, SetProperty("Text")]
    private string text;
    public string Text
    {
        get
        {
            return text;
        }
        set
        {
            text = value.ToUpper();
        }
    }

    public VanillaClass vanilla;
}

你可能感兴趣的:(A PropertyAttribute/PropertyDrawer combination that allows for properties in Unity)