using System.Collections.Generic; using System.Reflection; using UnityEditor; using UnityEditor.Animations; using UnityEngine; namespace NaughtyAttributes.Editor { [CustomPropertyDrawer(typeof(AnimatorParamAttribute))] public class AnimatorParamPropertyDrawer : PropertyDrawerBase { private const string InvalidAnimatorControllerWarningMessage = "Target animator controller is null"; private const string InvalidTypeWarningMessage = "{0} must be an int or a string"; protected override float GetPropertyHeight_Internal(SerializedProperty property, GUIContent label) { AnimatorParamAttribute animatorParamAttribute = PropertyUtility.GetAttribute(property); bool validAnimatorController = GetAnimatorController(property, animatorParamAttribute.AnimatorName) != null; bool validPropertyType = property.propertyType == SerializedPropertyType.Integer || property.propertyType == SerializedPropertyType.String; return (validAnimatorController && validPropertyType) ? GetPropertyHeight(property) : GetPropertyHeight(property) + GetHelpBoxHeight(); } protected override void OnGUI_Internal(Rect rect, SerializedProperty property, GUIContent label) { EditorGUI.BeginProperty(rect, label, property); AnimatorParamAttribute animatorParamAttribute = PropertyUtility.GetAttribute(property); AnimatorController animatorController = GetAnimatorController(property, animatorParamAttribute.AnimatorName); if (animatorController == null) { DrawDefaultPropertyAndHelpBox(rect, property, InvalidAnimatorControllerWarningMessage, MessageType.Warning); return; } int parametersCount = animatorController.parameters.Length; List animatorParameters = new List(parametersCount); for (int i = 0; i < parametersCount; i++) { AnimatorControllerParameter parameter = animatorController.parameters[i]; if (animatorParamAttribute.AnimatorParamType == null || parameter.type == animatorParamAttribute.AnimatorParamType) { animatorParameters.Add(parameter); } } switch (property.propertyType) { case SerializedPropertyType.Integer: DrawPropertyForInt(rect, property, label, animatorParameters); break; case SerializedPropertyType.String: DrawPropertyForString(rect, property, label, animatorParameters); break; default: DrawDefaultPropertyAndHelpBox(rect, property, string.Format(InvalidTypeWarningMessage, property.name), MessageType.Warning); break; } EditorGUI.EndProperty(); } private static void DrawPropertyForInt(Rect rect, SerializedProperty property, GUIContent label, List animatorParameters) { int paramNameHash = property.intValue; int index = 0; for (int i = 0; i < animatorParameters.Count; i++) { if (paramNameHash == animatorParameters[i].nameHash) { index = i + 1; // +1 because the first option is reserved for (None) break; } } string[] displayOptions = GetDisplayOptions(animatorParameters); int newIndex = EditorGUI.Popup(rect, label.text, index, displayOptions); int newValue = newIndex == 0 ? 0 : animatorParameters[newIndex - 1].nameHash; if (property.intValue != newValue) { property.intValue = newValue; } } private static void DrawPropertyForString(Rect rect, SerializedProperty property, GUIContent label, List animatorParameters) { string paramName = property.stringValue; int index = 0; for (int i = 0; i < animatorParameters.Count; i++) { if (paramName.Equals(animatorParameters[i].name, System.StringComparison.Ordinal)) { index = i + 1; // +1 because the first option is reserved for (None) break; } } string[] displayOptions = GetDisplayOptions(animatorParameters); int newIndex = EditorGUI.Popup(rect, label.text, index, displayOptions); string newValue = newIndex == 0 ? null : animatorParameters[newIndex - 1].name; if (!property.stringValue.Equals(newValue, System.StringComparison.Ordinal)) { property.stringValue = newValue; } } private static string[] GetDisplayOptions(List animatorParams) { string[] displayOptions = new string[animatorParams.Count + 1]; displayOptions[0] = "(None)"; for (int i = 0; i < animatorParams.Count; i++) { displayOptions[i + 1] = animatorParams[i].name; } return displayOptions; } private static AnimatorController GetAnimatorController(SerializedProperty property, string animatorName) { object target = PropertyUtility.GetTargetObjectWithProperty(property); FieldInfo animatorFieldInfo = ReflectionUtility.GetField(target, animatorName); if (animatorFieldInfo != null && animatorFieldInfo.FieldType == typeof(Animator)) { Animator animator = animatorFieldInfo.GetValue(target) as Animator; if (animator != null) { AnimatorController animatorController = animator.runtimeAnimatorController as AnimatorController; return animatorController; } } PropertyInfo animatorPropertyInfo = ReflectionUtility.GetProperty(target, animatorName); if (animatorPropertyInfo != null && animatorPropertyInfo.PropertyType == typeof(Animator)) { Animator animator = animatorPropertyInfo.GetValue(target) as Animator; if (animator != null) { AnimatorController animatorController = animator.runtimeAnimatorController as AnimatorController; return animatorController; } } MethodInfo animatorGetterMethodInfo = ReflectionUtility.GetMethod(target, animatorName); if (animatorGetterMethodInfo != null && animatorGetterMethodInfo.ReturnType == typeof(Animator) && animatorGetterMethodInfo.GetParameters().Length == 0) { Animator animator = animatorGetterMethodInfo.Invoke(target, null) as Animator; if (animator != null) { AnimatorController animatorController = animator.runtimeAnimatorController as AnimatorController; return animatorController; } } return null; } } }