using UnityEditor; namespace UnityEngine.ResourceManagement.Util { /// /// Creates a singleton. /// /// The singleton type. [ExecuteInEditMode] public abstract class ComponentSingleton : MonoBehaviour where T : ComponentSingleton { static T s_Instance; /// /// Indicates whether or not there is an existing instance of the singleton. /// public static bool Exists => s_Instance != null; /// /// Stores the instance of the singleton. /// public static T Instance { get { if (s_Instance == null) { s_Instance = FindInstance() ?? CreateNewSingleton(); } return s_Instance; } } static T FindInstance() { #if UNITY_EDITOR foreach (T cb in Resources.FindObjectsOfTypeAll(typeof(T))) { var go = cb.gameObject; if (!EditorUtility.IsPersistent(go.transform.root.gameObject) && !(go.hideFlags == HideFlags.NotEditable || go.hideFlags == HideFlags.HideAndDontSave)) return cb; } return null; #else return FindObjectOfType(); #endif } /// /// Retrieves the name of the object. /// /// Returns the name of the object. protected virtual string GetGameObjectName() => typeof(T).Name; static T CreateNewSingleton() { var go = new GameObject(); if (Application.isPlaying) { DontDestroyOnLoad(go); go.hideFlags = HideFlags.DontSave; } else { go.hideFlags = HideFlags.HideAndDontSave; } var instance = go.AddComponent(); go.name = instance.GetGameObjectName(); return instance; } private void Awake() { if (s_Instance != null && s_Instance != this) { DestroyImmediate(gameObject); return; } s_Instance = this as T; } /// /// Destroys the singleton. /// public static void DestroySingleton() { if (Exists) { DestroyImmediate(Instance.gameObject); s_Instance = null; } } #if UNITY_EDITOR void OnEnable() { EditorApplication.playModeStateChanged += PlayModeChanged; } void OnDisable() { EditorApplication.playModeStateChanged -= PlayModeChanged; } void PlayModeChanged(PlayModeStateChange state) { if (state == PlayModeStateChange.ExitingPlayMode) { if (Exists) { DestroyImmediate(Instance.gameObject); s_Instance = null; } } } #endif } }