Files
Fishing2/Packages/com.waveharmonic.crest/Runtime/Scripts/Utility/Shared/Component/ManagedBehaviour.cs
2026-01-01 22:00:33 +08:00

178 lines
5.8 KiB
C#

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