ControllerState.ParameterID.cs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. // Animancer // https://kybernetik.com.au/animancer // Copyright 2022 Kybernetik //
  2. using System;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. #if UNITY_EDITOR
  6. using UnityEditor.Animations;
  7. #endif
  8. namespace Animancer
  9. {
  10. /// https://kybernetik.com.au/animancer/api/Animancer/ControllerState
  11. partial class ControllerState
  12. {
  13. /************************************************************************************************************************/
  14. /// <summary>A wrapper for the name and hash of an <see cref="AnimatorControllerParameter"/>.</summary>
  15. public readonly struct ParameterID
  16. {
  17. /************************************************************************************************************************/
  18. /// <summary>The name of this parameter.</summary>
  19. public readonly string Name;
  20. /// <summary>The name hash of this parameter.</summary>
  21. public readonly int Hash;
  22. /************************************************************************************************************************/
  23. /// <summary>
  24. /// Creates a new <see cref="ParameterID"/> with the specified <see cref="Name"/> and uses
  25. /// <see cref="Animator.StringToHash"/> to calculate the <see cref="Hash"/>.
  26. /// </summary>
  27. public ParameterID(string name)
  28. {
  29. Name = name;
  30. Hash = Animator.StringToHash(name);
  31. }
  32. /// <summary>
  33. /// Creates a new <see cref="ParameterID"/> with the specified <see cref="Hash"/> and leaves the
  34. /// <see cref="Name"/> null.
  35. /// </summary>
  36. public ParameterID(int hash)
  37. {
  38. Name = null;
  39. Hash = hash;
  40. }
  41. /// <summary>Creates a new <see cref="ParameterID"/> with the specified <see cref="Name"/> and <see cref="Hash"/>.</summary>
  42. /// <remarks>This constructor does not verify that the `hash` actually corresponds to the `name`.</remarks>
  43. public ParameterID(string name, int hash)
  44. {
  45. Name = name;
  46. Hash = hash;
  47. }
  48. /************************************************************************************************************************/
  49. /// <summary>
  50. /// Creates a new <see cref="ParameterID"/> with the specified <see cref="Name"/> and uses
  51. /// <see cref="Animator.StringToHash"/> to calculate the <see cref="Hash"/>.
  52. /// </summary>
  53. public static implicit operator ParameterID(string name) => new ParameterID(name);
  54. /// <summary>
  55. /// Creates a new <see cref="ParameterID"/> with the specified <see cref="Hash"/> and leaves the
  56. /// <see cref="Name"/> null.
  57. /// </summary>
  58. public static implicit operator ParameterID(int hash) => new ParameterID(hash);
  59. /************************************************************************************************************************/
  60. /// <summary>Returns the <see cref="Hash"/>.</summary>
  61. public static implicit operator int(ParameterID parameter) => parameter.Hash;
  62. /************************************************************************************************************************/
  63. /// <summary>[Editor-Conditional]
  64. /// Throws if the `controller` doesn't have a parameter with the specified <see cref="Hash"/>
  65. /// and `type`.
  66. /// </summary>
  67. /// <exception cref="ArgumentException"/>
  68. [System.Diagnostics.Conditional(Strings.UnityEditor)]
  69. public void ValidateHasParameter(RuntimeAnimatorController controller, AnimatorControllerParameterType type)
  70. {
  71. #if UNITY_EDITOR
  72. var parameterDetails = GetParameterDetails(controller);
  73. if (parameterDetails == null)
  74. return;
  75. // Check that there is a parameter with the correct hash and type.
  76. if (!parameterDetails.TryGetValue(Hash, out var parameterType))
  77. {
  78. throw new ArgumentException($"{controller} has no {type} parameter matching {this}");
  79. }
  80. if (type != parameterType)
  81. {
  82. throw new ArgumentException($"{controller} has a parameter matching {this}, but it is not a {type}");
  83. }
  84. #endif
  85. }
  86. /************************************************************************************************************************/
  87. #if UNITY_EDITOR
  88. private static Dictionary<RuntimeAnimatorController, Dictionary<int, AnimatorControllerParameterType>>
  89. _ControllerToParameterHashAndType;
  90. /// <summary>[Editor-Only] Returns the hash mapped to the type of all parameters in the `controller`.</summary>
  91. /// <remarks>This doesn't work for if the `controller` was loaded from an Asset Bundle.</remarks>
  92. private static Dictionary<int, AnimatorControllerParameterType> GetParameterDetails(RuntimeAnimatorController controller)
  93. {
  94. Editor.AnimancerEditorUtilities.InitializeCleanDictionary(ref _ControllerToParameterHashAndType);
  95. if (_ControllerToParameterHashAndType.TryGetValue(controller, out var parameterDetails))
  96. return parameterDetails;
  97. if (controller is AnimatorController editorController)
  98. {
  99. var parameters = editorController.parameters;
  100. var count = parameters.Length;
  101. if (count != 0 || editorController.layers.Length != 0)
  102. {
  103. parameterDetails = new Dictionary<int, AnimatorControllerParameterType>();
  104. for (int i = 0; i < count; i++)
  105. {
  106. var parameter = parameters[i];
  107. parameterDetails.Add(parameter.nameHash, parameter.type);
  108. }
  109. _ControllerToParameterHashAndType.Add(controller, parameterDetails);
  110. return parameterDetails;
  111. }
  112. }
  113. _ControllerToParameterHashAndType.Add(controller, null);
  114. return null;
  115. }
  116. #endif
  117. /************************************************************************************************************************/
  118. /// <summary>Returns a string containing the <see cref="Name"/> and <see cref="Hash"/>.</summary>
  119. public override string ToString()
  120. {
  121. return $"{nameof(ControllerState)}.{nameof(ParameterID)}" +
  122. $"({nameof(Name)}: '{Name}'" +
  123. $", {nameof(Hash)}: {Hash})";
  124. }
  125. /************************************************************************************************************************/
  126. }
  127. /************************************************************************************************************************/
  128. }
  129. }