Created
August 6, 2022 07:45
-
-
Save takazerker/335b7769db45c2cebccbbf5bf43bafe4 to your computer and use it in GitHub Desktop.
Adds state and parameter selectors.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//============================================================================= | |
// Licensed under CC0. Takanori Shibasaki | |
//============================================================================= | |
using System.Collections.Generic; | |
using System.Runtime.CompilerServices; | |
using UnityEngine; | |
[System.Serializable] | |
public struct AnimatorStateName | |
{ | |
[SerializeField] | |
internal int m_Hash; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static implicit operator int(AnimatorStateName name) | |
{ | |
return name.m_Hash; | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static implicit operator bool(AnimatorStateName name) | |
{ | |
return name.m_Hash != 0; | |
} | |
} | |
[System.Serializable] | |
public struct AnimatorParameterName | |
{ | |
[SerializeField] | |
internal int m_Hash; | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static implicit operator int(AnimatorParameterName name) | |
{ | |
return name.m_Hash; | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static implicit operator bool(AnimatorParameterName name) | |
{ | |
return name.m_Hash != 0; | |
} | |
} | |
#if UNITY_EDITOR | |
abstract class AnimatorPropertyDrawer : UnityEditor.PropertyDrawer | |
{ | |
class AnimatorList : List<Animator> | |
{ | |
public bool Created; | |
} | |
protected static List<Animator> GetAnimators(UnityEditor.SerializedProperty property) | |
{ | |
var controlID = GUIUtility.GetControlID(FocusType.Passive); | |
var animatorList = GUIUtility.GetStateObject(typeof(AnimatorList), controlID) as AnimatorList; | |
if (animatorList.Created) | |
{ | |
return animatorList; | |
} | |
foreach (var obj in property.serializedObject.targetObjects) | |
{ | |
if (obj is Component component) | |
{ | |
var animator = component.GetComponent<Animator>(); | |
if (animator != null) | |
{ | |
animatorList.Add(animator); | |
continue; | |
} | |
} | |
animatorList.Clear(); | |
break; | |
} | |
animatorList.Created = true; | |
return animatorList; | |
} | |
} | |
[UnityEditor.CustomPropertyDrawer(typeof(AnimatorStateName))] | |
class AnimatorStateNameDrawer : AnimatorPropertyDrawer | |
{ | |
static SortedList<string, int> m_StateNames = new SortedList<string, int>(); | |
static List<string> m_Options = new List<string>(); | |
static List<int> m_Values = new List<int>(); | |
static void GetStateNames(List<Animator> animators, SortedList<string, int> result) | |
{ | |
static void GetStateNames(UnityEditor.Animations.AnimatorStateMachine stateMachine, SortedList<string, int> result) | |
{ | |
foreach (var childState in stateMachine.states) | |
{ | |
var hash = Animator.StringToHash(childState.state.name); | |
result[childState.state.name] = hash; | |
} | |
foreach (var childStateMachine in stateMachine.stateMachines) | |
{ | |
if (!string.IsNullOrEmpty(childStateMachine.stateMachine.name)) | |
{ | |
var hash = Animator.StringToHash(childStateMachine.stateMachine.name); | |
result[childStateMachine.stateMachine.name] = hash; | |
} | |
GetStateNames(childStateMachine.stateMachine, result); | |
} | |
} | |
result.Clear(); | |
foreach (var animator in animators) | |
{ | |
if (animator.runtimeAnimatorController is UnityEditor.Animations.AnimatorController controller) | |
{ | |
foreach (var layer in controller.layers) | |
{ | |
GetStateNames(layer.stateMachine, m_StateNames); | |
} | |
} | |
} | |
} | |
public override void OnGUI(Rect position, UnityEditor.SerializedProperty property, GUIContent label) | |
{ | |
var animators = GetAnimators(property); | |
if (animators.Count <= 0) | |
{ | |
return; | |
} | |
GetStateNames(animators, m_StateNames); | |
m_Options.Clear(); | |
m_Values.Clear(); | |
m_Options.Add("[None]"); | |
m_Values.Add(0); | |
foreach (var pair in m_StateNames) | |
{ | |
m_Options.Add(pair.Key); | |
m_Values.Add(pair.Value); | |
} | |
var selection = -1; | |
var hashProperty = property.FindPropertyRelative(nameof(AnimatorStateName.m_Hash)); | |
UnityEditor.EditorGUI.showMixedValue = property.hasMultipleDifferentValues; | |
if (!UnityEditor.EditorGUI.showMixedValue) | |
{ | |
if (hashProperty.intValue == 0) | |
{ | |
selection = 0; | |
} | |
else | |
{ | |
selection = m_StateNames.IndexOfValue(hashProperty.intValue) + 1; | |
if (selection == 0) | |
{ | |
selection = m_Options.Count; | |
m_Options.Add($"Unknown State {hashProperty.intValue}"); | |
m_Values.Add(property.intValue); | |
} | |
} | |
} | |
UnityEditor.EditorGUI.BeginChangeCheck(); | |
selection = UnityEditor.EditorGUI.Popup(position, label.text, selection, m_Options.ToArray()); | |
if (UnityEditor.EditorGUI.EndChangeCheck()) | |
{ | |
hashProperty.intValue = m_Values[selection]; | |
} | |
} | |
public override float GetPropertyHeight(UnityEditor.SerializedProperty property, GUIContent label) | |
{ | |
var animators = GetAnimators(property); | |
return 0 < animators.Count ? base.GetPropertyHeight(property, label) : 0; | |
} | |
} | |
[UnityEditor.CustomPropertyDrawer(typeof(AnimatorParameterName))] | |
class AnimatorParameterNameDrawer : AnimatorPropertyDrawer | |
{ | |
static SortedList<string, int> m_ParameterNames = new SortedList<string, int>(); | |
static List<string> m_Options = new List<string>(); | |
static List<int> m_Values = new List<int>(); | |
static void GetParameterNames(List<Animator> animators, SortedList<string, int> result) | |
{ | |
result.Clear(); | |
foreach (var animator in animators) | |
{ | |
if (animator.runtimeAnimatorController is UnityEditor.Animations.AnimatorController controller) | |
{ | |
foreach (var parameter in controller.parameters) | |
{ | |
result[parameter.name] = parameter.nameHash; | |
} | |
} | |
} | |
} | |
public override void OnGUI(Rect position, UnityEditor.SerializedProperty property, GUIContent label) | |
{ | |
var animators = GetAnimators(property); | |
if (animators.Count <= 0) | |
{ | |
return; | |
} | |
GetParameterNames(animators, m_ParameterNames); | |
m_Options.Clear(); | |
m_Values.Clear(); | |
m_Options.Add("[None]"); | |
m_Values.Add(0); | |
foreach (var pair in m_ParameterNames) | |
{ | |
m_Options.Add(pair.Key); | |
m_Values.Add(pair.Value); | |
} | |
var selection = -1; | |
var hashProperty = property.FindPropertyRelative(nameof(AnimatorStateName.m_Hash)); | |
UnityEditor.EditorGUI.showMixedValue = property.hasMultipleDifferentValues; | |
if (!UnityEditor.EditorGUI.showMixedValue) | |
{ | |
if (hashProperty.intValue == 0) | |
{ | |
selection = 0; | |
} | |
else | |
{ | |
selection = m_ParameterNames.IndexOfValue(hashProperty.intValue) + 1; | |
if (selection == 0) | |
{ | |
selection = m_Options.Count; | |
m_Options.Add($"Unknown Parameter {hashProperty.intValue}"); | |
m_Values.Add(property.intValue); | |
} | |
} | |
} | |
UnityEditor.EditorGUI.BeginChangeCheck(); | |
selection = UnityEditor.EditorGUI.Popup(position, label.text, selection, m_Options.ToArray()); | |
if (UnityEditor.EditorGUI.EndChangeCheck()) | |
{ | |
hashProperty.intValue = m_Values[selection]; | |
} | |
} | |
public override float GetPropertyHeight(UnityEditor.SerializedProperty property, GUIContent label) | |
{ | |
var animators = GetAnimators(property); | |
return 0 < animators.Count ? base.GetPropertyHeight(property, label) : 0; | |
} | |
} | |
#endif // UNITY_EDITOR |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment