using System; using UnityEngine; using UnityEngine.SceneManagement; namespace SUISS.Core { public class SingletonMonobehaviour : MonoBehaviour where T : SingletonMonobehaviour { protected virtual void Awake() { SingletonMonobehaviour.applicationIsQuitting = false; SingletonMonobehaviour.quitWarningShown = false; if (SingletonMonobehaviour._instance == this) { UnityEngine.Debug.Log(string.Format("[Singleton] I'm {0}, already the instance. Not executing Awake again.", base.name)); return; } if (SingletonMonobehaviour._instance != null) { if (!this._overrideOldInstance) { this._isValidNewInstance = false; this.DestroyInstanceObject((T)((object)this)); UnityEngine.Debug.LogWarning(string.Format("[Singleton] There already exists a {0} singleton. Instance will be kept with old, be carefull that enherited classes might reset other values in Awake or it's constructor. Instance on object {1} is removed.", typeof(T), base.gameObject.name)); return; } SingletonMonobehaviour._instance._isValidNewInstance = false; bool flag = this.DestroyInstanceObject(SingletonMonobehaviour._instance); UnityEngine.Debug.LogWarning(string.Format("[Singleton] There already exists a {0} singleton. New instance is used because it has been flagged as ForceUse. {1}", typeof(T), (!flag) ? string.Empty : " Old gameobject has been destroyed.")); } SingletonMonobehaviour._instance = (T)((object)this); if (PersistentManager.HasAttribute(typeof(T))) { if (base.transform.parent != null) { UnityEngine.Debug.LogWarning("Please don't parent any singletons with marked as DontDestroyOnLoad, as we can't promise the DontDestroyOnLoad functionality then."); } UnityEngine.Object.DontDestroyOnLoad(this); } } public static T InstanceIfAvailable { get { return (!SingletonMonobehaviour.IsAvailable) ? ((T)((object)null)) : SingletonMonobehaviour.Instance; } } public static T Instance { get { if (!object.ReferenceEquals(SingletonMonobehaviour._instance, null)) { return SingletonMonobehaviour._instance; } if (SingletonMonobehaviour.applicationIsQuitting) { if (!SingletonMonobehaviour.quitWarningShown) { UnityEngine.Debug.LogWarning(string.Format("[Singleton] Instance '{0}' already destroyed on application quit. Won't create again - returning null.", typeof(T))); SingletonMonobehaviour.quitWarningShown = true; } return (T)((object)null); } object @lock = SingletonMonobehaviour._lock; T instance; lock (@lock) { if (SingletonMonobehaviour._instance == null) { SingletonMonobehaviour._instance = (T)((object)UnityEngine.Object.FindObjectOfType(typeof(T))); if (UnityEngine.Object.FindObjectsOfType(typeof(T)).Length > 1) { UnityEngine.Debug.LogError("[Singleton] Something went really wrong - there should never be more than 1 singleton! Reopenning the scene might fix it."); return SingletonMonobehaviour._instance; } if (PersistentManager.HasAttribute(typeof(T))) { if (PersistentManager.SceneWasLoaded) { UnityEngine.Debug.LogWarning("[Singleton] PersistentManagers scene was already loaded."); } else { bool flag = true; if (SceneManager.GetSceneByName("PersistentManagers").IsValid()) { SceneManager.LoadScene("PersistentManagers", LoadSceneMode.Additive); } else { UnityEngine.Debug.LogWarning(typeof(T).ToString() + "'s attribute [PersistentManager] wants a PersistentManagers scene, but its not in the build settings! Will create a DontDestroyOnLoad object now. Please remove the attribute or implement it correctly (PersistentManager scene)"); flag = false; } PersistentManager.SceneWasLoaded = true; SingletonMonobehaviour._instance = (T)((object)UnityEngine.Object.FindObjectOfType(typeof(T))); if (SingletonMonobehaviour._instance == null && flag) { UnityEngine.Debug.LogWarning(string.Format("[Singleton] Loading of PersistentManagers scene did not create instance of {0}.", typeof(T))); } } } if (SingletonMonobehaviour._instance == null) { GameObject gameObject = new GameObject(); SingletonMonobehaviour._instance = gameObject.AddComponent(); gameObject.name = string.Format("(singleton) {0}", typeof(T).ToString()); if (PersistentManager.HasAttribute(typeof(T))) { UnityEngine.Object.DontDestroyOnLoad(gameObject); } if (!PersistentManager.IsLoadAtRuntime(typeof(T))) { UnityEngine.Debug.LogError(string.Format("[Singleton] An instance of {0} is needed in the scene, so '{1}' was created{2}.", typeof(T), gameObject, (!PersistentManager.HasAttribute(typeof(T))) ? string.Empty : " with DontDestroyOnLoad")); } } else { UnityEngine.Debug.Log(string.Format("[Singleton] Using instance already created: {0}", SingletonMonobehaviour._instance.gameObject.name)); } } instance = SingletonMonobehaviour._instance; } return instance; } } [Obsolete("Instead of using this, call Instance on the type you want.")] public static S InstanceAs() where S : T { T instance = SingletonMonobehaviour.Instance; if (instance is S) { return instance as S; } UnityEngine.Debug.LogError(string.Format("[Singleton] Instance of type {0} is not assignable to type {1}", (!(instance == null)) ? instance.GetType().Name : "null", typeof(S))); return (S)((object)null); } public static bool IsAvailable { get { return SingletonMonobehaviour._instance != null; } } protected virtual void OnApplicationQuit() { SingletonMonobehaviour.applicationIsQuitting = true; SingletonMonobehaviour.quitWarningShown = false; } protected virtual void OnDestroy() { if (!this._isValidNewInstance) { return; } if (SingletonMonobehaviour._instance == null) { UnityEngine.Debug.LogWarning(string.Format("[Singleton] instance of {0} singleton already is null in OnDestroy", typeof(T))); } SingletonMonobehaviour._instance = (T)((object)null); } private bool DestroyInstanceObject(T instance) { GameObject gameObject = instance.gameObject; UnityEngine.Object.Destroy(instance); bool result = false; if (gameObject.transform.childCount == 0 && gameObject.GetComponents().Length <= 2) { UnityEngine.Object.Destroy(gameObject); result = true; } return result; } private static T _instance = (T)((object)null); private static object _lock = new object(); private static bool quitWarningShown = false; [SerializeField] [Tooltip("Use this instance for the entire game cycle, even when someone with the same flag wants to become the instance")] protected bool _overrideOldInstance; protected bool _isValidNewInstance = true; private static bool applicationIsQuitting = false; } }