From 1afdb95231ec60d04198a1c802f183372af9ced1 Mon Sep 17 00:00:00 2001 From: ninemine <1371605831@qq.com> Date: Thu, 20 Nov 2025 17:29:16 +0800 Subject: [PATCH] =?UTF-8?q?=E5=87=86=E5=A4=87=E6=9B=B4=E6=96=B0BP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Convention/[Architecture]/Architecture.cs | 3 + .../Modules/ActionManager.cs.meta | 11 + .../PublicType/LinkedCacheList.cs | 445 ---------- .../PublicType/ReferencePool.cs | 481 ----------- Convention/[Runtime]/Config.cs | 13 +- .../[Runtime]/Convention.Collections.cs | 456 ++++++++++ .../[Runtime]/Convention.Collections.cs.meta | 11 + .../[Runtime]/Convention.ReferencePool.cs | 490 +++++++++++ .../Convention.ReferencePool.cs.meta | 11 + Convention/[Runtime]/Convention.TaskPool.cs | 803 ++++++++++++++++++ .../[Runtime]/Convention.TaskPool.cs.meta | 11 + Convention/[Runtime]/File.cs | 79 +- 12 files changed, 1849 insertions(+), 965 deletions(-) create mode 100644 Convention/[Architecture]/Modules/ActionManager.cs.meta create mode 100644 Convention/[Runtime]/Convention.Collections.cs create mode 100644 Convention/[Runtime]/Convention.Collections.cs.meta create mode 100644 Convention/[Runtime]/Convention.ReferencePool.cs create mode 100644 Convention/[Runtime]/Convention.ReferencePool.cs.meta create mode 100644 Convention/[Runtime]/Convention.TaskPool.cs create mode 100644 Convention/[Runtime]/Convention.TaskPool.cs.meta diff --git a/Convention/[Architecture]/Architecture.cs b/Convention/[Architecture]/Architecture.cs index 26dcf87..0a9d5d7 100644 --- a/Convention/[Architecture]/Architecture.cs +++ b/Convention/[Architecture]/Architecture.cs @@ -1,4 +1,7 @@ +using Convention.Collections; +using Convention.Collections.Generic; using Convention.Experimental.PublicType; +using Convention.ReferenceManagement; using System; using System.Collections.Generic; diff --git a/Convention/[Architecture]/Modules/ActionManager.cs.meta b/Convention/[Architecture]/Modules/ActionManager.cs.meta new file mode 100644 index 0000000..5a4b2d4 --- /dev/null +++ b/Convention/[Architecture]/Modules/ActionManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d8ac4985ed7261b4eb47642f5a27a1f5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Convention/[Architecture]/PublicType/LinkedCacheList.cs b/Convention/[Architecture]/PublicType/LinkedCacheList.cs index edaaa73..b9a37cc 100644 --- a/Convention/[Architecture]/PublicType/LinkedCacheList.cs +++ b/Convention/[Architecture]/PublicType/LinkedCacheList.cs @@ -7,449 +7,4 @@ using UnityEngine; namespace Convention.Experimental.PublicType { - /// - /// 附带有缓存机制的链表类。 - /// - /// 指定链表的元素类型。 - public sealed class LinkedCacheList : ICollection, IEnumerable, ICollection, IEnumerable - { - private readonly LinkedList m_LinkedList; - /// - /// 之所以需要这套缓存机制,主要有三点好处: - /// 减少 GC 压力:大量频繁的插入/删除会产生很多短生命周期的节点对象,通过复用可以显著降低托管堆的分配与回收次数 - /// 提升性能:避免频繁 new 和 GC,能减少停顿时间,提高链表在高频操作场景下的吞吐 - /// 便于观察与管理:类中还提供了 CachedNodeCount 方便调试统计缓存规模,必要时可通过 ClearCachedNodes 主动释放 - /// 适用场景是节点使用模式“高频增删但总量有限”,此时缓存能稳定性能;若链表规模始终在增长且很少释放,缓存收益会较低。 - /// - private readonly Queue> m_CachedNodes; - - /// - /// 初始化游戏框架链表类的新实例。 - /// - public LinkedCacheList() - { - m_LinkedList = new LinkedList(); - m_CachedNodes = new Queue>(); - } - - /// - /// 获取链表中实际包含的结点数量。 - /// - public int Count - { - get - { - return m_LinkedList.Count; - } - } - - /// - /// 获取链表结点缓存数量。 - /// - public int CachedNodeCount - { - get - { - return m_CachedNodes.Count; - } - } - - /// - /// 获取链表的第一个结点。 - /// - public LinkedListNode First - { - get - { - return m_LinkedList.First; - } - } - - /// - /// 获取链表的最后一个结点。 - /// - public LinkedListNode Last - { - get - { - return m_LinkedList.Last; - } - } - - /// - /// 获取一个值,该值指示 ICollection`1 是否为只读。 - /// - public bool IsReadOnly - { - get - { - return ((ICollection)m_LinkedList).IsReadOnly; - } - } - - /// - /// 获取可用于同步对 ICollection 的访问的对象。 - /// - public object SyncRoot - { - get - { - return ((ICollection)m_LinkedList).SyncRoot; - } - } - - /// - /// 获取一个值,该值指示是否同步对 ICollection 的访问(线程安全)。 - /// - public bool IsSynchronized - { - get - { - return ((ICollection)m_LinkedList).IsSynchronized; - } - } - - /// - /// 在链表中指定的现有结点后添加包含指定值的新结点。 - /// - /// 指定的现有结点。 - /// 指定值。 - /// 包含指定值的新结点。 - public LinkedListNode AddAfter(LinkedListNode node, T value) - { - LinkedListNode newNode = AcquireNode(value); - m_LinkedList.AddAfter(node, newNode); - return newNode; - } - - /// - /// 在链表中指定的现有结点后添加指定的新结点。 - /// - /// 指定的现有结点。 - /// 指定的新结点。 - public void AddAfter(LinkedListNode node, LinkedListNode newNode) - { - m_LinkedList.AddAfter(node, newNode); - } - - /// - /// 在链表中指定的现有结点前添加包含指定值的新结点。 - /// - /// 指定的现有结点。 - /// 指定值。 - /// 包含指定值的新结点。 - public LinkedListNode AddBefore(LinkedListNode node, T value) - { - LinkedListNode newNode = AcquireNode(value); - m_LinkedList.AddBefore(node, newNode); - return newNode; - } - - /// - /// 在链表中指定的现有结点前添加指定的新结点。 - /// - /// 指定的现有结点。 - /// 指定的新结点。 - public void AddBefore(LinkedListNode node, LinkedListNode newNode) - { - m_LinkedList.AddBefore(node, newNode); - } - - /// - /// 在链表的开头处添加包含指定值的新结点。 - /// - /// 指定值。 - /// 包含指定值的新结点。 - public LinkedListNode AddFirst(T value) - { - LinkedListNode node = AcquireNode(value); - m_LinkedList.AddFirst(node); - return node; - } - - /// - /// 在链表的开头处添加指定的新结点。 - /// - /// 指定的新结点。 - public void AddFirst(LinkedListNode node) - { - m_LinkedList.AddFirst(node); - } - - /// - /// 在链表的结尾处添加包含指定值的新结点。 - /// - /// 指定值。 - /// 包含指定值的新结点。 - public LinkedListNode AddLast(T value) - { - LinkedListNode node = AcquireNode(value); - m_LinkedList.AddLast(node); - return node; - } - - /// - /// 在链表的结尾处添加指定的新结点。 - /// - /// 指定的新结点。 - public void AddLast(LinkedListNode node) - { - m_LinkedList.AddLast(node); - } - - /// - /// 从链表中移除所有结点。 - /// - public void Clear() - { - LinkedListNode current = m_LinkedList.First; - while (current != null) - { - ReleaseNode(current); - current = current.Next; - } - - m_LinkedList.Clear(); - } - - /// - /// 清除链表结点缓存。 - /// - public void ClearCachedNodes() - { - m_CachedNodes.Clear(); - } - - /// - /// 确定某值是否在链表中。 - /// - /// 指定值。 - /// 某值是否在链表中。 - public bool Contains(T value) - { - return m_LinkedList.Contains(value); - } - - /// - /// 从目标数组的指定索引处开始将整个链表复制到兼容的一维数组。 - /// - /// 一维数组,它是从链表复制的元素的目标。数组必须具有从零开始的索引。 - /// array 中从零开始的索引,从此处开始复制。 - public void CopyTo(T[] array, int index) - { - m_LinkedList.CopyTo(array, index); - } - - /// - /// 从特定的 ICollection 索引开始,将数组的元素复制到一个数组中。 - /// - /// 一维数组,它是从 ICollection 复制的元素的目标。数组必须具有从零开始的索引。 - /// array 中从零开始的索引,从此处开始复制。 - public void CopyTo(Array array, int index) - { - ((ICollection)m_LinkedList).CopyTo(array, index); - } - - /// - /// 查找包含指定值的第一个结点。 - /// - /// 要查找的指定值。 - /// 包含指定值的第一个结点。 - public LinkedListNode Find(T value) - { - return m_LinkedList.Find(value); - } - - /// - /// 查找包含指定值的最后一个结点。 - /// - /// 要查找的指定值。 - /// 包含指定值的最后一个结点。 - public LinkedListNode FindLast(T value) - { - return m_LinkedList.FindLast(value); - } - - /// - /// 从链表中移除指定值的第一个匹配项。 - /// - /// 指定值。 - /// 是否移除成功。 - public bool Remove(T value) - { - LinkedListNode node = m_LinkedList.Find(value); - if (node != null) - { - m_LinkedList.Remove(node); - ReleaseNode(node); - return true; - } - - return false; - } - - /// - /// 从链表中移除指定的结点。 - /// - /// 指定的结点。 - public void Remove(LinkedListNode node) - { - m_LinkedList.Remove(node); - ReleaseNode(node); - } - - /// - /// 移除位于链表开头处的结点。 - /// - public void RemoveFirst() - { - LinkedListNode first = m_LinkedList.First; - if (first == null) - { - throw new GameException("First is invalid."); - } - - m_LinkedList.RemoveFirst(); - ReleaseNode(first); - } - - /// - /// 移除位于链表结尾处的结点。 - /// - public void RemoveLast() - { - LinkedListNode last = m_LinkedList.Last; - if (last == null) - { - throw new GameException("Last is invalid."); - } - - m_LinkedList.RemoveLast(); - ReleaseNode(last); - } - - /// - /// 返回循环访问集合的枚举数。 - /// - /// 循环访问集合的枚举数。 - public Enumerator GetEnumerator() - { - return new Enumerator(m_LinkedList); - } - - private LinkedListNode AcquireNode(T value) - { - LinkedListNode node = null; - if (m_CachedNodes.Count > 0) - { - node = m_CachedNodes.Dequeue(); - node.Value = value; - } - else - { - node = new LinkedListNode(value); - } - - return node; - } - - private void ReleaseNode(LinkedListNode node) - { - node.Value = default(T); - m_CachedNodes.Enqueue(node); - } - - /// - /// 将值添加到 ICollection`1 的结尾处。 - /// - /// 要添加的值。 - void ICollection.Add(T value) - { - AddLast(value); - } - - /// - /// 返回循环访问集合的枚举数。 - /// - /// 循环访问集合的枚举数。 - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - /// 返回循环访问集合的枚举数。 - /// - /// 循环访问集合的枚举数。 - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - /// 循环访问集合的枚举数。 - /// - [StructLayout(LayoutKind.Auto)] - public struct Enumerator : IEnumerator, IEnumerator - { - private LinkedList.Enumerator m_Enumerator; - - internal Enumerator(LinkedList linkedList) - { - if (linkedList == null) - { - throw new GameException("Linked list is invalid."); - } - - m_Enumerator = linkedList.GetEnumerator(); - } - - /// - /// 获取当前结点。 - /// - public T Current - { - get - { - return m_Enumerator.Current; - } - } - - /// - /// 获取当前的枚举数。 - /// - object IEnumerator.Current - { - get - { - return m_Enumerator.Current; - } - } - - /// - /// 清理枚举数。 - /// - public void Dispose() - { - m_Enumerator.Dispose(); - } - - /// - /// 获取下一个结点。 - /// - /// 返回下一个结点。 - public bool MoveNext() - { - return m_Enumerator.MoveNext(); - } - - /// - /// 重置枚举数。 - /// - void IEnumerator.Reset() - { - ((IEnumerator)m_Enumerator).Reset(); - } - } - } } diff --git a/Convention/[Architecture]/PublicType/ReferencePool.cs b/Convention/[Architecture]/PublicType/ReferencePool.cs index f6bfbd9..20d2569 100644 --- a/Convention/[Architecture]/PublicType/ReferencePool.cs +++ b/Convention/[Architecture]/PublicType/ReferencePool.cs @@ -7,485 +7,4 @@ 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/[Runtime]/Config.cs b/Convention/[Runtime]/Config.cs index 43631ab..c59e4d7 100644 --- a/Convention/[Runtime]/Config.cs +++ b/Convention/[Runtime]/Config.cs @@ -1,4 +1,7 @@ -using System; +using Convention.Experimental.PublicType; +using Convention.WindowsUI; +using Sirenix.Utilities; +using System; using System.Collections; using System.Collections.Generic; using System.IO; @@ -7,8 +10,6 @@ using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Threading; -using Convention.WindowsUI; -using Sirenix.Utilities; using UnityEditor; using UnityEngine; using UnityEngine.Events; @@ -2528,9 +2529,3 @@ namespace Convention } } -namespace Convention.Collections -{ - namespace Generic - { - } -} diff --git a/Convention/[Runtime]/Convention.Collections.cs b/Convention/[Runtime]/Convention.Collections.cs new file mode 100644 index 0000000..ec79408 --- /dev/null +++ b/Convention/[Runtime]/Convention.Collections.cs @@ -0,0 +1,456 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace Convention.Collections +{ + namespace Generic + { + /// + /// лƵ + /// + /// ָԪ + public sealed class LinkedCacheList : ICollection, IEnumerable, ICollection, IEnumerable + { + private readonly LinkedList m_LinkedList; + /// + /// ֮Ҫ׻ƣҪô + /// GC ѹƵIJ/ɾܶڵĽڵͨÿйܶѵķմ + /// ܣƵ new GCܼͣʱ䣬ڸƵµ + /// ڹ۲лṩ CachedNodeCount ͳƻģҪʱͨ ClearCachedNodes ͷ + /// óǽڵʹģʽƵɾޡʱȶܣģʼҺͷţϵ͡ + /// + private readonly Queue> m_CachedNodes; + + /// + /// ʼϷʵ + /// + public LinkedCacheList() + { + m_LinkedList = new LinkedList(); + m_CachedNodes = new Queue>(); + } + + /// + /// ȡʵʰĽ + /// + public int Count + { + get + { + return m_LinkedList.Count; + } + } + + /// + /// ȡ㻺 + /// + public int CachedNodeCount + { + get + { + return m_CachedNodes.Count; + } + } + + /// + /// ȡĵһ + /// + public LinkedListNode First + { + get + { + return m_LinkedList.First; + } + } + + /// + /// ȡһ + /// + public LinkedListNode Last + { + get + { + return m_LinkedList.Last; + } + } + + /// + /// ȡһֵֵָʾ ǷΪֻ + /// + public bool IsReadOnly + { + get + { + return ((ICollection)m_LinkedList).IsReadOnly; + } + } + + /// + /// ȡͬ ķʵĶ + /// + public object SyncRoot + { + get + { + return ((ICollection)m_LinkedList).SyncRoot; + } + } + + /// + /// ȡһֵֵָʾǷͬ ķʣ̰߳ȫ + /// + public bool IsSynchronized + { + get + { + return ((ICollection)m_LinkedList).IsSynchronized; + } + } + + /// + /// ָнӰֵָ½ + /// + /// ָн + /// ֵָ + /// ֵָ½ + public LinkedListNode AddAfter(LinkedListNode node, T value) + { + LinkedListNode newNode = AcquireNode(value); + m_LinkedList.AddAfter(node, newNode); + return newNode; + } + + /// + /// ָнָ½ + /// + /// ָн + /// ָ½ + public void AddAfter(LinkedListNode node, LinkedListNode newNode) + { + m_LinkedList.AddAfter(node, newNode); + } + + /// + /// ָнǰӰֵָ½ + /// + /// ָн + /// ֵָ + /// ֵָ½ + public LinkedListNode AddBefore(LinkedListNode node, T value) + { + LinkedListNode newNode = AcquireNode(value); + m_LinkedList.AddBefore(node, newNode); + return newNode; + } + + /// + /// ָнǰָ½ + /// + /// ָн + /// ָ½ + public void AddBefore(LinkedListNode node, LinkedListNode newNode) + { + m_LinkedList.AddBefore(node, newNode); + } + + /// + /// ĿͷӰֵָ½ + /// + /// ֵָ + /// ֵָ½ + public LinkedListNode AddFirst(T value) + { + LinkedListNode node = AcquireNode(value); + m_LinkedList.AddFirst(node); + return node; + } + + /// + /// Ŀͷָ½ + /// + /// ָ½ + public void AddFirst(LinkedListNode node) + { + m_LinkedList.AddFirst(node); + } + + /// + /// ĽβӰֵָ½ + /// + /// ֵָ + /// ֵָ½ + public LinkedListNode AddLast(T value) + { + LinkedListNode node = AcquireNode(value); + m_LinkedList.AddLast(node); + return node; + } + + /// + /// Ľβָ½ + /// + /// ָ½ + public void AddLast(LinkedListNode node) + { + m_LinkedList.AddLast(node); + } + + /// + /// Ƴн + /// + public void Clear() + { + LinkedListNode current = m_LinkedList.First; + while (current != null) + { + ReleaseNode(current); + current = current.Next; + } + + m_LinkedList.Clear(); + } + + /// + /// 㻺 + /// + public void ClearCachedNodes() + { + m_CachedNodes.Clear(); + } + + /// + /// ȷijֵǷ + /// + /// ֵָ + /// ijֵǷ + public bool Contains(T value) + { + return m_LinkedList.Contains(value); + } + + /// + /// ĿָʼƵݵһά + /// + /// һά飬ǴƵԪصĿꡣд㿪ʼ + /// array д㿪ʼӴ˴ʼ + public void CopyTo(T[] array, int index) + { + m_LinkedList.CopyTo(array, index); + } + + /// + /// ض ICollection ʼԪظƵһ + /// + /// һά飬Ǵ ICollection ƵԪصĿꡣд㿪ʼ + /// array д㿪ʼӴ˴ʼ + public void CopyTo(Array array, int index) + { + ((ICollection)m_LinkedList).CopyTo(array, index); + } + + /// + /// Ұֵָĵһ + /// + /// Ҫҵֵָ + /// ֵָĵһ + public LinkedListNode Find(T value) + { + return m_LinkedList.Find(value); + } + + /// + /// Ұֵָһ + /// + /// Ҫҵֵָ + /// ֵָһ + public LinkedListNode FindLast(T value) + { + return m_LinkedList.FindLast(value); + } + + /// + /// Ƴֵָĵһƥ + /// + /// ֵָ + /// ǷƳɹ + public bool Remove(T value) + { + LinkedListNode node = m_LinkedList.Find(value); + if (node != null) + { + m_LinkedList.Remove(node); + ReleaseNode(node); + return true; + } + + return false; + } + + /// + /// ƳָĽ + /// + /// ָĽ + public void Remove(LinkedListNode node) + { + m_LinkedList.Remove(node); + ReleaseNode(node); + } + + /// + /// ƳλͷĽ + /// + public void RemoveFirst() + { + LinkedListNode first = m_LinkedList.First; + if (first == null) + { + throw new InvalidOperationException("Rmove first is invalid."); + } + + m_LinkedList.RemoveFirst(); + ReleaseNode(first); + } + + /// + /// ƳλβĽ㡣 + /// + public void RemoveLast() + { + LinkedListNode last = m_LinkedList.Last; + if (last == null) + { + throw new InvalidOperationException("Remove last is invalid."); + } + + m_LinkedList.RemoveLast(); + ReleaseNode(last); + } + + /// + /// ѭʼϵö + /// + /// ѭʼϵö + public Enumerator GetEnumerator() + { + return new Enumerator(m_LinkedList); + } + + private LinkedListNode AcquireNode(T value) + { + LinkedListNode node = null; + if (m_CachedNodes.Count > 0) + { + node = m_CachedNodes.Dequeue(); + node.Value = value; + } + else + { + node = new LinkedListNode(value); + } + + return node; + } + + private void ReleaseNode(LinkedListNode node) + { + node.Value = default(T); + m_CachedNodes.Enqueue(node); + } + + /// + /// ֵӵ ICollection`1 Ľβ + /// + /// Ҫӵֵ + void ICollection.Add(T value) + { + AddLast(value); + } + + /// + /// ѭʼϵö + /// + /// ѭʼϵö + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// ѭʼϵö + /// + /// ѭʼϵö + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// ѭʼϵö + /// + [StructLayout(LayoutKind.Auto)] + public struct Enumerator : IEnumerator, IEnumerator + { + private LinkedList.Enumerator m_Enumerator; + + internal Enumerator(LinkedList linkedList) + { + if (linkedList == null) + { + throw new InvalidOperationException("Linked list is invalid."); + } + + m_Enumerator = linkedList.GetEnumerator(); + } + + /// + /// ȡǰ + /// + public T Current + { + get + { + return m_Enumerator.Current; + } + } + + /// + /// ȡǰö + /// + object IEnumerator.Current + { + get + { + return m_Enumerator.Current; + } + } + + /// + /// ö + /// + public void Dispose() + { + m_Enumerator.Dispose(); + } + + /// + /// ȡһ + /// + /// һ + public bool MoveNext() + { + return m_Enumerator.MoveNext(); + } + + /// + /// ö + /// + void IEnumerator.Reset() + { + ((IEnumerator)m_Enumerator).Reset(); + } + } + } + } +} \ No newline at end of file diff --git a/Convention/[Runtime]/Convention.Collections.cs.meta b/Convention/[Runtime]/Convention.Collections.cs.meta new file mode 100644 index 0000000..bb751a0 --- /dev/null +++ b/Convention/[Runtime]/Convention.Collections.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a40a6ad3561c922478840f163ea43790 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Convention/[Runtime]/Convention.ReferencePool.cs b/Convention/[Runtime]/Convention.ReferencePool.cs new file mode 100644 index 0000000..d37f47d --- /dev/null +++ b/Convention/[Runtime]/Convention.ReferencePool.cs @@ -0,0 +1,490 @@ + +using Convention.Experimental.PublicType; +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace Convention.ReferenceManagement +{ + /// + /// ýӿ + /// + 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/[Runtime]/Convention.ReferencePool.cs.meta b/Convention/[Runtime]/Convention.ReferencePool.cs.meta new file mode 100644 index 0000000..1be568d --- /dev/null +++ b/Convention/[Runtime]/Convention.ReferencePool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 84ff342f46113f140afa7a506fb879d4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Convention/[Runtime]/Convention.TaskPool.cs b/Convention/[Runtime]/Convention.TaskPool.cs new file mode 100644 index 0000000..7e26092 --- /dev/null +++ b/Convention/[Runtime]/Convention.TaskPool.cs @@ -0,0 +1,803 @@ +using Convention.Collections; +using Convention.Collections.Generic; +using Convention.ReferenceManagement; +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace Convention.TaskManagement +{ + /// + /// + /// + public abstract class TaskBase: IReference + { + /// + /// Ĭȼ + /// + public const int DefaultPriority = 0; + + private int m_SerialId; + private string m_Tag; + private int m_Priority; + private object m_UserData; + + private bool m_Done; + + /// + /// ʼʵ + /// + public TaskBase() + { + m_SerialId = 0; + m_Tag = null; + m_Priority = DefaultPriority; + m_Done = false; + m_UserData = null; + } + + /// + /// ȡб + /// + public int SerialId + { + get + { + return m_SerialId; + } + } + + /// + /// ȡıǩ + /// + public string Tag + { + get + { + return m_Tag; + } + } + + /// + /// ȡȼ + /// + public int Priority + { + get + { + return m_Priority; + } + } + + /// + /// ȡûԶ + /// + public object UserData + { + get + { + return m_UserData; + } + } + + /// + /// ȡǷ + /// + public bool Done + { + get + { + return m_Done; + } + set + { + m_Done = value; + } + } + + /// + /// ȡ + /// + public virtual string Description + { + get + { + return null; + } + } + + /// + /// ʼ + /// + /// б + /// ıǩ + /// ȼ + /// ûԶ + internal void Initialize(int serialId, string tag, int priority, object userData) + { + m_SerialId = serialId; + m_Tag = tag; + m_Priority = priority; + m_UserData = userData; + m_Done = false; + } + + /// + /// + /// + public virtual void Clear() + { + m_SerialId = 0; + m_Tag = null; + m_Priority = DefaultPriority; + m_UserData = null; + m_Done = false; + } + } + + /// + /// ʼ״̬ + /// + public enum StartTaskStatus : byte + { + /// + /// ̴ɴ + /// + Done = 0, + + /// + /// Լ + /// + CanResume, + + /// + /// ܼȴִ + /// + HasToWait, + + /// + /// ܼ񣬳δ֪ + /// + UnknownError + } + + /// + /// ӿ + /// + /// + public interface ITaskAgent where T : TaskBase + { + /// + /// ȡ + /// + T Task + { + get; + } + + /// + /// ʼ + /// + void Initialize(); + + /// + /// ѯ + /// + /// ߼ʱ䣬Ϊλ + /// ʵʱ䣬Ϊλ + void Update(float elapseSeconds, float realElapseSeconds); + + /// + /// رղ + /// + void Shutdown(); + + /// + /// ʼ + /// + /// Ҫ + /// ʼ״̬ + StartTaskStatus Start(T task); + + /// + /// ֹͣڴ + /// + void Reset(); + } + + /// + /// ״̬ + /// + public enum TaskStatus : byte + { + /// + /// δʼ + /// + Todo = 0, + + /// + /// ִ + /// + Doing, + + /// + /// + /// + Done + } + + /// + /// Ϣ + /// + [StructLayout(LayoutKind.Auto)] + public readonly struct TaskInfo + { + private readonly bool m_IsValid; + private readonly int m_SerialId; + private readonly string m_Tag; + private readonly int m_Priority; + private readonly object m_UserData; + private readonly TaskStatus m_Status; + private readonly string m_Description; + + /// + /// ʼϢʵ + /// + /// б + /// ıǩ + /// ȼ + /// ûԶ + /// ״̬ + /// + public TaskInfo(int serialId, string tag, int priority, object userData, TaskStatus status, string description) + { + m_IsValid = true; + m_SerialId = serialId; + m_Tag = tag; + m_Priority = priority; + m_UserData = userData; + m_Status = status; + m_Description = description; + } + + /// + /// ȡϢǷЧ + /// + public bool IsValid + { + get + { + return m_IsValid; + } + } + + /// + /// ȡб + /// + public int SerialId + { + get + { + if (!m_IsValid) + { + throw new InvalidOperationException("Data is invalid."); + } + + return m_SerialId; + } + } + + /// + /// ȡıǩ + /// + public string Tag + { + get + { + if (!m_IsValid) + { + throw new InvalidOperationException("Data is invalid."); + } + + return m_Tag; + } + } + + /// + /// ȡȼ + /// + public int Priority + { + get + { + if (!m_IsValid) + { + throw new InvalidOperationException("Data is invalid."); + } + + return m_Priority; + } + } + + /// + /// ȡûԶ + /// + public object UserData + { + get + { + if (!m_IsValid) + { + throw new InvalidOperationException("Data is invalid."); + } + + return m_UserData; + } + } + + /// + /// ȡ״̬ + /// + public TaskStatus Status + { + get + { + if (!m_IsValid) + { + throw new InvalidOperationException("Data is invalid."); + } + + return m_Status; + } + } + + /// + /// ȡ + /// + public string Description + { + get + { + if (!m_IsValid) + { + throw new InvalidOperationException("Data is invalid."); + } + + return m_Description; + } + } + } + + /// + /// + /// + /// + public class TaskPool where T : TaskBase + { + private readonly Stack> m_FreeAgents; + private readonly LinkedCacheList> m_WorkingAgents; + private readonly LinkedCacheList m_WaitingTasks; + private bool m_Paused; + + /// + /// ʼصʵ + /// + public TaskPool() + { + m_FreeAgents = new Stack>(); + m_WorkingAgents = new LinkedCacheList>(); + m_WaitingTasks = new LinkedCacheList(); + m_Paused = false; + } + + /// + /// ȡǷͣ + /// + public bool Paused + { + get + { + return m_Paused; + } + set + { + m_Paused = value; + } + } + + /// + /// ȡ + /// + public int TotalAgentCount + { + get + { + return FreeAgentCount + WorkingAgentCount; + } + } + + /// + /// ȡ + /// + public int FreeAgentCount + { + get + { + return m_FreeAgents.Count; + } + } + + /// + /// ȡ + /// + public int WorkingAgentCount + { + get + { + return m_WorkingAgents.Count; + } + } + + /// + /// ȡȴ + /// + public int WaitingTaskCount + { + get + { + return m_WaitingTasks.Count; + } + } + + /// + /// ѯ + /// + /// ߼ʱ䣬Ϊλ + /// ʵʱ䣬Ϊλ + public void Update(float elapseSeconds, float realElapseSeconds) + { + if (m_Paused) + { + return; + } + + ProcessRunningTasks(elapseSeconds, realElapseSeconds); + ProcessWaitingTasks(elapseSeconds, realElapseSeconds); + } + + /// + /// رղء + /// + public void Shutdown() + { + RemoveAllTasks(); + + while (FreeAgentCount > 0) + { + m_FreeAgents.Pop().Shutdown(); + } + } + + /// + /// + /// + /// Ҫӵ + public void AddAgent(ITaskAgent agent) + { + if (agent == null) + { + throw new InvalidOperationException("Task agent is invalid."); + } + + agent.Initialize(); + m_FreeAgents.Push(agent); + } + + /// + /// бŻȡϢ + /// + /// ҪȡϢбš + /// Ϣ + public TaskInfo GetTaskInfo(int serialId) + { + foreach (ITaskAgent workingAgent in m_WorkingAgents) + { + T workingTask = workingAgent.Task; + if (workingTask.SerialId == serialId) + { + return new TaskInfo(workingTask.SerialId, workingTask.Tag, workingTask.Priority, workingTask.UserData, workingTask.Done ? TaskStatus.Done : TaskStatus.Doing, workingTask.Description); + } + } + + foreach (T waitingTask in m_WaitingTasks) + { + if (waitingTask.SerialId == serialId) + { + return new TaskInfo(waitingTask.SerialId, waitingTask.Tag, waitingTask.Priority, waitingTask.UserData, TaskStatus.Todo, waitingTask.Description); + } + } + + return default(TaskInfo); + } + + /// + /// ıǩȡϢ + /// + /// ҪȡϢıǩ + /// Ϣ + public TaskInfo[] GetTaskInfos(string tag) + { + List results = new List(); + GetTaskInfos(tag, results); + return results.ToArray(); + } + + /// + /// ıǩȡϢ + /// + /// ҪȡϢıǩ + /// Ϣ + public void GetTaskInfos(string tag, List results) + { + if (results == null) + { + throw new InvalidOperationException("Results is invalid."); + } + + results.Clear(); + foreach (ITaskAgent workingAgent in m_WorkingAgents) + { + T workingTask = workingAgent.Task; + if (workingTask.Tag == tag) + { + results.Add(new TaskInfo(workingTask.SerialId, workingTask.Tag, workingTask.Priority, workingTask.UserData, workingTask.Done ? TaskStatus.Done : TaskStatus.Doing, workingTask.Description)); + } + } + + foreach (T waitingTask in m_WaitingTasks) + { + if (waitingTask.Tag == tag) + { + results.Add(new TaskInfo(waitingTask.SerialId, waitingTask.Tag, waitingTask.Priority, waitingTask.UserData, TaskStatus.Todo, waitingTask.Description)); + } + } + } + + /// + /// ȡϢ + /// + /// Ϣ + public TaskInfo[] GetAllTaskInfos() + { + int index = 0; + TaskInfo[] results = new TaskInfo[m_WorkingAgents.Count + m_WaitingTasks.Count]; + foreach (ITaskAgent workingAgent in m_WorkingAgents) + { + T workingTask = workingAgent.Task; + results[index++] = new TaskInfo(workingTask.SerialId, workingTask.Tag, workingTask.Priority, workingTask.UserData, workingTask.Done ? TaskStatus.Done : TaskStatus.Doing, workingTask.Description); + } + + foreach (T waitingTask in m_WaitingTasks) + { + results[index++] = new TaskInfo(waitingTask.SerialId, waitingTask.Tag, waitingTask.Priority, waitingTask.UserData, TaskStatus.Todo, waitingTask.Description); + } + + return results; + } + + /// + /// ȡϢ + /// + /// Ϣ + public void GetAllTaskInfos(List results) + { + if (results == null) + { + throw new InvalidOperationException("Results is invalid."); + } + + results.Clear(); + foreach (ITaskAgent workingAgent in m_WorkingAgents) + { + T workingTask = workingAgent.Task; + results.Add(new TaskInfo(workingTask.SerialId, workingTask.Tag, workingTask.Priority, workingTask.UserData, workingTask.Done ? TaskStatus.Done : TaskStatus.Doing, workingTask.Description)); + } + + foreach (T waitingTask in m_WaitingTasks) + { + results.Add(new TaskInfo(waitingTask.SerialId, waitingTask.Tag, waitingTask.Priority, waitingTask.UserData, TaskStatus.Todo, waitingTask.Description)); + } + } + + /// + /// + /// + /// Ҫӵ + public void AddTask(T task) + { + LinkedListNode current = m_WaitingTasks.Last; + while (current != null) + { + if (task.Priority <= current.Value.Priority) + { + break; + } + + current = current.Previous; + } + + if (current != null) + { + m_WaitingTasks.AddAfter(current, task); + } + else + { + m_WaitingTasks.AddFirst(task); + } + } + + /// + /// бƳ + /// + /// ҪƳбš + /// ǷƳɹ + public bool RemoveTask(int serialId) + { + foreach (T task in m_WaitingTasks) + { + if (task.SerialId == serialId) + { + m_WaitingTasks.Remove(task); + ReferencePool.Release(task); + return true; + } + } + + LinkedListNode> currentWorkingAgent = m_WorkingAgents.First; + while (currentWorkingAgent != null) + { + LinkedListNode> next = currentWorkingAgent.Next; + ITaskAgent workingAgent = currentWorkingAgent.Value; + T task = workingAgent.Task; + if (task.SerialId == serialId) + { + workingAgent.Reset(); + m_FreeAgents.Push(workingAgent); + m_WorkingAgents.Remove(currentWorkingAgent); + ReferencePool.Release(task); + return true; + } + + currentWorkingAgent = next; + } + + return false; + } + + /// + /// ıǩƳ + /// + /// ҪƳıǩ + /// Ƴ + public int RemoveTasks(string tag) + { + int count = 0; + + LinkedListNode currentWaitingTask = m_WaitingTasks.First; + while (currentWaitingTask != null) + { + LinkedListNode next = currentWaitingTask.Next; + T task = currentWaitingTask.Value; + if (task.Tag == tag) + { + m_WaitingTasks.Remove(currentWaitingTask); + ReferencePool.Release(task); + count++; + } + + currentWaitingTask = next; + } + + LinkedListNode> currentWorkingAgent = m_WorkingAgents.First; + while (currentWorkingAgent != null) + { + LinkedListNode> next = currentWorkingAgent.Next; + ITaskAgent workingAgent = currentWorkingAgent.Value; + T task = workingAgent.Task; + if (task.Tag == tag) + { + workingAgent.Reset(); + m_FreeAgents.Push(workingAgent); + m_WorkingAgents.Remove(currentWorkingAgent); + ReferencePool.Release(task); + count++; + } + + currentWorkingAgent = next; + } + + return count; + } + + /// + /// Ƴ + /// + /// Ƴ + public int RemoveAllTasks() + { + int count = m_WaitingTasks.Count + m_WorkingAgents.Count; + + foreach (T task in m_WaitingTasks) + { + ReferencePool.Release(task); + } + + m_WaitingTasks.Clear(); + + foreach (ITaskAgent workingAgent in m_WorkingAgents) + { + T task = workingAgent.Task; + workingAgent.Reset(); + m_FreeAgents.Push(workingAgent); + ReferencePool.Release(task); + } + + m_WorkingAgents.Clear(); + + return count; + } + + private void ProcessRunningTasks(float elapseSeconds, float realElapseSeconds) + { + LinkedListNode> current = m_WorkingAgents.First; + while (current != null) + { + T task = current.Value.Task; + if (!task.Done) + { + current.Value.Update(elapseSeconds, realElapseSeconds); + current = current.Next; + continue; + } + + LinkedListNode> next = current.Next; + current.Value.Reset(); + m_FreeAgents.Push(current.Value); + m_WorkingAgents.Remove(current); + ReferencePool.Release(task); + current = next; + } + } + + private void ProcessWaitingTasks(float elapseSeconds, float realElapseSeconds) + { + LinkedListNode current = m_WaitingTasks.First; + while (current != null && FreeAgentCount > 0) + { + ITaskAgent agent = m_FreeAgents.Pop(); + LinkedListNode> agentNode = m_WorkingAgents.AddLast(agent); + T task = current.Value; + LinkedListNode next = current.Next; + StartTaskStatus status = agent.Start(task); + if (status == StartTaskStatus.Done || status == StartTaskStatus.HasToWait || status == StartTaskStatus.UnknownError) + { + agent.Reset(); + m_FreeAgents.Push(agent); + m_WorkingAgents.Remove(agentNode); + } + + if (status == StartTaskStatus.Done || status == StartTaskStatus.CanResume || status == StartTaskStatus.UnknownError) + { + m_WaitingTasks.Remove(current); + } + + if (status == StartTaskStatus.Done || status == StartTaskStatus.UnknownError) + { + ReferencePool.Release(task); + } + + current = next; + } + } + } +} diff --git a/Convention/[Runtime]/Convention.TaskPool.cs.meta b/Convention/[Runtime]/Convention.TaskPool.cs.meta new file mode 100644 index 0000000..2121da9 --- /dev/null +++ b/Convention/[Runtime]/Convention.TaskPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4f8c7df8532754c46b224b0cd4d0e171 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Convention/[Runtime]/File.cs b/Convention/[Runtime]/File.cs index 159d108..8c7a76c 100644 --- a/Convention/[Runtime]/File.cs +++ b/Convention/[Runtime]/File.cs @@ -36,7 +36,7 @@ namespace Convention } [Serializable] - public sealed class ToolFile + public class ToolFile { public static string[] TextFileExtensions = new string[] { "txt", "ini", "manifest" }; public static string[] AudioFileExtension = new string[] { "ogg", "mp2", "mp3", "mod", "wav", "it" }; @@ -59,7 +59,7 @@ namespace Convention private string OriginPath; private FileSystemInfo OriginInfo; - public ToolFile(string path) + public ToolFile(string path) { OriginPath = Environment.ExpandEnvironmentVariables(path).Replace('\\', '/'); Refresh(); @@ -219,16 +219,16 @@ namespace Convention { if (IsFile() == false) throw new InvalidOperationException("Target is not a file"); - + var lines = File.ReadAllLines(OriginPath); var result = new List(); - + foreach (var line in lines) { var fields = line.Split(','); result.Add(fields); } - + return result; } @@ -286,7 +286,7 @@ namespace Convention callback(result.assetBundle); yield return null; } - public IEnumerator LoadAsAssetBundle([In]Action progress, [In] Action callback) + public IEnumerator LoadAsAssetBundle([In] Action progress, [In] Action callback) { AssetBundleCreateRequest result = AssetBundle.LoadFromFileAsync(OriginPath); while (result.isDone == false) @@ -314,7 +314,7 @@ namespace Convention } public void SaveAsJson(T data, string key = "data") { - ES3.Save(key, data,OriginPath); + ES3.Save(key, data, OriginPath); } public void SaveAsText(string data) { @@ -323,7 +323,7 @@ namespace Convention sw.Write(data); sw.Flush(); } - public static void SaveDataAsBinary(string path, byte[] outdata, FileStream Stream = null) + public static void SaveDataAsBinary(string path, byte[] outdata, FileStream Stream = null) { if (Stream != null && Stream.CanWrite) { @@ -347,7 +347,7 @@ namespace Convention { if (IsFile() == false) throw new InvalidOperationException("Target is not a file"); - + var lines = csvData.Select(row => string.Join(",", row)); File.WriteAllLines(OriginPath, lines); } @@ -466,7 +466,7 @@ namespace Convention { return new ToolFile(left.IsDir() ? left.GetFullPath() : $"{left.GetFullPath().Replace('\\', '/')}/"); } - string first = left.GetFullPath().Replace('\\','/'); + string first = left.GetFullPath().Replace('\\', '/'); string second = rightPath.Replace('\\', '/'); if (first == "./") return new ToolFile(second); @@ -518,7 +518,7 @@ namespace Convention } public ToolFile Rename(string newPath) { - if(IsDir()) + if (IsDir()) { var dir = OriginInfo as DirectoryInfo; dir.MoveTo(newPath); @@ -536,7 +536,7 @@ namespace Convention Rename(path); return this; } - public ToolFile Copy(string path,out ToolFile copyTo) + public ToolFile Copy(string path, out ToolFile copyTo) { if (IsDir()) { @@ -555,19 +555,19 @@ namespace Convention { if (targetPath == null) return new ToolFile(OriginPath); - + if (!Exists()) throw new FileNotFoundException("File not found"); - + var targetFile = new ToolFile(targetPath); if (targetFile.IsDir()) targetFile = targetFile | GetFilename(); - + if (IsDir()) CopyDirectory(OriginPath, targetFile.GetFullPath()); else File.Copy(OriginPath, targetFile.GetFullPath()); - + return targetFile; } @@ -649,7 +649,7 @@ namespace Convention { if (!IsDir()) throw new InvalidOperationException("Target is not a directory"); - + var entries = Directory.GetFileSystemEntries(OriginPath); if (ignore_folder) { @@ -661,7 +661,7 @@ namespace Convention { if (!IsDir()) throw new InvalidOperationException("Target is not a directory"); - + foreach (var file in DirToolFileIter()) { file.Remove(); @@ -673,13 +673,13 @@ namespace Convention { if (!IsDir()) throw new InvalidOperationException("Cannot make file inside a file, because this object target is not a directory"); - + var result = this | data.GetFilename(); if (is_delete_source) data.Move(result.GetFullPath()); else data.Copy(result.GetFullPath()); - + return this; } @@ -947,7 +947,7 @@ namespace Convention public ToolFile SaveHash(string algorithm = "MD5", string outputPath = null) { string hash = CalculateHash(algorithm); - + if (outputPath == null) { outputPath = GetFullPath() + "." + algorithm.ToLower(); @@ -955,7 +955,7 @@ namespace Convention var hashFile = new ToolFile(outputPath); hashFile.SaveAsText(hash); - + return hashFile; } @@ -963,8 +963,8 @@ namespace Convention #region File Monitoring - public void StartMonitoring(Action callback, bool recursive = false, - List ignorePatterns = null, bool ignoreDirectories = false, + public void StartMonitoring(Action callback, bool recursive = false, + List ignorePatterns = null, bool ignoreDirectories = false, bool caseSensitive = true, bool isLog = true) { if (!IsDir()) @@ -988,7 +988,7 @@ namespace Convention #region Backup - public ToolFile CreateBackup(string backupDir = null, int maxBackups = 5, + public ToolFile CreateBackup(string backupDir = null, int maxBackups = 5, string backupFormat = "zip", bool includeMetadata = true) { if (!Exists()) @@ -1101,7 +1101,7 @@ namespace Convention throw new FileNotFoundException($"File not found: {GetFullPath()}"); var permissions = new Dictionary(); - + try { var fileInfo = new FileInfo(OriginPath); @@ -1123,7 +1123,7 @@ namespace Convention return permissions; } - public ToolFile SetPermissions(bool? read = null, bool? write = null, + public ToolFile SetPermissions(bool? read = null, bool? write = null, bool? execute = null, bool? hidden = null, bool recursive = false) { if (!Exists()) @@ -1233,15 +1233,15 @@ namespace Convention } public static string[] SelectMultipleFiles(string filter = "所有文件|*.*", string title = "选择文件") { - return PluginExtenion.SelectMultipleFiles(filter,title); + return PluginExtenion.SelectMultipleFiles(filter, title); } public static string SelectFile(string filter = "所有文件|*.*", string title = "选择文件") { - return PluginExtenion.SelectFile(filter,title); + return PluginExtenion.SelectFile(filter, title); } public static string SaveFile(string filter = "所有文件|*.*", string title = "保存文件") { - return PluginExtenion.SaveFile(filter,title); + return PluginExtenion.SaveFile(filter, title); } public static string SelectFolder(string description = "请选择文件夹") { @@ -1264,4 +1264,23 @@ namespace Convention #endregion } + + [Serializable] + public class MustExistFile : ToolFile + { + public MustExistFile(string path) : base(path) + { + MustExistsPath(); + } + } + + [Serializable] + public class DependentFile : ToolFile + { + public DependentFile(string path) : base(path) + { + if (Exists() == false) + throw new FileNotFoundException($"Dependent file not found: {path}"); + } + } }