using System; using System.Reflection; using UnityEngine; using UnityEditor; using Object = UnityEngine.Object; namespace Core.Utilities.Editor { /// /// Property drawer for serializable interfaces /// [CustomPropertyDrawer(typeof(SerializableInterface), true)] public class SerializableInterfaceDrawer : PropertyDrawer { /// /// Cached interface type that we get generically /// Type m_CachedInterfaceType; public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { SerializedProperty gameObjectProperty = property.FindPropertyRelative("unityObjectReference"); // Try and find the interface type we need to filter for // Use ISerializableInterface by default Type interfaceType = typeof(ISerializableInterface); Object containingObject = property.serializedObject.targetObject; Type containingObjectType = property.serializedObject.targetObject.GetType(); FieldInfo field = GetNestedField(containingObjectType, property.propertyPath); if (field != null) { Type serializableInterfaceType = FindAncestorSerializableType(field.FieldType); interfaceType = serializableInterfaceType.GetGenericArguments()[0]; } EditorGUI.BeginProperty(position, label, property); EditorGUI.ObjectField(position, gameObjectProperty, interfaceType, new GUIContent(property.displayName)); EditorGUI.EndProperty(); } static FieldInfo GetNestedField(Type owningType, string fieldPath) { while (true) { int firstDotIndex = fieldPath.IndexOf(".", StringComparison.Ordinal); if (firstDotIndex > 0) { // Get first type and recurse in string parentFieldName = fieldPath.Substring(0, firstDotIndex); FieldInfo parentField = owningType.GetField(parentFieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (parentField == null) { return null; } owningType = parentField.FieldType; fieldPath = fieldPath.Substring(firstDotIndex + 1); } else { return owningType.GetField(fieldPath, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } } } static Type FindAncestorSerializableType(Type childType) { while (childType != null && !childType.IsGenericType && childType != typeof(SerializableInterface<>)) { childType = childType.BaseType; } return childType; } } }