using System; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; #if UNITY_EDITOR using UnityEditor; #endif namespace Jovian.InspectorTools { public class AnimatorParameterAttribute : PropertyAttribute { public readonly string animatorPropertyName; public bool allParameterTypes; public AnimatorControllerParameterType parameterType; public AnimatorParameterAttribute(string animatorPropertyName) { this.animatorPropertyName = animatorPropertyName; allParameterTypes = true; } public AnimatorParameterAttribute(string animatorPropertyName, AnimatorControllerParameterType parameterType) { this.animatorPropertyName = animatorPropertyName; allParameterTypes = false; this.parameterType = parameterType; } } } #if UNITY_EDITOR namespace Jovian.InspectorTools.Internal { [CustomPropertyDrawer(typeof(AnimatorParameterAttribute))] public class AnimatorParameterAttributeDrawer : PropertyDrawer { private bool hasAnimator; private Animator animator; private string[] parameterNames; public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { label = EditorGUI.BeginProperty(position, label, property); position = EditorGUI.PrefixLabel(position, label); if(parameterNames == null) { var animatorParameterAttribute = (AnimatorParameterAttribute)attribute; string animatorFieldName = animatorParameterAttribute.animatorPropertyName; parameterNames = UpdateParameterNames(property, animatorFieldName, animatorParameterAttribute.allParameterTypes, animatorParameterAttribute.parameterType); } EditorGUI.BeginChangeCheck(); bool didChange = false; if(parameterNames is { Length: > 0 }) { int parameterIndex = Array.IndexOf(parameterNames, property.stringValue); int newIndex = EditorGUI.Popup(position, parameterIndex, parameterNames); if(parameterIndex != newIndex) { property.stringValue = parameterNames[newIndex]; didChange = true; } } else { EditorGUI.PropertyField(position, property, GUIContent.none); } int indentLevel = EditorGUI.indentLevel; EditorGUI.indentLevel = 0; if(EditorGUI.EndChangeCheck() || didChange) { property.serializedObject.ApplyModifiedProperties(); } EditorGUI.indentLevel = indentLevel; EditorGUI.EndProperty(); } private string[] UpdateParameterNames(SerializedProperty property, string animatorFieldName, bool allParameterTypesAllowed, AnimatorControllerParameterType parameterType) { int pathIndexOfPropertyName = property.propertyPath.LastIndexOf(property.name, StringComparison.Ordinal); bool isTopLevelObject = pathIndexOfPropertyName == 0; SerializedProperty animatorProperty; if(isTopLevelObject) { animatorProperty = property.serializedObject.FindProperty(animatorFieldName); } else { SerializedProperty parentProperty = property.serializedObject.FindProperty(property.propertyPath.Substring(0, pathIndexOfPropertyName - 1)); animatorProperty = parentProperty.FindPropertyRelative(animatorFieldName); } if(animatorProperty is { objectReferenceValue: Animator targetAnimator }) { if(!targetAnimator.gameObject.activeSelf || !targetAnimator.gameObject.activeInHierarchy || targetAnimator.runtimeAnimatorController == null) { return new string[] { }; // return an empty array so it uses the fallback of just text } AnimatorControllerParameter[] parameters = targetAnimator.parameters; if(allParameterTypesAllowed) { return parameters.Select(p => p.name).ToArray(); } else { return parameters.Where(p => p.type == parameterType).Select(p => p.name).ToArray(); } } return new[] { "" }; } } } #endif