AnimancerEvent.Invoker.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. // Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
  2. using System.Collections.Generic;
  3. using System.Runtime.CompilerServices;
  4. using UnityEngine;
  5. namespace Animancer
  6. {
  7. /// https://kybernetik.com.au/animancer/api/Animancer/AnimancerEvent
  8. partial struct AnimancerEvent
  9. {
  10. /************************************************************************************************************************/
  11. /// <summary>Events ready to be invoked by the next <see cref="Invoker.InvokeAllAndClear"/>.</summary>
  12. /// <remarks>
  13. /// This field should be inside the Invoker class.
  14. /// But that can potentially cause a TypeLoadException if Invoker initializes before AnimancerEvent.
  15. /// Having it out in AnimancerEvent avoids that possibility.
  16. /// </remarks>
  17. private static readonly List<Invocation>
  18. InvocationQueue = new();
  19. /************************************************************************************************************************/
  20. /// <summary>Gathers delegates in a static list to be invoked at a later time by any child class.</summary>
  21. /// https://kybernetik.com.au/animancer/api/Animancer/Invoker
  22. [DefaultExecutionOrder(-30000)]// Run as soon as possible in whatever update cycle is being executed.
  23. [ExecuteAlways]
  24. public abstract class Invoker : MonoBehaviour
  25. {
  26. /************************************************************************************************************************/
  27. /// <summary>Ensures that an appropriate <see cref="Invoker"/> has been created.</summary>
  28. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  29. public static Invoker Initialize(bool fixedUpdate)
  30. => fixedUpdate
  31. ? InvokerFixed.Initialize()
  32. : InvokerDynamic.Initialize();
  33. /// <summary>Ensures that an appropriate <see cref="Invoker"/> has been created.</summary>
  34. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  35. public static Invoker Initialize(AnimatorUpdateMode updateMode)
  36. {
  37. const AnimatorUpdateMode FixedUpdateMode =
  38. #if UNITY_2023_1_OR_NEWER
  39. AnimatorUpdateMode.Fixed;
  40. #else
  41. AnimatorUpdateMode.AnimatePhysics;
  42. #endif
  43. return Initialize(updateMode == FixedUpdateMode);
  44. }
  45. /************************************************************************************************************************/
  46. /// <summary>[Internal] Adds an event to the queue to be invoked by the next update.</summary>
  47. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  48. internal static void Add(Invocation invocation)
  49. {
  50. #if UNITY_ASSERTIONS
  51. if (!HasEnabledInstance)
  52. Debug.LogWarning(
  53. $"There is no currently enabled {nameof(AnimancerEvent)}.{nameof(Invoker)}" +
  54. $" so events will not be invoked.");
  55. #endif
  56. InvocationQueue.Add(invocation);
  57. }
  58. /************************************************************************************************************************/
  59. /// <summary>
  60. /// In case <see cref="InvokeAllAndClear"/> gets called recursively,
  61. /// we need to avoid invoking the same event multiple times
  62. /// without the performance cost of immediately removing them each from the queue.
  63. /// </summary>
  64. private static int _CurrentInvocation;
  65. /// <summary>Invokes all queued events and clears the queue.</summary>
  66. public static void InvokeAllAndClear()
  67. {
  68. while (_CurrentInvocation < InvocationQueue.Count)
  69. InvocationQueue[_CurrentInvocation++].Invoke();
  70. InvocationQueue.Clear();
  71. _CurrentInvocation = 0;
  72. }
  73. /************************************************************************************************************************/
  74. /// <summary>Returns an enumerator for all invocations currently in the queue.</summary>
  75. public static List<Invocation>.Enumerator EnumerateInvocationQueue()
  76. => InvocationQueue.GetEnumerator();
  77. /************************************************************************************************************************/
  78. #if UNITY_ASSERTIONS
  79. /************************************************************************************************************************/
  80. private static readonly List<Invoker>
  81. Instances = new();
  82. /************************************************************************************************************************/
  83. /// <summary>[Assert-Only] Registers this instance.</summary>
  84. protected virtual void Awake()
  85. => Instances.Add(this);
  86. /************************************************************************************************************************/
  87. /// <summary>[Assert-Only] Un-registers this instance.</summary>
  88. protected virtual void OnDestroy()
  89. => Instances.Remove(this);
  90. /************************************************************************************************************************/
  91. /// <summary>[Assert-Only] Is there any <see cref="Behaviour.enabled"/> instance?</summary>
  92. private static bool HasEnabledInstance
  93. {
  94. get
  95. {
  96. for (int i = 0; i < Instances.Count; i++)
  97. if (Instances[i].enabled)
  98. return true;
  99. return false;
  100. }
  101. }
  102. /************************************************************************************************************************/
  103. #endif
  104. /************************************************************************************************************************/
  105. }
  106. }
  107. }