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;
}
网友评论