// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik // #if UNITY_EDITOR using System; using System.Collections.Generic; using System.Reflection; using UnityEditor; using UnityEngine; namespace Animancer.Editor { /// [Editor-Only] A cache to optimize repeated attribute access. /// /// If implements for , /// its method will be called automatically. /// /// https://kybernetik.com.au/animancer/api/Animancer.Editor/AttributeCache_1 public static class AttributeCache where TAttribute : class { /************************************************************************************************************************/ private static readonly Dictionary MemberToAttribute = new(); /************************************************************************************************************************/ /// /// Returns the attribute on the specified `member` (if there is one). /// public static TAttribute GetAttribute(MemberInfo member) { if (!MemberToAttribute.TryGetValue(member, out var attribute)) { try { attribute = member.GetAttribute(); if (attribute is IInitializable initializable) initializable.Initialize(member); } catch (Exception exception) { Debug.LogException(exception); attribute = null; } MemberToAttribute.Add(member, attribute); } return attribute; } /************************************************************************************************************************/ /// /// Returns the attribute (if any) /// on the specified `type` or its (recursively). /// public static TAttribute GetAttribute(Type type) { if (type == null) return null; var attribute = GetAttribute((MemberInfo)type); if (attribute != null) return attribute; return MemberToAttribute[type] = GetAttribute(type.BaseType); } /************************************************************************************************************************/ /// /// Returns the attribute on the specified `field` or its /// or . /// public static TAttribute FindAttribute(FieldInfo field) { var attribute = GetAttribute(field); if (attribute != null) return attribute; attribute = GetAttribute(field.FieldType); if (attribute != null) return MemberToAttribute[field] = attribute; attribute = GetAttribute(field.DeclaringType); if (attribute != null) return MemberToAttribute[field] = attribute; return attribute; } /************************************************************************************************************************/ /// [Editor-Only] /// Returns the attribute on the underlying field /// of the `property` or its or /// or any of the parent properties /// or the type of the . /// public static TAttribute FindAttribute(SerializedProperty property) { var accessor = property.GetAccessor(); while (accessor != null) { var field = accessor.GetField(property); var attribute = GetAttribute(field); if (attribute != null) return attribute; var value = accessor.GetValue(property); if (value != null) { attribute = GetAttribute(value.GetType()); if (attribute != null) return attribute; } accessor = accessor.Parent; } // If none of the fields of types they are declared in have names, try the actual type of the target. { var attribute = GetAttribute(property.serializedObject.targetObject.GetType()); if (attribute != null) return attribute; } return null; } /************************************************************************************************************************/ } } #endif