diff --git a/UnityProject/Assets/GameScripts/HotFix/GameBase/Singleton.cs b/UnityProject/Assets/GameScripts/HotFix/GameBase/Singleton.cs index 2f14742f..18be3b73 100644 --- a/UnityProject/Assets/GameScripts/HotFix/GameBase/Singleton.cs +++ b/UnityProject/Assets/GameScripts/HotFix/GameBase/Singleton.cs @@ -1,14 +1,14 @@ -using TEngine; +using System.Diagnostics; namespace GameBase { /// - /// 通用单例。 + /// 全局对象必须继承于此。 /// - /// 泛型T。 - public class Singleton where T : new() + /// 子类类型。 + public abstract class Singleton : ISingleton where T : Singleton, new() { - private static T _instance; + protected static T _instance = default(T); public static T Instance { @@ -17,11 +17,43 @@ namespace GameBase if (null == _instance) { _instance = new T(); - Log.Assert(_instance != null); + _instance.Init(); + SingletonSystem.Retain(_instance); } return _instance; } } + + public static bool IsValid => _instance != null; + + protected Singleton() + { +#if UNITY_EDITOR + string st = new StackTrace().ToString(); + // using const string to compare simply + if (!st.Contains("GameBase.Singleton`1[T].get_Instance")) + { + UnityEngine.Debug.LogError($"请必须通过Instance方法来实例化{typeof(T).FullName}类"); + } +#endif + } + + protected virtual void Init() + { + } + + public virtual void Active() + { + } + + public virtual void Release() + { + if (_instance != null) + { + SingletonSystem.Release(_instance); + _instance = null; + } + } } } \ No newline at end of file diff --git a/UnityProject/Assets/GameScripts/HotFix/GameBase/SingletonBehaviour.cs b/UnityProject/Assets/GameScripts/HotFix/GameBase/SingletonBehaviour.cs new file mode 100644 index 00000000..91010dbc --- /dev/null +++ b/UnityProject/Assets/GameScripts/HotFix/GameBase/SingletonBehaviour.cs @@ -0,0 +1,108 @@ +using TEngine; +using UnityEngine; + +namespace GameBase +{ + /// + /// 全局MonoBehavior必须继承于此 + /// + /// 子类类型 + public class SingletonBehaviour : MonoBehaviour where T : SingletonBehaviour + { + private static T _instance; + + private void Awake() + { + if (CheckInstance()) + { + OnLoad(); + } + } + + private bool CheckInstance() + { + if (this == Instance) + { + return true; + } + Object.Destroy(gameObject); + return false; + } + + protected virtual void OnLoad() + { + + } + + protected virtual void OnDestroy() + { + Release(); + } + + /// + /// 判断对象是否有效 + /// + public static bool IsValid + { + get + { + return _instance != null; + } + } + + public static T Active() + { + return Instance; + } + + public static void Release() + { + if (_instance != null) + { + SingletonSystem.Release(_instance.gameObject); + _instance = null; + } + } + + /// + /// 实例 + /// + public static T Instance + { + get + { + if (_instance == null) + { + System.Type thisType = typeof(T); + string instName = thisType.Name; + GameObject go = SingletonSystem.GetGameObject(instName); + if (go == null) + { + go = GameObject.Find($"/{instName}"); + if (go == null) + { + go = new GameObject(instName); + go.transform.position = Vector3.zero; + } + SingletonSystem.Retain(go); + } + + if (go != null) + { + _instance = go.GetComponent(); + if (_instance == null) + { + _instance = go.AddComponent(); + } + } + + if(_instance == null) + { + Log.Error($"Can't create SingletonBehaviour<{typeof(T)}>"); + } + } + return _instance; + } + } + } +} \ No newline at end of file diff --git a/UnityProject/Assets/GameScripts/HotFix/GameBase/SingletonBehaviour.cs.meta b/UnityProject/Assets/GameScripts/HotFix/GameBase/SingletonBehaviour.cs.meta new file mode 100644 index 00000000..5534933a --- /dev/null +++ b/UnityProject/Assets/GameScripts/HotFix/GameBase/SingletonBehaviour.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bc365e281d234e61891bf9f922a0897a +timeCreated: 1715574965 \ No newline at end of file diff --git a/UnityProject/Assets/GameScripts/HotFix/GameBase/SingletonSystem.cs b/UnityProject/Assets/GameScripts/HotFix/GameBase/SingletonSystem.cs new file mode 100644 index 00000000..99bde03c --- /dev/null +++ b/UnityProject/Assets/GameScripts/HotFix/GameBase/SingletonSystem.cs @@ -0,0 +1,141 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace GameBase +{ + public interface ISingleton + { + /// + /// 激活接口,通常用于在某个时机手动实例化 + /// + void Active(); + + /// + /// 释放接口 + /// + void Release(); + } + + /// + /// 框架中的全局对象与Unity场景依赖相关的DontDestroyOnLoad需要统一管理,方便重启游戏时清除工作 + /// + public static class SingletonSystem + { + private static List _singletons; + private static Dictionary _gameObjects; + + public static void Retain(ISingleton go) + { + if (_singletons == null) + { + _singletons = new List(); + } + + _singletons.Add(go); + } + + public static void Retain(GameObject go) + { + if (_gameObjects == null) + { + _gameObjects = new Dictionary(); + } + + if (_gameObjects.TryAdd(go.name, go)) + { + if (Application.isPlaying) + { + Object.DontDestroyOnLoad(go); + } + } + } + + public static void Release(GameObject go) + { + if (_gameObjects != null && _gameObjects.ContainsKey(go.name)) + { + _gameObjects.Remove(go.name); + Object.Destroy(go); + } + } + + public static void Release(ISingleton go) + { + if (_singletons != null && _singletons.Contains(go)) + { + _singletons.Remove(go); + } + } + + public static void Release() + { + if (_gameObjects != null) + { + foreach (var item in _gameObjects) + { + Object.Destroy(item.Value); + } + + _gameObjects.Clear(); + } + + if (_singletons != null) + { + for (int i = 0; i < _singletons.Count; ++i) + { + _singletons[i].Release(); + } + + _singletons.Clear(); + } + + Resources.UnloadUnusedAssets(); + } + + public static GameObject GetGameObject(string name) + { + GameObject go = null; + if (_gameObjects != null) + { + _gameObjects.TryGetValue(name, out go); + } + + return go; + } + + internal static bool ContainsKey(string name) + { + if (_gameObjects != null) + { + return _gameObjects.ContainsKey(name); + } + + return false; + } + + public static void Restart() + { + if (Camera.main != null) + { + Camera.main.gameObject.SetActive(false); + } + + Release(); + SceneManager.LoadScene(0); + } + + internal static ISingleton GetSingleton(string name) + { + for (int i = 0; i < _singletons.Count; ++i) + { + if (_singletons[i].ToString() == name) + { + return _singletons[i]; + } + } + + return null; + } + } +} \ No newline at end of file diff --git a/UnityProject/Assets/GameScripts/HotFix/GameBase/SingletonSystem.cs.meta b/UnityProject/Assets/GameScripts/HotFix/GameBase/SingletonSystem.cs.meta new file mode 100644 index 00000000..21fcf5b1 --- /dev/null +++ b/UnityProject/Assets/GameScripts/HotFix/GameBase/SingletonSystem.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4ad00b596d0743a4b04591fe52087d0f +timeCreated: 1715574577 \ No newline at end of file diff --git a/UnityProject/Assets/GameScripts/HotFix/GameLogic/GameApp.cs b/UnityProject/Assets/GameScripts/HotFix/GameLogic/GameApp.cs index f5707b3b..0f3bd97e 100644 --- a/UnityProject/Assets/GameScripts/HotFix/GameLogic/GameApp.cs +++ b/UnityProject/Assets/GameScripts/HotFix/GameLogic/GameApp.cs @@ -19,7 +19,7 @@ public partial class GameApp:Singleton _hotfixAssembly = (List)objects[0]; Log.Warning("======= 看到此条日志代表你成功运行了热更新代码 ======="); Log.Warning("======= Entrance GameApp ======="); - Instance.Init(); + Instance.Active(); Instance.Start(); Utility.Unity.AddUpdateListener(Instance.Update); Utility.Unity.AddFixedUpdateListener(Instance.FixedUpdate); @@ -60,8 +60,9 @@ public partial class GameApp:Singleton Utility.Unity.RemoveDestroyListener(Instance.OnDestroy); Utility.Unity.RemoveOnDrawGizmosListener(Instance.OnDrawGizmos); Utility.Unity.RemoveOnApplicationPauseListener(Instance.OnApplicationPause); - return; } + + SingletonSystem.Release(); } private void Start() diff --git a/UnityProject/Assets/GameScripts/HotFix/GameLogic/GameApp_RegisterSystem.cs b/UnityProject/Assets/GameScripts/HotFix/GameLogic/GameApp_RegisterSystem.cs index 9c973f17..357f72a1 100644 --- a/UnityProject/Assets/GameScripts/HotFix/GameLogic/GameApp_RegisterSystem.cs +++ b/UnityProject/Assets/GameScripts/HotFix/GameLogic/GameApp_RegisterSystem.cs @@ -7,7 +7,7 @@ public partial class GameApp { private List _listLogicMgr; - private void Init() + public override void Active() { CodeTypes.Instance.Init(_hotfixAssembly.ToArray()); EventInterfaceHelper.Init();