using System; using System.Reflection; using UnityEditor; using UnityEngine; namespace UnityAtoms.Editor { public static class SerializedPropertyExtensions { /// /// Generic method that tries to retrieve a value from a SerializedProperty of a specfic type. /// /// The SerializedProperty. /// Managed object. /// /// The value of type T. public static T GetGenericPropertyValue(this SerializedProperty property, T managedObjectOut) { object box = managedObjectOut; var type = managedObjectOut.GetType(); foreach (var field in type.GetFields(BindingFlags.Instance | BindingFlags.Public)) { try { field.SetValue(box, property.FindPropertyRelative(field.Name).GetPropertyValue()); } catch (InvalidOperationException) { } } return (T)box; } /// /// Get property value from SerializedProperty. /// /// The SerializedProperty. /// The value as an object. public static object GetPropertyValue(this SerializedProperty property) { if (property == null) throw new ArgumentNullException(nameof(property)); switch (property.propertyType) { case SerializedPropertyType.ObjectReference: return property.objectReferenceValue; case SerializedPropertyType.ArraySize: return property.arraySize; case SerializedPropertyType.Integer: return property.intValue; case SerializedPropertyType.Boolean: return property.boolValue; case SerializedPropertyType.Float: return property.floatValue; case SerializedPropertyType.String: return property.stringValue; case SerializedPropertyType.Color: return property.colorValue; case SerializedPropertyType.LayerMask: return (LayerMask)property.intValue; case SerializedPropertyType.Enum: return property.enumValueIndex; case SerializedPropertyType.Vector2: return property.vector2Value; case SerializedPropertyType.Vector3: return property.vector3Value; case SerializedPropertyType.Vector4: return property.vector4Value; case SerializedPropertyType.Vector2Int: return property.vector2IntValue; case SerializedPropertyType.Vector3Int: return property.vector3IntValue; case SerializedPropertyType.Quaternion: return property.quaternionValue; case SerializedPropertyType.Rect: return property.rectValue; case SerializedPropertyType.RectInt: return property.rectIntValue; case SerializedPropertyType.BoundsInt: return property.boundsIntValue; case SerializedPropertyType.Bounds: return property.boundsValue; case SerializedPropertyType.Character: return (char)property.intValue; case SerializedPropertyType.AnimationCurve: return property.animationCurveValue; case SerializedPropertyType.FixedBufferSize: return property.fixedBufferSize; case SerializedPropertyType.ExposedReference: return property.exposedReferenceValue; case SerializedPropertyType.Generic: case SerializedPropertyType.Gradient: throw new InvalidOperationException($"Cant handle {property.propertyType} types. for property {property.name}"); default: throw new NotImplementedException(); } } /// /// Determine if a SerializedProperty array contains an int value. /// /// The SerializedProperty. /// The value to check if it exists. /// True if the int exists in the array, otherwise false. public static bool ArrayContainsInt(this SerializedProperty property, int value) { if (!property.isArray) { throw new ArgumentException("property is not an array"); } for (int i = 0; i < property.arraySize; ++i) { var intVal = property.GetArrayElementAtIndex(i).intValue; if (intVal.Equals(value)) return true; } return false; } /// /// Helper method to remove an element from a SerializedProperty array. Needed because of quirks using DeleteArrayElementAtIndex. /// /// The SerializedProperty. /// The index to delete from array. public static void RemoveArrayElement(this SerializedProperty property, int index) { if (!property.isArray) { throw new ArgumentException("property is not an array"); } // For some reason you need to set objectReferenceValue to null in order to delete an array element from an array. var itemProp = property.GetArrayElementAtIndex(index); if (itemProp.propertyType == SerializedPropertyType.ObjectReference && itemProp.objectReferenceValue != null) itemProp.objectReferenceValue = null; // For some reason it is not possible to delete last element in array with DeleteArrayElementAtIndex. if (index == property.arraySize - 1) { property.arraySize--; } else { property.DeleteArrayElementAtIndex(index); } } } }