You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

118 lines
3.5 KiB
C#

using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.SceneManagement;
namespace LanLib.Singleton
{
[ExecuteInEditMode]
public class Singleton<T> : SingletonBase where T : Singleton<T>
{
private const BindingFlags BindingFlags = System.Reflection.BindingFlags.Default
| System.Reflection.BindingFlags.FlattenHierarchy
| System.Reflection.BindingFlags.Static
| System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.NonPublic;
private static T _instance;
public static T Instance
{
get
{
if (!_instance)
{
#if UNITY_EDITOR
_instance = Resources.FindObjectsOfTypeAll<T>().FirstOrDefault(inst => inst);
#else
_instance = FindObjectOfType<T>();
#endif
}
if (!_instance)
{
_instance = (T)typeof(T).GetMethod("CreateInstance", BindingFlags)?.Invoke(null, null);
}
Assert.IsNotNull(_instance);
return _instance;
}
}
protected static T CreateInstance()
{
return new GameObject(typeof(T).Name)
{
hideFlags = HideFlags.HideAndDontSave ^ HideFlags.NotEditable
}.AddComponent<T>();
}
protected virtual void Awake()
{
if (_instance == null)
{
_instance = this as T;
if (Application.isPlaying)
{
DestroyOnSceneUnload = DestroyOnSceneUnload;
}
}
else
{
DestroySelf();
}
}
}
public abstract class SingletonBase : MonoBehaviour
{
private SingletonDestroyCondition _destroyCondition = SingletonDestroyCondition.ReloadDomain;
public virtual SingletonDestroyCondition DestroyCondition
{
get => _destroyCondition;
private set
{
var flgSceneUnload = (value ^ _destroyCondition) & SingletonDestroyCondition.SceneUnload;
if (flgSceneUnload != 0)
{
var hasFlag = 0 != (value & SingletonDestroyCondition.SceneUnload);
DestroyOnSceneUnload = hasFlag;
}
_destroyCondition = value;
}
}
public bool DestroyOnSceneUnload
{
get => DestroyCondition.Contains(SingletonDestroyCondition.SceneUnload);
set
{
if (value)
{
SceneManager.MoveGameObjectToScene(gameObject, SceneManager.GetActiveScene());
DestroyCondition |= SingletonDestroyCondition.SceneUnload;
}
else
{
DontDestroyOnLoad(gameObject);
DestroyCondition &= ~SingletonDestroyCondition.SceneUnload;
}
}
}
internal void DestroySelf()
{
if (Application.isPlaying)
{
Destroy(gameObject);
}
else
{
DestroyImmediate(gameObject);
}
}
}
}