using UnityEngine; namespace JoeSiu.Common.Infrastructure.Runtime { public abstract class MonoSingleton : MonoBehaviour where T : MonoSingleton { private static T _instance; public static T Instance { get { if (_instance) return _instance; var objs = FindObjectsByType(FindObjectsSortMode.None); if (objs.Length > 0) { AssignInstance(objs[0]); } if (objs.Length > 1) { for (var index = 1; index < objs.Length; index++) { var obj = objs[index]; DestroyDuplicate(obj); } } if (!_instance) { Debug.LogWarning( $"[MonoSingleton] No instance of type '{typeof(T).Name}' is found, make sure to add it in the scene!"); } return _instance; } } public static T GetInstance() => _instance; public static void CreateInstance(bool dontDestroyOnLoad = true) { var go = new GameObject(typeof(T).Name); var instance = go.AddComponent(); if (dontDestroyOnLoad) DontDestroyOnLoad(go); Debug.Log( $"[MonoSingleton] Created game object '{go.name}' {(dontDestroyOnLoad ? "(DontDestroyOnLoad)" : "")} for type '{typeof(T).Name}'", go); AssignInstance(instance); } [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] public static void RemoveInstance() { _instance = null; Debug.Log($"[MonoSingleton] Removed instance of type '{typeof(T).Name}'"); } protected virtual void Awake() { if (!_instance) AssignInstance(this as T); else if (_instance != this) DestroyDuplicate(this as T); } private static void AssignInstance(T instance) { if (!instance) return; _instance = instance; Debug.Log($"[MonoSingleton] Assigned instance of type '{typeof(T).Name}' to object '{instance.gameObject.name}'", instance.gameObject); } private static void DestroyDuplicate(T instance) { if (!_instance) return; if (!instance) return; Debug.LogError( $"[MonoSingleton] Instance of type '{typeof(T).Name}' is already assigned to object '{_instance.gameObject.name}', destroying duplicate instance '{instance.gameObject.name}'...", instance.gameObject); if (Application.isPlaying) Destroy(instance); else DestroyImmediate(instance); } } }