// Crest Water System // Copyright © 2024 Wave Harmonic. All rights reserved. using System; using System.Collections.Generic; namespace WaveHarmonic.Crest.Internal { /// /// Manages ManagedBehaviours. Replaces Unity's event system. /// /// The manager type. public abstract class ManagerBehaviour : CustomBehaviour where T : ManagerBehaviour { internal static readonly List> s_OnUpdate = new(); internal static readonly List> s_OnLateUpdate = new(); internal static readonly List> s_OnFixedUpdate = new(); internal static readonly List> s_OnEnable = new(); internal static readonly List> s_OnDisable = new(); /// /// The singleton instance. /// public static T Instance { get; private set; } void Broadcast(List> listeners, T instance) { for (var i = listeners.Count - 1; i >= 0; --i) { listeners[i].Invoke(instance); } } void Broadcast(List> listeners) { Broadcast(listeners, Instance); } private protected virtual void Enable() { // Setting up instance should be last. Instance = (T)this; Broadcast(s_OnEnable); } private protected virtual void Disable() { Broadcast(s_OnDisable); Instance = null; } private protected virtual void FixedUpdate() => Broadcast(s_OnFixedUpdate); private protected void BroadcastUpdate() => Broadcast(s_OnUpdate); private protected virtual void LateUpdate() => Broadcast(s_OnLateUpdate); // OnLoad etc cannot be used on open generic types. internal static void AfterRuntimeLoad() { Instance = null; } internal static void AfterScriptReload() { Instance = FindFirstObjectByType(); } } /// /// A behaviour which is driven by a ManagerBehaviour instead of Unity's event system. /// /// The manager type. public abstract class ManagedBehaviour : CustomBehaviour where T : ManagerBehaviour { readonly Action _OnUpdate; readonly Action _OnLateUpdate; readonly Action _OnFixedUpdate; readonly Action _OnEnable; readonly Action _OnDisable; /// /// The Update method called by the manager class. /// private protected virtual Action OnUpdateMethod => null; /// /// The LateUpdate method called by the manager class. /// private protected virtual Action OnLateUpdateMethod => null; /// /// The FixedUpdated method called by the manager class. /// private protected virtual Action OnFixedUpdateMethod => null; /// /// The OnEnable method called by the manager class. /// private protected virtual Action OnEnableMethod => null; /// /// The OnDisable method called by the manager class. /// private protected virtual Action OnDisableMethod => null; /// /// Constructor which caches Actions to avoid allocations. /// public ManagedBehaviour() { if (OnUpdateMethod != null) _OnUpdate = new(OnUpdateMethod); if (OnLateUpdateMethod != null) _OnLateUpdate = new(OnLateUpdateMethod); if (OnFixedUpdateMethod != null) _OnFixedUpdate = new(OnFixedUpdateMethod); if (OnEnableMethod != null) _OnEnable = new(OnEnableMethod); if (OnDisableMethod != null) _OnDisable = new(OnDisableMethod); } /// private protected override void OnEnable() { base.OnEnable(); UpdateSubscription(listen: true); // Trigger OnEnable as it has already passed. if (_OnEnable != null && ManagerBehaviour.Instance != null) { _OnEnable(ManagerBehaviour.Instance); } } /// /// Unity's OnDisable method. Make sure to call base if overriden. /// private protected virtual void OnDisable() { UpdateSubscription(listen: false); if (_OnDisable != null && ManagerBehaviour.Instance != null) { _OnDisable(ManagerBehaviour.Instance); } } void UpdateSubscription(bool listen) { if (_OnUpdate != null) { ManagerBehaviour.s_OnUpdate.Remove(_OnUpdate); if (listen) ManagerBehaviour.s_OnUpdate.Add(_OnUpdate); } if (_OnLateUpdate != null) { ManagerBehaviour.s_OnLateUpdate.Remove(_OnLateUpdate); if (listen) ManagerBehaviour.s_OnLateUpdate.Add(_OnLateUpdate); } if (_OnFixedUpdate != null) { ManagerBehaviour.s_OnFixedUpdate.Remove(_OnFixedUpdate); if (listen) ManagerBehaviour.s_OnFixedUpdate.Add(_OnFixedUpdate); } if (_OnEnable != null) { ManagerBehaviour.s_OnEnable.Remove(_OnEnable); if (listen) ManagerBehaviour.s_OnEnable.Add(_OnEnable); } if (_OnDisable != null) { ManagerBehaviour.s_OnDisable.Remove(_OnDisable); if (listen) ManagerBehaviour.s_OnDisable.Add(_OnDisable); } } } }