123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- // Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
- using System.Collections.Generic;
- using System.Runtime.CompilerServices;
- using UnityEngine;
- namespace Animancer
- {
- /// https://kybernetik.com.au/animancer/api/Animancer/AnimancerEvent
- partial struct AnimancerEvent
- {
- /************************************************************************************************************************/
- /// <summary>Events ready to be invoked by the next <see cref="Invoker.InvokeAllAndClear"/>.</summary>
- /// <remarks>
- /// This field should be inside the Invoker class.
- /// But that can potentially cause a TypeLoadException if Invoker initializes before AnimancerEvent.
- /// Having it out in AnimancerEvent avoids that possibility.
- /// </remarks>
- private static readonly List<Invocation>
- InvocationQueue = new();
- /************************************************************************************************************************/
- /// <summary>Gathers delegates in a static list to be invoked at a later time by any child class.</summary>
- /// https://kybernetik.com.au/animancer/api/Animancer/Invoker
- [DefaultExecutionOrder(-30000)]// Run as soon as possible in whatever update cycle is being executed.
- [ExecuteAlways]
- public abstract class Invoker : MonoBehaviour
- {
- /************************************************************************************************************************/
- /// <summary>Ensures that an appropriate <see cref="Invoker"/> has been created.</summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Invoker Initialize(bool fixedUpdate)
- => fixedUpdate
- ? InvokerFixed.Initialize()
- : InvokerDynamic.Initialize();
- /// <summary>Ensures that an appropriate <see cref="Invoker"/> has been created.</summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Invoker Initialize(AnimatorUpdateMode updateMode)
- {
- const AnimatorUpdateMode FixedUpdateMode =
- #if UNITY_2023_1_OR_NEWER
- AnimatorUpdateMode.Fixed;
- #else
- AnimatorUpdateMode.AnimatePhysics;
- #endif
- return Initialize(updateMode == FixedUpdateMode);
- }
- /************************************************************************************************************************/
- /// <summary>[Internal] Adds an event to the queue to be invoked by the next update.</summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static void Add(Invocation invocation)
- {
- #if UNITY_ASSERTIONS
- if (!HasEnabledInstance)
- Debug.LogWarning(
- $"There is no currently enabled {nameof(AnimancerEvent)}.{nameof(Invoker)}" +
- $" so events will not be invoked.");
- #endif
- InvocationQueue.Add(invocation);
- }
- /************************************************************************************************************************/
- /// <summary>
- /// In case <see cref="InvokeAllAndClear"/> gets called recursively,
- /// we need to avoid invoking the same event multiple times
- /// without the performance cost of immediately removing them each from the queue.
- /// </summary>
- private static int _CurrentInvocation;
- /// <summary>Invokes all queued events and clears the queue.</summary>
- public static void InvokeAllAndClear()
- {
- while (_CurrentInvocation < InvocationQueue.Count)
- InvocationQueue[_CurrentInvocation++].Invoke();
- InvocationQueue.Clear();
- _CurrentInvocation = 0;
- }
- /************************************************************************************************************************/
- /// <summary>Returns an enumerator for all invocations currently in the queue.</summary>
- public static List<Invocation>.Enumerator EnumerateInvocationQueue()
- => InvocationQueue.GetEnumerator();
- /************************************************************************************************************************/
- #if UNITY_ASSERTIONS
- /************************************************************************************************************************/
- private static readonly List<Invoker>
- Instances = new();
- /************************************************************************************************************************/
- /// <summary>[Assert-Only] Registers this instance.</summary>
- protected virtual void Awake()
- => Instances.Add(this);
- /************************************************************************************************************************/
- /// <summary>[Assert-Only] Un-registers this instance.</summary>
- protected virtual void OnDestroy()
- => Instances.Remove(this);
- /************************************************************************************************************************/
- /// <summary>[Assert-Only] Is there any <see cref="Behaviour.enabled"/> instance?</summary>
- private static bool HasEnabledInstance
- {
- get
- {
- for (int i = 0; i < Instances.Count; i++)
- if (Instances[i].enabled)
- return true;
- return false;
- }
- }
- /************************************************************************************************************************/
- #endif
- /************************************************************************************************************************/
- }
- }
- }
|