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}");
+ }
+ }
}