diff --git a/Convention/[Architecture]/Architecture.cs b/Convention/[Architecture]/Architecture.cs index 9f0a59e..e4405cd 100644 --- a/Convention/[Architecture]/Architecture.cs +++ b/Convention/[Architecture]/Architecture.cs @@ -1,9 +1,6 @@ -using Convention; -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; using Convention.Experimental.PublicType; +using System; +using System.Collections.Generic; namespace Convention.Experimental { @@ -16,14 +13,23 @@ namespace Convention.Experimental /// /// 要创建的类型 /// 要创建的 - private static GameModule CreateModule(Type moduleType) + private static GameModule CreateModule(Type moduleType, int stackLayer = 0) { + if (stackLayer >= 100) + { + throw new GameException($"Create module '{moduleType.FullName}' failed, recursion too deep, there may be a circular dependency."); + } + GameModule module = (GameModule)Activator.CreateInstance(moduleType); if (module == null) { throw new GameException($"Can not create module '{moduleType.FullName}'"); } + // 递归创建依赖模块 + foreach (var dependenceType in module.Dependences()) + _ = GetModule(dependenceType, stackLayer + 1); + LinkedListNode current = s_GameFrameworkModules.First; while (current != null) { @@ -53,7 +59,7 @@ namespace Convention.Experimental /// 要获取的 /// 要获取的 /// 如果要获取的不存在,则自动创建该实例。 - private static GameModule GetModule(Type moduleType) + private static GameModule GetModule(Type moduleType, int stackLayer = 0) { foreach (GameModule module in s_GameFrameworkModules) { @@ -63,7 +69,7 @@ namespace Convention.Experimental } } - return CreateModule(moduleType); + return CreateModule(moduleType, stackLayer + 1); } /// diff --git a/Convention/[Architecture]/Modules.meta b/Convention/[Architecture]/Modules.meta new file mode 100644 index 0000000..2376210 --- /dev/null +++ b/Convention/[Architecture]/Modules.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 591a2c63cd01a22408284eeaa811e930 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Convention/[Architecture]/PublicType/GameModule.cs b/Convention/[Architecture]/PublicType/GameModule.cs index 7aee320..bbf4ca7 100644 --- a/Convention/[Architecture]/PublicType/GameModule.cs +++ b/Convention/[Architecture]/PublicType/GameModule.cs @@ -1,18 +1,17 @@ -using System.Collections; +using System; using System.Collections.Generic; -using UnityEngine; namespace Convention.Experimental.PublicType { /// - /// 游戏框架模块抽象类。 + /// 游戏框架模块抽象类 /// public abstract class GameModule { /// - /// 获取游戏框架模块优先级。 + /// 获取游戏框架模块优先级 /// - /// 优先级较高的模块会优先轮询,并且关闭操作会后进行。 + /// 优先级较高的模块会优先轮询,优先级较低的模块会优先卸载 internal virtual int Priority { get @@ -22,15 +21,20 @@ namespace Convention.Experimental.PublicType } /// - /// 游戏框架模块轮询。 + /// 游戏框架模块轮询 /// - /// 逻辑流逝时间,以秒为单位。 - /// 真实流逝时间,以秒为单位。 - internal abstract void Update(float elapseSeconds, float realElapseSeconds); + /// 逻辑流逝时间,以秒为单位 + /// 真实流逝时间,以秒为单位 + internal virtual void Update(float elapseSeconds, float realElapseSeconds) { } /// - /// 关闭并清理游戏框架模块。 + /// 关闭并清理游戏框架模块 /// - internal abstract void Shutdown(); + internal virtual void Shutdown() { } + + /// + /// 前置依赖的游戏框架模块类型集合 + /// + internal virtual IEnumerable Dependences() => Array.Empty(); } } diff --git a/Convention/[Architecture]/PublicType/ReferencePool.cs b/Convention/[Architecture]/PublicType/ReferencePool.cs new file mode 100644 index 0000000..f6bfbd9 --- /dev/null +++ b/Convention/[Architecture]/PublicType/ReferencePool.cs @@ -0,0 +1,491 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Unity.VisualScripting; +using UnityEngine; + +namespace Convention.Experimental.PublicType +{ + /// + /// 引用接口。 + /// + public interface IReference + { + /// + /// 清理引用。 + /// + void Clear(); + } + + /// + /// 引用池 + /// + public static partial class ReferencePool + { + private static bool m_EnableStrictCheck = false; + + /// + /// 获取或设置是否开启强制检查 + /// + public static bool EnableStrictCheck + { + get + { + return m_EnableStrictCheck; + } + set + { + m_EnableStrictCheck = value; + } + } + + + private sealed class ReferenceCollection + { + private readonly Queue m_References; + private readonly Type m_ReferenceType; + private int m_UsingReferenceCount; + private int m_AcquireReferenceCount; + private int m_ReleaseReferenceCount; + private int m_AddReferenceCount; + private int m_RemoveReferenceCount; + + public ReferenceCollection(Type referenceType) + { + m_References = new Queue(); + m_ReferenceType = referenceType; + m_UsingReferenceCount = 0; + m_AcquireReferenceCount = 0; + m_ReleaseReferenceCount = 0; + m_AddReferenceCount = 0; + m_RemoveReferenceCount = 0; + } + + public Type ReferenceType + { + get + { + return m_ReferenceType; + } + } + + public int UnusedReferenceCount + { + get + { + return m_References.Count; + } + } + + public int UsingReferenceCount + { + get + { + return m_UsingReferenceCount; + } + } + + public int AcquireReferenceCount + { + get + { + return m_AcquireReferenceCount; + } + } + + public int ReleaseReferenceCount + { + get + { + return m_ReleaseReferenceCount; + } + } + + public int AddReferenceCount + { + get + { + return m_AddReferenceCount; + } + } + + public int RemoveReferenceCount + { + get + { + return m_RemoveReferenceCount; + } + } + + public T Acquire() where T : class, IReference, new() + { + if (typeof(T) != m_ReferenceType) + { + throw new GameException("Type is invalid."); + } + + m_UsingReferenceCount++; + m_AcquireReferenceCount++; + lock (m_References) + { + if (m_References.Count > 0) + { + return (T)m_References.Dequeue(); + } + } + + m_AddReferenceCount++; + return new T(); + } + + public IReference Acquire() + { + m_UsingReferenceCount++; + m_AcquireReferenceCount++; + lock (m_References) + { + if (m_References.Count > 0) + { + return m_References.Dequeue(); + } + } + + m_AddReferenceCount++; + return (IReference)Activator.CreateInstance(m_ReferenceType); + } + + public void Release(IReference reference) + { + reference.Clear(); + lock (m_References) + { + if (m_EnableStrictCheck && m_References.Contains(reference)) + { + throw new GameException("The reference has been released."); + } + + m_References.Enqueue(reference); + } + + m_ReleaseReferenceCount++; + m_UsingReferenceCount--; + } + + public void Add(int count) where T : class, IReference, new() + { + if (typeof(T) != m_ReferenceType) + { + throw new GameException("Type is invalid."); + } + + lock (m_References) + { + m_AddReferenceCount += count; + while (count-- > 0) + { + m_References.Enqueue(new T()); + } + } + } + + public void Add(int count) + { + lock (m_References) + { + m_AddReferenceCount += count; + while (count-- > 0) + { + m_References.Enqueue((IReference)Activator.CreateInstance(m_ReferenceType)); + } + } + } + + public void Remove(int count) + { + lock (m_References) + { + if (count > m_References.Count) + { + count = m_References.Count; + } + + m_RemoveReferenceCount += count; + while (count-- > 0) + { + m_References.Dequeue(); + } + } + } + + public void RemoveAll() + { + lock (m_References) + { + m_RemoveReferenceCount += m_References.Count; + m_References.Clear(); + } + } + } + + private static readonly Dictionary s_ReferenceCollections = new(); + + /// + /// 获取引用池的数量。 + /// + public static int Count + { + get + { + return s_ReferenceCollections.Count; + } + } + + /// + /// 引用池信息 + /// + [StructLayout(LayoutKind.Auto)] + public readonly struct ReferencePoolInfo + { + /// + /// 引用池类型 + /// + public readonly Type Type; + /// + /// 未使用引用数量 + /// + public readonly int UnusedReferenceCount; + /// + /// 正在使用引用数量 + /// + public readonly int UsingReferenceCount; + /// + /// 获取引用数量 + /// + public readonly int AcquireReferenceCount; + /// + /// 归还引用数量 + /// + public readonly int ReleaseReferenceCount; + /// + /// 增加引用数量 + /// + public readonly int AddReferenceCount; + /// + /// 移除引用数量 + /// + public readonly int RemoveReferenceCount; + + /// + /// 初始化引用池信息的新实例。 + /// + /// 引用池类型。 + /// 未使用引用数量。 + /// 正在使用引用数量。 + /// 获取引用数量。 + /// 归还引用数量。 + /// 增加引用数量。 + /// 移除引用数量。 + public ReferencePoolInfo(Type type, + int unusedReferenceCount, + int usingReferenceCount, + int acquireReferenceCount, + int releaseReferenceCount, + int addReferenceCount, + int removeReferenceCount) + { + this.Type = type; + this.UnusedReferenceCount = unusedReferenceCount; + this.UsingReferenceCount = usingReferenceCount; + this.AcquireReferenceCount = acquireReferenceCount; + this.ReleaseReferenceCount = releaseReferenceCount; + this.AddReferenceCount = addReferenceCount; + this.RemoveReferenceCount = removeReferenceCount; + } + } + + /// + /// 获取所有引用池的信息 + /// + /// 所有引用池的信息 + public static ReferencePoolInfo[] GetAllReferencePoolInfos() + { + int index = 0; + ReferencePoolInfo[] results = null; + + lock (s_ReferenceCollections) + { + results = new ReferencePoolInfo[s_ReferenceCollections.Count]; + foreach (var (key,value) in s_ReferenceCollections) + { + results[index++] = new ReferencePoolInfo(key, + value.UnusedReferenceCount, + value.UsingReferenceCount, + value.AcquireReferenceCount, + value.ReleaseReferenceCount, + value.AddReferenceCount, + value.RemoveReferenceCount); + } + } + + return results; + } + + /// + /// 清除所有引用池 + /// + public static void ClearAll() + { + lock (s_ReferenceCollections) + { + foreach (var (_, value) in s_ReferenceCollections) + { + value.RemoveAll(); + } + + s_ReferenceCollections.Clear(); + } + } + + private static ReferenceCollection GetReferenceCollection(Type referenceType) + { + if (referenceType == null) + { + throw new GameException("ReferenceType is invalid."); + } + + ReferenceCollection referenceCollection = null; + lock (s_ReferenceCollections) + { + if (!s_ReferenceCollections.TryGetValue(referenceType, out referenceCollection)) + { + referenceCollection = new ReferenceCollection(referenceType); + s_ReferenceCollections.Add(referenceType, referenceCollection); + } + } + + return referenceCollection; + } + + private static void InternalCheckReferenceType(Type referenceType) + { + if (!m_EnableStrictCheck) + { + return; + } + + if (referenceType == null) + { + throw new GameException("Reference type is invalid."); + } + + if (!referenceType.IsClass || referenceType.IsAbstract) + { + throw new GameException("Reference type is not a non-abstract class type."); + } + + if (!typeof(IReference).IsAssignableFrom(referenceType)) + { + throw new GameException($"Reference type '{referenceType.FullName}' is invalid."); + } + } + + /// + /// 从引用池获取引用 + /// + /// 引用类型 + /// 引用 + public static IReference Acquire(Type referenceType) + { + InternalCheckReferenceType(referenceType); + return GetReferenceCollection(referenceType).Acquire(); + } + + /// + /// 从引用池获取引用 + /// + /// 引用类型 + /// 引用 + public static T Acquire() where T : class, IReference, new() + { + return GetReferenceCollection(typeof(T)).Acquire(); + } + + /// + /// 将引用归还引用池 + /// + /// 引用 + public static void Release(IReference reference) + { + if (reference == null) + { + throw new GameException("Reference is invalid."); + } + + Type referenceType = reference.GetType(); + InternalCheckReferenceType(referenceType); + GetReferenceCollection(referenceType).Release(reference); + } + + /// + /// 向引用池中追加指定数量的引用 + /// + /// 引用类型 + /// 追加数量 + public static void Add(int count) where T : class, IReference, new() + { + GetReferenceCollection(typeof(T)).Add(count); + } + + /// + /// 向引用池中追加指定数量的引用 + /// + /// 引用类型 + /// 追加数量 + public static void Add(Type referenceType, int count) + { + InternalCheckReferenceType(referenceType); + GetReferenceCollection(referenceType).Add(count); + } + + /// + /// 从引用池中移除指定数量的引用 + /// + /// 引用类型 + /// 移除数量 + public static void Remove(int count) where T : class, IReference + { + GetReferenceCollection(typeof(T)).Remove(count); + } + + /// + /// 从引用池中移除指定数量的引用 + /// + /// 引用类型 + /// 移除数量 + public static void Remove(Type referenceType, int count) + { + InternalCheckReferenceType(referenceType); + GetReferenceCollection(referenceType).Remove(count); + } + + /// + /// 从引用池中移除所有的引用 + /// + /// 引用类型 + public static void RemoveAll() where T : class, IReference + { + GetReferenceCollection(typeof(T)).RemoveAll(); + } + + /// + /// 从引用池中移除所有的引用。 + /// + /// 引用类型。 + public static void RemoveAll(Type referenceType) + { + InternalCheckReferenceType(referenceType); + GetReferenceCollection(referenceType).RemoveAll(); + } + } +} \ No newline at end of file diff --git a/Convention/[Architecture]/PublicType/ReferencePool.cs.meta b/Convention/[Architecture]/PublicType/ReferencePool.cs.meta new file mode 100644 index 0000000..ce23ab7 --- /dev/null +++ b/Convention/[Architecture]/PublicType/ReferencePool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7a8ec3e4cc6e7e242b158fc02010c774 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Convention/[Runtime]/Config.cs b/Convention/[Runtime]/Config.cs index 98953d6..361ce2c 100644 --- a/Convention/[Runtime]/Config.cs +++ b/Convention/[Runtime]/Config.cs @@ -1285,6 +1285,7 @@ namespace Convention } private static CoroutineMonoStarterUtil CoroutineStarter; + public static GameObject Singleton => CoroutineStarter.gameObject; private class CoroutineMonoStarterUtil : MonoBehaviour {