diff --git a/IPA.Loader/Utilities/ModSingleton.cs b/IPA.Loader/Utilities/ModSingleton.cs new file mode 100644 index 00000000..acc43ebe --- /dev/null +++ b/IPA.Loader/Utilities/ModSingleton.cs @@ -0,0 +1,91 @@ +using UnityEngine; + +namespace IPA.Utilities +{ + /// + /// Generate a persistent singleton which can be destroyed. + /// + /// + public class ModSingleton : MonoBehaviour where T : MonoBehaviour + { + /// + /// The stored reference for the instance + /// + protected static T _instance; + /// + /// The lock for the instance to prevent more than one being created. + /// + protected static object _lock = new object(); + + /// + /// Checks to see if the singleton if the singleton can be accessed + /// + public static bool IsSingletonAvailable => _instance != null; + + /// + /// Noncapitalized version which points to the actual property. + /// + public static T instance => Instance; + + /// + /// Creates and or returns the singleton + /// + public static T Instance + { + get + { + T result; + object @lock = _lock; + lock (@lock) + { + if (_instance == null) + { + _instance = (T)((object)FindObjectOfType(typeof(T))); + if (FindObjectsOfType(typeof(T)).Length > 1) + { + IPA.Logging.Logger.log.Warn($"[Singleton] Something went really wrong - there should never be more than one singleton of {nameof(T)}"); + return _instance; + } + if (_instance == null) + { + GameObject gameObject = new GameObject(); + _instance = gameObject.AddComponent(); + gameObject.name = $"{nameof(T)} Singleton"; + DontDestroyOnLoad(gameObject); + } + } + result = _instance; + } + return result; + } + } + + /// + /// Called when the singleton is enabled to prevent the singleton from being destroyed naturally + /// + private void OnEnabled() + { + DontDestroyOnLoad(this); + } + + /// + /// Destroys the singleton. + /// + public static void Destroy() + { + if (_instance != null) + { + _lock = new object(); + Destroy(_instance); + } + } + + /// + /// Touches the instance to easily create it without having to assign it. + /// + public static void TouchInstance() + { + _ = Instance == null; + } + } +}