#if (UNITY_EDITOR || DEVELOPMENT_BUILD) && !UPDATE_MANAGER_DISABLE_PROFILER_MARKERS
#define ENABLE_PROFILER_MARKERS
#endif
using System;
using LanLib.UpdateManager.Internal;
using LanLib.UpdateManager.Jobs;
using UnityEngine;
namespace LanLib.UpdateManager
{
///
/// Singleton MonoBehaviour that calls , or to registered objects every frame.
///
///
/// Any C# object can be registered for updates, including MonoBehaviours, pure C# classes and structs, as long as they implement , or .
/// Managed methods are called inside a try/catch block, so that exceptions don't stop other objects from updating.
///
/// This class doesn't implement any execution order mechanism, so don't rely on managed methods being executed in any order.
/// In fact, the order of executed methods will most likely change during the lifetime of the UpdateManager.
///
[ExecuteAlways]
public class UpdateManager : MonoBehaviour
{
/// Get or create the singleton instance
public static UpdateManager Instance => (ApplicationUtils.IsQuitting || _instance != null)
? _instance
: (_instance = CreateInstance());
protected static UpdateManager _instance;
private static UpdateManager CreateInstance()
{
var gameObject = new GameObject(nameof(UpdateManager))
{
hideFlags = HideFlags.DontSave,
};
#if UNITY_EDITOR
if (!Application.isPlaying)
{
gameObject.hideFlags = HideFlags.HideAndDontSave;
}
else
#endif
{
DontDestroyOnLoad(gameObject);
}
return gameObject.AddComponent();
}
#if UNITY_EDITOR
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void DestroyEditorUpdateManager()
{
if (_instance)
{
DestroyImmediate(_instance.gameObject);
}
}
#endif
///
/// Returns whether there are any objects registered for managed updates.
///
public bool HasRegisteredObjects => _updatableObjects.Count > 0
|| _lateUpdatableObjects.Count > 0
|| _fixedUpdatableObjects.Count > 0;
private readonly FastRemoveList _updatableObjects = new FastRemoveList();
private readonly FastRemoveList _lateUpdatableObjects = new FastRemoveList();
private readonly FastRemoveList _fixedUpdatableObjects = new FastRemoveList();
protected void Update()
{
UpdateJobTime.InstanceRef.Refresh();
foreach (IUpdatable updatable in _updatableObjects)
{
try
{
#if ENABLE_PROFILER_MARKERS
using (ProfilerMarkerMap.Get("ManagedUpdate", updatable))
#endif
updatable.ManagedUpdate();
}
catch (Exception ex)
{
Debug.LogException(ex);
}
}
}
protected void LateUpdate()
{
foreach (ILateUpdatable lateUpdatable in _lateUpdatableObjects)
{
try
{
#if ENABLE_PROFILER_MARKERS
using (ProfilerMarkerMap.Get("ManagedLateUpdate", lateUpdatable))
#endif
lateUpdatable.ManagedLateUpdate();
}
catch (Exception ex)
{
Debug.LogException(ex);
}
}
}
protected void FixedUpdate()
{
foreach (IFixedUpdatable fixedUpdatable in _fixedUpdatableObjects)
{
try
{
#if ENABLE_PROFILER_MARKERS
using (ProfilerMarkerMap.Get("ManagedFixedUpdate", fixedUpdatable))
#endif
fixedUpdatable.ManagedFixedUpdate();
}
catch (Exception ex)
{
Debug.LogException(ex);
}
}
}
///
/// Register to be updated every frame.
///
///
/// Registering updatable objects is O(1).
/// Registering an object more than once is a no-op.
///
public void Register(IManagedObject obj)
{
if (obj is IUpdatable updatable)
{
_updatableObjects.Add(updatable);
}
if (obj is ILateUpdatable lateUpdatable)
{
_lateUpdatableObjects.Add(lateUpdatable);
}
if (obj is IFixedUpdatable fixedUpdatable)
{
_fixedUpdatableObjects.Add(fixedUpdatable);
}
enabled = HasRegisteredObjects;
}
///
/// Unregister , so it is not updated every frame anymore.
///
///
/// Unregistering updatable objects is O(1).
/// Unregistering an object that wasn't registered is a no-op.
///
public void Unregister(IManagedObject obj)
{
if (obj is IUpdatable updatable)
{
_updatableObjects.Remove(updatable);
}
if (obj is ILateUpdatable lateUpdatable)
{
_lateUpdatableObjects.Remove(lateUpdatable);
}
if (obj is IFixedUpdatable fixedUpdatable)
{
_fixedUpdatableObjects.Remove(fixedUpdatable);
}
enabled = HasRegisteredObjects;
}
///
/// Unregisters all updatable objects at once.
///
public void Clear()
{
_updatableObjects.Clear();
_lateUpdatableObjects.Clear();
_fixedUpdatableObjects.Clear();
enabled = false;
}
}
}