diff --git a/Editor/ObjectPool/ObjectPoolComponentInspector.cs b/Editor/ObjectPool/ObjectPoolComponentInspector.cs index 23cd7c6..fa2d75c 100644 --- a/Editor/ObjectPool/ObjectPoolComponentInspector.cs +++ b/Editor/ObjectPool/ObjectPoolComponentInspector.cs @@ -67,26 +67,27 @@ namespace AlicizaX.Editor EditorGUILayout.LabelField("Auto Release Interval", objectPool.AutoReleaseInterval.ToString()); EditorGUILayout.LabelField("Capacity", objectPool.Capacity.ToString()); EditorGUILayout.LabelField("Used Count", objectPool.Count.ToString()); - EditorGUILayout.LabelField("Can Release Count", objectPool.CanReleaseCount.ToString()); EditorGUILayout.LabelField("Expire Time", objectPool.ExpireTime.ToString()); EditorGUILayout.LabelField("Priority", objectPool.Priority.ToString()); ObjectInfo[] objectInfos = objectPool.GetAllObjectInfos(); if (objectInfos.Length > 0) { - EditorGUILayout.LabelField("Name", objectPool.AllowMultiSpawn ? "Locked\tCount\tFlag\tPriority\tLast Use Time" : "Locked\tIn Use\tFlag\tPriority\tLast Use Time"); + EditorGUILayout.LabelField("Name", objectPool.AllowMultiSpawn ? "Locked\tCount\tFlag\tLast Use Time" : "Locked\tIn Use\tFlag\tLast Use Time"); foreach (ObjectInfo objectInfo in objectInfos) { #if UNITY_6000_0_OR_NEWER + string lastUse = Utility.Text.Format("{0:F1}s ago", UnityEngine.Time.realtimeSinceStartup - objectInfo.LastUseTime); EditorGUILayout.LabelField(string.IsNullOrEmpty(objectInfo.Name) ? "" : objectInfo.Name, objectPool.AllowMultiSpawn - ? Utility.Text.Format("{0,-12}\t{1,-12}\t{2,-12}\t{3,-12}\t{4:yyyy-MM-dd HH:mm:ss,-12}", objectInfo.Locked, objectInfo.SpawnCount, objectInfo.CustomCanReleaseFlag, objectInfo.Priority, objectInfo.LastUseTime.ToLocalTime()) - : Utility.Text.Format("{0,-12}\t{1,-12}\t{2,-12}\t{3,-12}\t{4:yyyy-MM-dd HH:mm:ss,-12}", objectInfo.Locked, objectInfo.IsInUse, objectInfo.CustomCanReleaseFlag, objectInfo.Priority, objectInfo.LastUseTime.ToLocalTime())); + ? Utility.Text.Format("{0,-12}\t{1,-12}\t{2,-12}\t{3,-12}", objectInfo.Locked, objectInfo.SpawnCount, objectInfo.CustomCanReleaseFlag, lastUse) + : Utility.Text.Format("{0,-12}\t{1,-12}\t{2,-12}\t{3,-12}", objectInfo.Locked, objectInfo.IsInUse, objectInfo.CustomCanReleaseFlag, lastUse)); #else - EditorGUILayout.LabelField(string.IsNullOrEmpty(objectInfo.Name) ? "" : objectInfo.Name, + string lastUse = Utility.Text.Format("{0:F1}s ago", UnityEngine.Time.realtimeSinceStartup - objectInfo.LastUseTime); + EditorGUILayout.LabelField(string.IsNullOrEmpty(objectInfo.Name) ? "" : objectInfo.Name, objectPool.AllowMultiSpawn - ? Utility.Text.Format("{0}\t{1}\t{2}\t{3}\t{4:yyyy-MM-dd HH:mm:ss}", objectInfo.Locked, objectInfo.SpawnCount, objectInfo.CustomCanReleaseFlag, objectInfo.Priority, objectInfo.LastUseTime.ToLocalTime()) - : Utility.Text.Format("{0}\t{1}\t{2}\t{3}\t{4:yyyy-MM-dd HH:mm:ss}", objectInfo.Locked, objectInfo.IsInUse, objectInfo.CustomCanReleaseFlag, objectInfo.Priority, objectInfo.LastUseTime.ToLocalTime())); + ? Utility.Text.Format("{0}\t{1}\t{2}\t{3}", objectInfo.Locked, objectInfo.SpawnCount, objectInfo.CustomCanReleaseFlag, lastUse) + : Utility.Text.Format("{0}\t{1}\t{2}\t{3}", objectInfo.Locked, objectInfo.IsInUse, objectInfo.CustomCanReleaseFlag, lastUse)); #endif } @@ -109,12 +110,13 @@ namespace AlicizaX.Editor { int index = 0; string[] data = new string[objectInfos.Length + 1]; - data[index++] = Utility.Text.Format("Name,Locked,{0},Custom Can Release Flag,Priority,Last Use Time", objectPool.AllowMultiSpawn ? "Count" : "In Use"); + data[index++] = Utility.Text.Format("Name,Locked,{0},Custom Can Release Flag,Last Use Time", objectPool.AllowMultiSpawn ? "Count" : "In Use"); foreach (ObjectInfo objectInfo in objectInfos) { + string csvLastUse = Utility.Text.Format("{0:F1}s ago", UnityEngine.Time.realtimeSinceStartup - objectInfo.LastUseTime); data[index++] = objectPool.AllowMultiSpawn - ? Utility.Text.Format("{0},{1},{2},{3},{4},{5:yyyy-MM-dd HH:mm:ss}", objectInfo.Name, objectInfo.Locked, objectInfo.SpawnCount, objectInfo.CustomCanReleaseFlag, objectInfo.Priority, objectInfo.LastUseTime.ToLocalTime()) - : Utility.Text.Format("{0},{1},{2},{3},{4},{5:yyyy-MM-dd HH:mm:ss}", objectInfo.Name, objectInfo.Locked, objectInfo.IsInUse, objectInfo.CustomCanReleaseFlag, objectInfo.Priority, objectInfo.LastUseTime.ToLocalTime()); + ? Utility.Text.Format("{0},{1},{2},{3},{4}", objectInfo.Name, objectInfo.Locked, objectInfo.SpawnCount, objectInfo.CustomCanReleaseFlag, csvLastUse) + : Utility.Text.Format("{0},{1},{2},{3},{4}", objectInfo.Name, objectInfo.Locked, objectInfo.IsInUse, objectInfo.CustomCanReleaseFlag, csvLastUse); } File.WriteAllLines(exportFileName, data, Encoding.UTF8); diff --git a/Runtime/ABase/DataStruct/GameFrameworkLinkedList.cs b/Runtime/ABase/DataStruct/GameFrameworkLinkedList.cs deleted file mode 100644 index 97bdf9a..0000000 --- a/Runtime/ABase/DataStruct/GameFrameworkLinkedList.cs +++ /dev/null @@ -1,456 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace AlicizaX -{ - /// - /// 游戏框架链表类。 - /// - /// 指定链表的元素类型。 - public sealed class GameFrameworkLinkedList : ICollection, IEnumerable, ICollection, IEnumerable - { - private readonly LinkedList m_LinkedList; - private readonly Queue> m_CachedNodes; - - /// - /// 初始化游戏框架链表类的新实例。 - /// - public GameFrameworkLinkedList() - { - 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); - } - - /// - /// 确定指定结点是否在链表中。 - /// - /// 要检查的结点。 - /// 指定结点是否在链表中。 - public bool Contains(LinkedListNode node) - { - return node != null && node.List == m_LinkedList; - } - - /// - /// 从目标数组的指定索引处开始将整个链表复制到兼容的一维数组。 - /// - /// 一维数组,它是从链表复制的元素的目标。数组必须具有从零开始的索引。 - /// 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 GameFrameworkException("First is invalid."); - } - - m_LinkedList.RemoveFirst(); - ReleaseNode(first); - } - - /// - /// 移除位于链表结尾处的结点。 - /// - public void RemoveLast() - { - LinkedListNode last = m_LinkedList.Last; - if (last == null) - { - throw new GameFrameworkException("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 GameFrameworkException("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/Runtime/ABase/DataStruct/GameFrameworkLinkedList.cs.meta b/Runtime/ABase/DataStruct/GameFrameworkLinkedList.cs.meta deleted file mode 100644 index d89ec26..0000000 --- a/Runtime/ABase/DataStruct/GameFrameworkLinkedList.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8662d2b0651bb46308fa9ea5a24a9f08 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/ABase/DataStruct/GameFrameworkLinkedListRange.cs b/Runtime/ABase/DataStruct/GameFrameworkLinkedListRange.cs deleted file mode 100644 index 4799dbf..0000000 --- a/Runtime/ABase/DataStruct/GameFrameworkLinkedListRange.cs +++ /dev/null @@ -1,210 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace AlicizaX -{ - /// - /// 游戏框架链表范围。 - /// - /// 指定链表范围的元素类型。 - [StructLayout(LayoutKind.Auto)] - public readonly struct GameFrameworkLinkedListRange : IEnumerable, IEnumerable - { - private readonly LinkedListNode m_First; - private readonly LinkedListNode m_Terminal; - - /// - /// 初始化游戏框架链表范围的新实例。 - /// - /// 链表范围的开始结点。 - /// 链表范围的终结标记结点。 - public GameFrameworkLinkedListRange(LinkedListNode first, LinkedListNode terminal) - { - if (first == null || terminal == null || first == terminal) - { - throw new GameFrameworkException("Range is invalid."); - } - - m_First = first; - m_Terminal = terminal; - } - - /// - /// 获取链表范围是否有效。 - /// - public bool IsValid - { - get - { - return m_First != null && m_Terminal != null && m_First != m_Terminal; - } - } - - /// - /// 获取链表范围的开始结点。 - /// - public LinkedListNode First - { - get - { - return m_First; - } - } - - /// - /// 获取链表范围的终结标记结点。 - /// - public LinkedListNode Terminal - { - get - { - return m_Terminal; - } - } - - /// - /// 获取链表范围的结点数量。 - /// - public int Count - { - get - { - if (!IsValid) - { - return 0; - } - - int count = 0; - for (LinkedListNode current = m_First; current != null && current != m_Terminal; current = current.Next) - { - count++; - } - - return count; - } - } - - /// - /// 检查是否包含指定值。 - /// - /// 要检查的值。 - /// 是否包含指定值。 - public bool Contains(T value) - { - for (LinkedListNode current = m_First; current != null && current != m_Terminal; current = current.Next) - { - if (current.Value.Equals(value)) - { - return true; - } - } - - return false; - } - - /// - /// 返回循环访问集合的枚举数。 - /// - /// 循环访问集合的枚举数。 - public Enumerator GetEnumerator() - { - return new Enumerator(this); - } - - /// - /// 返回循环访问集合的枚举数。 - /// - /// 循环访问集合的枚举数。 - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - /// 返回循环访问集合的枚举数。 - /// - /// 循环访问集合的枚举数。 - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - /// 循环访问集合的枚举数。 - /// - [StructLayout(LayoutKind.Auto)] - public struct Enumerator : IEnumerator, IEnumerator - { - private readonly GameFrameworkLinkedListRange m_GameFrameworkLinkedListRange; - private LinkedListNode m_Current; - private T m_CurrentValue; - - internal Enumerator(GameFrameworkLinkedListRange range) - { - if (!range.IsValid) - { - throw new GameFrameworkException("Range is invalid."); - } - - m_GameFrameworkLinkedListRange = range; - m_Current = m_GameFrameworkLinkedListRange.m_First; - m_CurrentValue = default(T); - } - - /// - /// 获取当前结点。 - /// - public T Current - { - get - { - return m_CurrentValue; - } - } - - /// - /// 获取当前的枚举数。 - /// - object IEnumerator.Current - { - get - { - return m_CurrentValue; - } - } - - /// - /// 清理枚举数。 - /// - public void Dispose() - { - } - - /// - /// 获取下一个结点。 - /// - /// 返回下一个结点。 - public bool MoveNext() - { - if (m_Current == null || m_Current == m_GameFrameworkLinkedListRange.m_Terminal) - { - return false; - } - - m_CurrentValue = m_Current.Value; - m_Current = m_Current.Next; - return true; - } - - /// - /// 重置枚举数。 - /// - void IEnumerator.Reset() - { - m_Current = m_GameFrameworkLinkedListRange.m_First; - m_CurrentValue = default(T); - } - } - } -} diff --git a/Runtime/ABase/DataStruct/GameFrameworkLinkedListRange.cs.meta b/Runtime/ABase/DataStruct/GameFrameworkLinkedListRange.cs.meta deleted file mode 100644 index 72d94f7..0000000 --- a/Runtime/ABase/DataStruct/GameFrameworkLinkedListRange.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 7edbebe0b1fd848418e2f1d863b611e1 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/ABase/DataStruct/GameFrameworkMultiDictionary.cs b/Runtime/ABase/DataStruct/GameFrameworkMultiDictionary.cs deleted file mode 100644 index 081fa01..0000000 --- a/Runtime/ABase/DataStruct/GameFrameworkMultiDictionary.cs +++ /dev/null @@ -1,304 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace AlicizaX -{ - /// - /// 游戏框架多值字典类。 - /// - /// 指定多值字典的主键类型。 - /// 指定多值字典的值类型。 - public sealed class GameFrameworkMultiDictionary : IEnumerable>>, IEnumerable - { - private readonly GameFrameworkLinkedList m_LinkedList; - private readonly Dictionary> m_Dictionary; - - /// - /// 初始化游戏框架多值字典类的新实例。 - /// - public GameFrameworkMultiDictionary() - { - m_LinkedList = new GameFrameworkLinkedList(); - m_Dictionary = new Dictionary>(); - } - - /// - /// 获取多值字典中实际包含的主键数量。 - /// - public int Count - { - get - { - return m_Dictionary.Count; - } - } - - /// - /// 获取多值字典中指定主键的范围。 - /// - /// 指定的主键。 - /// 指定主键的范围。 - public GameFrameworkLinkedListRange this[TKey key] - { - get - { - GameFrameworkLinkedListRange range = default(GameFrameworkLinkedListRange); - m_Dictionary.TryGetValue(key, out range); - return range; - } - } - - /// - /// 清理多值字典。 - /// - public void Clear() - { - m_Dictionary.Clear(); - m_LinkedList.Clear(); - } - - /// - /// 检查多值字典中是否包含指定主键。 - /// - /// 要检查的主键。 - /// 多值字典中是否包含指定主键。 - public bool Contains(TKey key) - { - return m_Dictionary.ContainsKey(key); - } - - /// - /// 检查多值字典中是否包含指定值。 - /// - /// 要检查的主键。 - /// 要检查的值。 - /// 多值字典中是否包含指定值。 - public bool Contains(TKey key, TValue value) - { - GameFrameworkLinkedListRange range = default(GameFrameworkLinkedListRange); - if (m_Dictionary.TryGetValue(key, out range)) - { - return range.Contains(value); - } - - return false; - } - - /// - /// 尝试获取多值字典中指定主键的范围。 - /// - /// 指定的主键。 - /// 指定主键的范围。 - /// 是否获取成功。 - public bool TryGetValue(TKey key, out GameFrameworkLinkedListRange range) - { - return m_Dictionary.TryGetValue(key, out range); - } - - /// - /// 向指定的主键增加指定的值。 - /// - /// 指定的主键。 - /// 指定的值。 - public LinkedListNode Add(TKey key, TValue value) - { - GameFrameworkLinkedListRange range = default(GameFrameworkLinkedListRange); - if (m_Dictionary.TryGetValue(key, out range)) - { - return m_LinkedList.AddBefore(range.Terminal, value); - } - else - { - LinkedListNode first = m_LinkedList.AddLast(value); - LinkedListNode terminal = m_LinkedList.AddLast(default(TValue)); - m_Dictionary.Add(key, new GameFrameworkLinkedListRange(first, terminal)); - return first; - } - } - - /// - /// 从指定的主键中移除指定的值。 - /// - /// 指定的主键。 - /// 指定的值。 - /// 是否移除成功。 - public bool Remove(TKey key, TValue value) - { - GameFrameworkLinkedListRange range = default(GameFrameworkLinkedListRange); - if (m_Dictionary.TryGetValue(key, out range)) - { - for (LinkedListNode current = range.First; current != null && current != range.Terminal; current = current.Next) - { - if (current.Value.Equals(value)) - { - return Remove(key, current); - } - } - } - - return false; - } - - /// - /// 从指定的主键中移除指定结点。 - /// - /// 指定的主键。 - /// 要移除的结点。 - /// 是否移除成功。 - public bool Remove(TKey key, LinkedListNode node) - { - if (node == null) - { - return false; - } - - GameFrameworkLinkedListRange range = default(GameFrameworkLinkedListRange); - if (!m_Dictionary.TryGetValue(key, out range)) - { - return false; - } - - if (!m_LinkedList.Contains(node) || node == range.Terminal) - { - return false; - } - - if (node == range.First) - { - LinkedListNode next = node.Next; - if (next == range.Terminal) - { - m_LinkedList.Remove(next); - m_Dictionary.Remove(key); - } - else - { - m_Dictionary[key] = new GameFrameworkLinkedListRange(next, range.Terminal); - } - } - - m_LinkedList.Remove(node); - return true; - } - - /// - /// 从指定的主键中移除所有的值。 - /// - /// 指定的主键。 - /// 是否移除成功。 - public bool RemoveAll(TKey key) - { - GameFrameworkLinkedListRange range = default(GameFrameworkLinkedListRange); - if (m_Dictionary.TryGetValue(key, out range)) - { - m_Dictionary.Remove(key); - - LinkedListNode current = range.First; - while (current != null) - { - LinkedListNode next = current != range.Terminal ? current.Next : null; - m_LinkedList.Remove(current); - current = next; - } - - return true; - } - - return false; - } - - /// - /// 返回循环访问集合的枚举数。 - /// - /// 循环访问集合的枚举数。 - public Enumerator GetEnumerator() - { - return new Enumerator(m_Dictionary); - } - - /// - /// 返回循环访问集合的枚举数。 - /// - /// 循环访问集合的枚举数。 - IEnumerator>> IEnumerable>>.GetEnumerator() - { - return GetEnumerator(); - } - - /// - /// 返回循环访问集合的枚举数。 - /// - /// 循环访问集合的枚举数。 - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - /// 循环访问集合的枚举数。 - /// - [StructLayout(LayoutKind.Auto)] - public struct Enumerator : IEnumerator>>, IEnumerator - { - private Dictionary>.Enumerator m_Enumerator; - - internal Enumerator(Dictionary> dictionary) - { - if (dictionary == null) - { - throw new GameFrameworkException("Dictionary is invalid."); - } - - m_Enumerator = dictionary.GetEnumerator(); - } - - /// - /// 获取当前结点。 - /// - public KeyValuePair> 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/Runtime/ABase/DataStruct/GameFrameworkSerializer.cs b/Runtime/ABase/DataStruct/GameFrameworkSerializer.cs deleted file mode 100644 index 54c79b7..0000000 --- a/Runtime/ABase/DataStruct/GameFrameworkSerializer.cs +++ /dev/null @@ -1,199 +0,0 @@ -using System.Collections.Generic; -using System.IO; - -namespace AlicizaX -{ - /// - /// 游戏框架序列化器基类。 - /// - /// 要序列化的数据类型。 - public abstract class GameFrameworkSerializer - { - private readonly Dictionary _serializeCallbacks; - private readonly Dictionary _deserializeCallbacks; - private readonly Dictionary _tryGetValueCallbacks; - private byte _latestSerializeCallbackVersion; - - /// - /// 初始化游戏框架序列化器基类的新实例。 - /// - [UnityEngine.Scripting.Preserve] - public GameFrameworkSerializer() - { - _serializeCallbacks = new Dictionary(); - _deserializeCallbacks = new Dictionary(); - _tryGetValueCallbacks = new Dictionary(); - _latestSerializeCallbackVersion = 0; - } - - /// - /// 序列化回调函数。 - /// - /// 目标流。 - /// 要序列化的数据。 - /// 是否序列化数据成功。 - public delegate bool SerializeCallback(Stream stream, T data); - - /// - /// 反序列化回调函数。 - /// - /// 指定流。 - /// 反序列化的数据。 - public delegate T DeserializeCallback(Stream stream); - - /// - /// 尝试从指定流获取指定键的值回调函数。 - /// - /// 指定流。 - /// 指定键。 - /// 指定键的值。 - /// 是否从指定流获取指定键的值成功。 - public delegate bool TryGetValueCallback(Stream stream, string key, out object value); - - /// - /// 注册序列化回调函数。 - /// - /// 序列化回调函数的版本。 - /// 序列化回调函数。 - public void RegisterSerializeCallback(byte version, SerializeCallback callback) - { - if (callback == null) - { - throw new GameFrameworkException("Serialize callback is invalid."); - } - - _serializeCallbacks[version] = callback; - if (version > _latestSerializeCallbackVersion) - { - _latestSerializeCallbackVersion = version; - } - } - - /// - /// 注册反序列化回调函数。 - /// - /// 反序列化回调函数的版本。 - /// 反序列化回调函数。 - public void RegisterDeserializeCallback(byte version, DeserializeCallback callback) - { - if (callback == null) - { - throw new GameFrameworkException("Deserialize callback is invalid."); - } - - _deserializeCallbacks[version] = callback; - } - - /// - /// 注册尝试从指定流获取指定键的值回调函数。 - /// - /// 尝试从指定流获取指定键的值回调函数的版本。 - /// 尝试从指定流获取指定键的值回调函数。 - public void RegisterTryGetValueCallback(byte version, TryGetValueCallback callback) - { - if (callback == null) - { - throw new GameFrameworkException("Try get value callback is invalid."); - } - - _tryGetValueCallbacks[version] = callback; - } - - /// - /// 序列化数据到目标流中。 - /// - /// 目标流。 - /// 要序列化的数据。 - /// 是否序列化数据成功。 - public bool Serialize(Stream stream, T data) - { - if (_serializeCallbacks.Count <= 0) - { - throw new GameFrameworkException("No serialize callback registered."); - } - - return Serialize(stream, data, _latestSerializeCallbackVersion); - } - - /// - /// 序列化数据到目标流中。 - /// - /// 目标流。 - /// 要序列化的数据。 - /// 序列化回调函数的版本。 - /// 是否序列化数据成功。 - public bool Serialize(Stream stream, T data, byte version) - { - byte[] header = GetHeader(); - stream.WriteByte(header[0]); - stream.WriteByte(header[1]); - stream.WriteByte(header[2]); - stream.WriteByte(version); - if (!_serializeCallbacks.TryGetValue(version, out var callback)) - { - throw new GameFrameworkException(Utility.Text.Format("Serialize callback '{0}' is not exist.", version)); - } - - return callback(stream, data); - } - - /// - /// 从指定流反序列化数据。 - /// - /// 指定流。 - /// 反序列化的数据。 - public T Deserialize(Stream stream) - { - byte[] header = GetHeader(); - byte header0 = (byte)stream.ReadByte(); - byte header1 = (byte)stream.ReadByte(); - byte header2 = (byte)stream.ReadByte(); - if (header0 != header[0] || header1 != header[1] || header2 != header[2]) - { - throw new GameFrameworkException(Utility.Text.Format("Header is invalid, need '{0}{1}{2}', current '{3}{4}{5}'.", (char)header[0], (char)header[1], (char)header[2], (char)header0, (char)header1, (char)header2)); - } - - byte version = (byte)stream.ReadByte(); - if (!_deserializeCallbacks.TryGetValue(version, out var callback)) - { - throw new GameFrameworkException(Utility.Text.Format("Deserialize callback '{0}' is not exist.", version)); - } - - return callback(stream); - } - - /// - /// 尝试从指定流获取指定键的值。 - /// - /// 指定流。 - /// 指定键。 - /// 指定键的值。 - /// 是否从指定流获取指定键的值成功。 - public bool TryGetValue(Stream stream, string key, out object value) - { - value = null; - byte[] header = GetHeader(); - byte header0 = (byte)stream.ReadByte(); - byte header1 = (byte)stream.ReadByte(); - byte header2 = (byte)stream.ReadByte(); - if (header0 != header[0] || header1 != header[1] || header2 != header[2]) - { - return false; - } - - byte version = (byte)stream.ReadByte(); - if (!_tryGetValueCallbacks.TryGetValue(version, out var callback)) - { - return false; - } - - return callback(stream, key, out value); - } - - /// - /// 获取数据头标识。 - /// - /// 数据头标识。 - protected abstract byte[] GetHeader(); - } -} diff --git a/Runtime/ABase/DataStruct/GameFrameworkSerializer.cs.meta b/Runtime/ABase/DataStruct/GameFrameworkSerializer.cs.meta deleted file mode 100644 index 68af999..0000000 --- a/Runtime/ABase/DataStruct/GameFrameworkSerializer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2c8469a7db4474e1da10e383bc09e77f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/ABase/MemoryPool/MemoryPoolRegistry.cs b/Runtime/ABase/MemoryPool/MemoryPoolRegistry.cs index 97568ad..935b7c1 100644 --- a/Runtime/ABase/MemoryPool/MemoryPoolRegistry.cs +++ b/Runtime/ABase/MemoryPool/MemoryPoolRegistry.cs @@ -39,7 +39,6 @@ namespace AlicizaX private static readonly Dictionary s_Handles = new Dictionary(64); - // Tick 回调用数组缓存,避免每帧遍历 Dictionary private static Action[] s_TickArray = Array.Empty>(); private static int s_TickCount; private static bool s_TickArrayDirty; diff --git a/Runtime/ABase/ObjectPool/IObjectPool.cs b/Runtime/ABase/ObjectPool/IObjectPool.cs index e44fbdc..7bcbbdf 100644 --- a/Runtime/ABase/ObjectPool/IObjectPool.cs +++ b/Runtime/ABase/ObjectPool/IObjectPool.cs @@ -1,181 +1,28 @@ -using System; +using System; namespace AlicizaX.ObjectPool { - public interface IObjectPool + public interface IObjectPool where T : ObjectBase { - } - - /// - /// 对象池接口。 - /// - /// 对象类型。 - public interface IObjectPool : IObjectPool where T : ObjectBase - { - /// - /// 获取对象池名称。 - /// string Name { get; } - - /// - /// 获取对象池完整名称。 - /// string FullName { get; } - - /// - /// 获取对象池对象类型。 - /// Type ObjectType { get; } - - /// - /// 获取对象池中对象的数量。 - /// int Count { get; } - - /// - /// 获取对象池中能被释放的对象的数量。 - /// - int CanReleaseCount { get; } - - /// - /// 获取是否允许对象被多次获取。 - /// bool AllowMultiSpawn { get; } - - /// - /// 获取或设置对象池自动释放可释放对象的间隔秒数。 - /// float AutoReleaseInterval { get; set; } - - /// - /// 获取或设置对象池的容量。 - /// int Capacity { get; set; } - - /// - /// 获取或设置对象池对象过期秒数。 - /// float ExpireTime { get; set; } - - /// - /// 获取或设置对象池的优先级。 - /// int Priority { get; set; } - /// - /// 创建对象。 - /// - /// 对象。 - /// 对象是否已被获取。 void Register(T obj, bool spawned); - - /// - /// 检查对象。 - /// - /// 要检查的对象是否存在。 bool CanSpawn(); - - /// - /// 检查对象。 - /// - /// 对象名称。 - /// 要检查的对象是否存在。 bool CanSpawn(string name); - - /// - /// 获取对象。 - /// - /// 要获取的对象。 T Spawn(); - - /// - /// 获取对象。 - /// - /// 对象名称。 - /// 要获取的对象。 T Spawn(string name); - - /// - /// 回收对象。 - /// - /// 要回收的对象。 void Unspawn(T obj); - - /// - /// 回收对象。 - /// - /// 要回收的对象。 void Unspawn(object target); - - /// - /// 设置对象是否被加锁。 - /// - /// 要设置被加锁的对象。 - /// 是否被加锁。 - void SetLocked(T obj, bool locked); - - /// - /// 设置对象是否被加锁。 - /// - /// 要设置被加锁的对象。 - /// 是否被加锁。 - void SetLocked(object target, bool locked); - - /// - /// 设置对象的优先级。 - /// - /// 要设置优先级的对象。 - /// 优先级。 - void SetPriority(T obj, int priority); - - /// - /// 设置对象的优先级。 - /// - /// 要设置优先级的对象。 - /// 优先级。 - void SetPriority(object target, int priority); - - /// - /// 释放对象。 - /// - /// 要释放的对象。 - /// 释放对象是否成功。 - bool ReleaseObject(T obj); - - /// - /// 释放对象。 - /// - /// 要释放的对象。 - /// 释放对象是否成功。 - bool ReleaseObject(object target); - - /// - /// 释放对象池中的可释放对象。 - /// void Release(); - - /// - /// 释放对象池中的可释放对象。 - /// - /// 尝试释放对象数量。 void Release(int toReleaseCount); - - /// - /// 释放对象池中的可释放对象。 - /// - /// 释放对象筛选函数。 - void Release(ReleaseObjectFilterCallback releaseObjectFilterCallback); - - /// - /// 释放对象池中的可释放对象。 - /// - /// 尝试释放对象数量。 - /// 释放对象筛选函数。 - void Release(int toReleaseCount, ReleaseObjectFilterCallback releaseObjectFilterCallback); - - /// - /// 释放对象池中的所有未使用对象。 - /// void ReleaseAllUnused(); } } diff --git a/Runtime/ABase/ObjectPool/IObjectPoolService.cs b/Runtime/ABase/ObjectPool/IObjectPoolService.cs index a00b635..5453732 100644 --- a/Runtime/ABase/ObjectPool/IObjectPoolService.cs +++ b/Runtime/ABase/ObjectPool/IObjectPoolService.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using AlicizaX; namespace AlicizaX.ObjectPool { @@ -8,17 +7,17 @@ namespace AlicizaX.ObjectPool { public readonly string Name; public readonly bool AllowMultiSpawn; - public readonly float AutoReleaseInterval; - public readonly int Capacity; - public readonly float ExpireTime; + public readonly float? AutoReleaseInterval; + public readonly int? Capacity; + public readonly float? ExpireTime; public readonly int Priority; public ObjectPoolCreateOptions( string name = "", bool allowMultiSpawn = false, - float autoReleaseInterval = float.MaxValue, - int capacity = int.MaxValue, - float expireTime = float.MaxValue, + float? autoReleaseInterval = null, + int? capacity = null, + float? expireTime = null, int priority = 0) { Name = name ?? string.Empty; @@ -39,37 +38,32 @@ namespace AlicizaX.ObjectPool => new ObjectPoolCreateOptions(name: name, allowMultiSpawn: true); } - /// - /// 对象池管理器。 - /// + public interface IObjectPoolService : IService { int Count { get; } bool HasObjectPool() where T : ObjectBase; - bool HasObjectPool(Type objectType); bool HasObjectPool(string name) where T : ObjectBase; + bool HasObjectPool(Type objectType); bool HasObjectPool(Type objectType, string name); - bool HasObjectPool(Predicate condition); IObjectPool GetObjectPool() where T : ObjectBase; - ObjectPoolBase GetObjectPool(Type objectType); IObjectPool GetObjectPool(string name) where T : ObjectBase; + ObjectPoolBase GetObjectPool(Type objectType); ObjectPoolBase GetObjectPool(Type objectType, string name); - ObjectPoolBase GetObjectPool(Predicate condition); - ObjectPoolBase[] GetObjectPools(Predicate condition); - void GetObjectPools(Predicate condition, List results); + ObjectPoolBase[] GetAllObjectPools(); - void GetAllObjectPools(List results); ObjectPoolBase[] GetAllObjectPools(bool sort); + void GetAllObjectPools(List results); void GetAllObjectPools(bool sort, List results); IObjectPool CreatePool(ObjectPoolCreateOptions options = default) where T : ObjectBase; ObjectPoolBase CreatePool(Type objectType, ObjectPoolCreateOptions options = default); bool DestroyObjectPool() where T : ObjectBase; - bool DestroyObjectPool(Type objectType); bool DestroyObjectPool(string name) where T : ObjectBase; + bool DestroyObjectPool(Type objectType); bool DestroyObjectPool(Type objectType, string name); bool DestroyObjectPool(IObjectPool objectPool) where T : ObjectBase; bool DestroyObjectPool(ObjectPoolBase objectPool); diff --git a/Runtime/ABase/ObjectPool/IntOpenHashMap.cs b/Runtime/ABase/ObjectPool/IntOpenHashMap.cs new file mode 100644 index 0000000..0bfce09 --- /dev/null +++ b/Runtime/ABase/ObjectPool/IntOpenHashMap.cs @@ -0,0 +1,170 @@ +using System; +using System.Runtime.CompilerServices; + +namespace AlicizaX.ObjectPool +{ + + internal struct IntOpenHashMap + { + private int[] m_Buckets; + private int[] m_Keys; + private int[] m_Values; + private int[] m_Next; + private int m_Count; + private int m_FreeList; + private int m_Mask; + private int m_AllocCount; + + private const int MinCapacity = 8; + + public int Count => m_Count; + + public IntOpenHashMap(int capacity) + { + int cap = NextPowerOf2(Math.Max(capacity, MinCapacity)); + m_Mask = cap - 1; + m_Buckets = new int[cap]; + m_Keys = new int[cap]; + m_Values = new int[cap]; + m_Next = new int[cap]; + m_Count = 0; + m_FreeList = 0; + m_AllocCount = 0; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(int key, out int value) + { + if (m_Buckets == null) { value = -1; return false; } + int i = m_Buckets[(key & 0x7FFFFFFF) & m_Mask]; + while (i > 0) + { + int idx = i - 1; + if (m_Keys[idx] == key) { value = m_Values[idx]; return true; } + i = m_Next[idx]; + } + value = -1; + return false; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddOrUpdate(int key, int value) + { + if (m_Count >= ((m_Mask + 1) * 3 >> 2)) + Grow(); + + int bucket = (key & 0x7FFFFFFF) & m_Mask; + int i = m_Buckets[bucket]; + while (i > 0) + { + int ei = i - 1; + if (m_Keys[ei] == key) { m_Values[ei] = value; return; } + i = m_Next[ei]; + } + + int idx; + if (m_FreeList > 0) + { + idx = m_FreeList - 1; + m_FreeList = m_Next[idx]; + } + else + { + if (m_AllocCount > m_Mask) { Grow(); bucket = (key & 0x7FFFFFFF) & m_Mask; } + idx = m_AllocCount++; + } + + m_Keys[idx] = key; + m_Values[idx] = value; + m_Next[idx] = m_Buckets[bucket]; + m_Buckets[bucket] = idx + 1; + m_Count++; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Remove(int key) + { + if (m_Buckets == null) return false; + int bucket = (key & 0x7FFFFFFF) & m_Mask; + int prev = 0; + int i = m_Buckets[bucket]; + while (i > 0) + { + int idx = i - 1; + if (m_Keys[idx] == key) + { + if (prev == 0) m_Buckets[bucket] = m_Next[idx]; + else m_Next[prev - 1] = m_Next[idx]; + m_Keys[idx] = 0; + m_Values[idx] = -1; + m_Next[idx] = m_FreeList; + m_FreeList = idx + 1; + m_Count--; + return true; + } + prev = i; + i = m_Next[idx]; + } + return false; + } + + public void Clear() + { + if (m_Buckets == null) return; + int cap = m_Mask + 1; + Array.Clear(m_Buckets, 0, cap); + Array.Clear(m_Keys, 0, cap); + Array.Clear(m_Values, 0, cap); + Array.Clear(m_Next, 0, cap); + m_Count = 0; + m_FreeList = 0; + m_AllocCount = 0; + } + + private void Grow() + { + int newCap = (m_Mask + 1) << 1; + if (newCap < MinCapacity) newCap = MinCapacity; + int newMask = newCap - 1; + var newBuckets = new int[newCap]; + var newKeys = new int[newCap]; + var newValues = new int[newCap]; + var newNext = new int[newCap]; + + int newAlloc = 0; + int oldCap = m_Mask + 1; + for (int b = 0; b < oldCap; b++) + { + int i = m_Buckets[b]; + while (i > 0) + { + int old = i - 1; + int ni = newAlloc++; + newKeys[ni] = m_Keys[old]; + newValues[ni] = m_Values[old]; + int nb = (newKeys[ni] & 0x7FFFFFFF) & newMask; + newNext[ni] = newBuckets[nb]; + newBuckets[nb] = ni + 1; + i = m_Next[old]; + } + } + + m_Buckets = newBuckets; + m_Keys = newKeys; + m_Values = newValues; + m_Next = newNext; + m_Mask = newMask; + m_AllocCount = newAlloc; + m_FreeList = 0; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int NextPowerOf2(int v) + { + v--; + v |= v >> 1; v |= v >> 2; v |= v >> 4; + v |= v >> 8; v |= v >> 16; + return v + 1; + } + } +} diff --git a/Runtime/ABase/DataStruct/GameFrameworkMultiDictionary.cs.meta b/Runtime/ABase/ObjectPool/IntOpenHashMap.cs.meta similarity index 83% rename from Runtime/ABase/DataStruct/GameFrameworkMultiDictionary.cs.meta rename to Runtime/ABase/ObjectPool/IntOpenHashMap.cs.meta index 8e90a86..a5d1a3a 100644 --- a/Runtime/ABase/DataStruct/GameFrameworkMultiDictionary.cs.meta +++ b/Runtime/ABase/ObjectPool/IntOpenHashMap.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: ce20200ce38864c44b02e0c1ebc7fc3a +guid: 6e20a3f64bc47ae4dbf407342897a015 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Runtime/ABase/ObjectPool/ObjectBase.cs b/Runtime/ABase/ObjectPool/ObjectBase.cs index 75322e0..9ae0c1d 100644 --- a/Runtime/ABase/ObjectPool/ObjectBase.cs +++ b/Runtime/ABase/ObjectPool/ObjectBase.cs @@ -1,175 +1,57 @@ -using System; -using AlicizaX; - namespace AlicizaX.ObjectPool { - /// - /// 对象基类。 - /// public abstract class ObjectBase : IMemory { private string m_Name; private object m_Target; private bool m_Locked; - private int m_Priority; - private DateTime m_LastUseTime; + private float m_LastUseTime; - /// - /// 初始化对象基类的新实例。 - /// - public ObjectBase() - { - m_Name = null; - m_Target = null; - m_Locked = false; - m_Priority = 0; - m_LastUseTime = default(DateTime); - } + public string Name => m_Name; + public object Target => m_Target; - /// - /// 获取对象名称。 - /// - public virtual string Name - { - get { return m_Name; } - protected set { m_Name = value; } - } - - /// - /// 获取对象。 - /// - public object Target - { - get { return m_Target; } - } - - /// - /// 获取或设置对象是否被加锁。 - /// public bool Locked { - get { return m_Locked; } - set { m_Locked = value; } + get => m_Locked; + set => m_Locked = value; } - /// - /// 获取或设置对象的优先级。 - /// - public int Priority + public float LastUseTime { - get { return m_Priority; } - set { m_Priority = value; } + get => m_LastUseTime; + internal set => m_LastUseTime = value; } - /// - /// 获取自定义释放检查标记。 - /// - public virtual bool CustomCanReleaseFlag - { - get { return true; } - } + public virtual bool CustomCanReleaseFlag => true; - /// - /// 获取对象上次使用时间。 - /// - public DateTime LastUseTime - { - get { return m_LastUseTime; } - internal set { m_LastUseTime = value; } - } - - /// - /// 初始化对象基类。 - /// - /// 对象。 protected void Initialize(object target) { - Initialize(null, target, false, 0); + Initialize(string.Empty, target, false); } - /// - /// 初始化对象基类。 - /// - /// 对象名称。 - /// 对象。 protected void Initialize(string name, object target) { - Initialize(name, target, false, 0); + Initialize(name, target, false); } - /// - /// 初始化对象基类。 - /// - /// 对象名称。 - /// 对象。 - /// 对象是否被加锁。 protected void Initialize(string name, object target, bool locked) { - Initialize(name, target, locked, 0); - } - - /// - /// 初始化对象基类。 - /// - /// 对象名称。 - /// 对象。 - /// 对象的优先级。 - protected void Initialize(string name, object target, int priority) - { - Initialize(name, target, false, priority); - } - - /// - /// 初始化对象基类。 - /// - /// 对象名称。 - /// 对象。 - /// 对象是否被加锁。 - /// 对象的优先级。 - protected void Initialize(string name, object target, bool locked, int priority) - { - if (target == null) - { - throw new GameFrameworkException(Utility.Text.Format("Target '{0}' is invalid.", name)); - } - m_Name = name ?? string.Empty; m_Target = target; m_Locked = locked; - m_Priority = priority; - m_LastUseTime = DateTime.UtcNow; + m_LastUseTime = 0f; } - /// - /// 清理对象基类。 - /// + protected internal virtual void OnSpawn() { } + protected internal virtual void OnUnspawn() { } + protected internal abstract void Release(bool isShutdown); + public virtual void Clear() { m_Name = null; m_Target = null; m_Locked = false; - m_Priority = 0; - m_LastUseTime = default(DateTime); + m_LastUseTime = 0f; } - - /// - /// 获取对象时的事件。 - /// - protected internal virtual void OnSpawn() - { - } - - /// - /// 回收对象时的事件。 - /// - protected internal virtual void OnUnspawn() - { - } - - /// - /// 释放对象。 - /// - /// 是否是关闭对象池时触发。 - protected internal abstract void Release(bool isShutdown); } } diff --git a/Runtime/ABase/ObjectPool/ObjectInfo.cs b/Runtime/ABase/ObjectPool/ObjectInfo.cs index 6d08d64..1002b9a 100644 --- a/Runtime/ABase/ObjectPool/ObjectInfo.cs +++ b/Runtime/ABase/ObjectPool/ObjectInfo.cs @@ -1,115 +1,27 @@ -using System; using System.Runtime.InteropServices; namespace AlicizaX.ObjectPool { - /// - /// 对象信息。 - /// + [StructLayout(LayoutKind.Auto)] - public struct ObjectInfo + public readonly struct ObjectInfo { - private readonly string m_Name; - private readonly bool m_Locked; - private readonly bool m_CustomCanReleaseFlag; - private readonly int m_Priority; - private readonly DateTime m_LastUseTime; - private readonly int m_SpawnCount; + public readonly string Name; + public readonly bool Locked; + public readonly bool CustomCanReleaseFlag; + public readonly float LastUseTime; + public readonly int SpawnCount; - /// - /// 初始化对象信息的新实例。 - /// - /// 对象名称。 - /// 对象是否被加锁。 - /// 对象自定义释放检查标记。 - /// 对象的优先级。 - /// 对象上次使用时间。 - /// 对象的获取计数。 - public ObjectInfo(string name, bool locked, bool customCanReleaseFlag, int priority, DateTime lastUseTime, int spawnCount) + public ObjectInfo(string name, bool locked, bool customCanReleaseFlag, + float lastUseTime, int spawnCount) { - m_Name = name; - m_Locked = locked; - m_CustomCanReleaseFlag = customCanReleaseFlag; - m_Priority = priority; - m_LastUseTime = lastUseTime; - m_SpawnCount = spawnCount; + Name = name; + Locked = locked; + CustomCanReleaseFlag = customCanReleaseFlag; + LastUseTime = lastUseTime; + SpawnCount = spawnCount; } - /// - /// 获取对象名称。 - /// - public string Name - { - get - { - return m_Name; - } - } - - /// - /// 获取对象是否被加锁。 - /// - public bool Locked - { - get - { - return m_Locked; - } - } - - /// - /// 获取对象自定义释放检查标记。 - /// - public bool CustomCanReleaseFlag - { - get - { - return m_CustomCanReleaseFlag; - } - } - - /// - /// 获取对象的优先级。 - /// - public int Priority - { - get - { - return m_Priority; - } - } - - /// - /// 获取对象上次使用时间。 - /// - public DateTime LastUseTime - { - get - { - return m_LastUseTime; - } - } - - /// - /// 获取对象是否正在使用。 - /// - public bool IsInUse - { - get - { - return m_SpawnCount > 0; - } - } - - /// - /// 获取对象的获取计数。 - /// - public int SpawnCount - { - get - { - return m_SpawnCount; - } - } + public bool IsInUse => SpawnCount > 0; } } diff --git a/Runtime/ABase/ObjectPool/ObjectPoolBase.cs b/Runtime/ABase/ObjectPool/ObjectPoolBase.cs index 86df41f..2ea4056 100644 --- a/Runtime/ABase/ObjectPool/ObjectPoolBase.cs +++ b/Runtime/ABase/ObjectPool/ObjectPoolBase.cs @@ -1,149 +1,53 @@ -using System; +using System; using System.Collections.Generic; -using AlicizaX; namespace AlicizaX.ObjectPool { - /// - /// 对象池基类。 - /// + public abstract class ObjectPoolBase { private readonly string m_Name; - /// - /// 初始化对象池基类的新实例。 - /// - public ObjectPoolBase() - : this(null) - { - } + public ObjectPoolBase() : this(null) { } - /// - /// 初始化对象池基类的新实例。 - /// - /// 对象池名称。 public ObjectPoolBase(string name) { m_Name = name ?? string.Empty; } - /// - /// 获取对象池名称。 - /// - public string Name + public string Name => m_Name; + + public string FullName => new TypeNamePair(ObjectType, m_Name).ToString(); + + public abstract Type ObjectType { get; } + public abstract int Count { get; } + public abstract bool AllowMultiSpawn { get; } + + public abstract float AutoReleaseInterval { get; set; } + public abstract int Capacity { get; set; } + public abstract float ExpireTime { get; set; } + public abstract int Priority { get; set; } + + + public virtual int ReleasePerFrameBudget { - get - { - return m_Name; - } + get => 8; + set { } } - /// - /// 获取对象池完整名称。 - /// - public string FullName - { - get - { - return new TypeNamePair(ObjectType, m_Name).ToString(); - } - } - - /// - /// 获取对象池对象类型。 - /// - public abstract Type ObjectType - { - get; - } - - /// - /// 获取对象池中对象的数量。 - /// - public abstract int Count - { - get; - } - - /// - /// 获取对象池中能被释放的对象的数量。 - /// - public abstract int CanReleaseCount - { - get; - } - - /// - /// 获取是否允许对象被多次获取。 - /// - public abstract bool AllowMultiSpawn - { - get; - } - - /// - /// 获取或设置对象池自动释放可释放对象的间隔秒数。 - /// - public abstract float AutoReleaseInterval - { - get; - set; - } - - /// - /// 获取或设置对象池的容量。 - /// - public abstract int Capacity - { - get; - set; - } - - /// - /// 获取或设置对象池对象过期秒数。 - /// - public abstract float ExpireTime - { - get; - set; - } - - /// - /// 获取或设置对象池的优先级。 - /// - public abstract int Priority - { - get; - set; - } - - /// - /// 释放对象池中的可释放对象。 - /// public abstract void Release(); - - /// - /// 释放对象池中的可释放对象。 - /// - /// 尝试释放对象数量。 public abstract void Release(int toReleaseCount); - - /// - /// 释放对象池中的所有未使用对象。 - /// public abstract void ReleaseAllUnused(); - /// - /// 获取所有对象信息。 - /// - /// 所有对象信息。 public abstract ObjectInfo[] GetAllObjectInfos(); - public abstract void GetAllObjectInfos(List results); internal abstract void Update(float elapseSeconds, float realElapseSeconds); - internal abstract void Shutdown(); + + internal virtual void OnLowMemory() + { + ReleaseAllUnused(); + } } } diff --git a/Runtime/ABase/ObjectPool/ObjectPoolComponent.cs b/Runtime/ABase/ObjectPool/ObjectPoolComponent.cs index 9671b48..f12263c 100644 --- a/Runtime/ABase/ObjectPool/ObjectPoolComponent.cs +++ b/Runtime/ABase/ObjectPool/ObjectPoolComponent.cs @@ -3,40 +3,34 @@ using UnityEngine; namespace AlicizaX { - /// - /// 对象池组件。 - /// + public sealed class ObjectPoolComponent : MonoBehaviour { - private IObjectPoolService _mObjectPoolService = null; + private IObjectPoolService _mObjectPoolService; - /// - /// 获取对象池数量。 - /// - public int Count - { - get { return _mObjectPoolService.Count; } - } + public int Count => _mObjectPoolService.Count; private void Awake() { _mObjectPoolService = AppServices.RegisterApp(new ObjectPoolService()); + Application.lowMemory += OnLowMemory; } private void OnDestroy() { + Application.lowMemory -= OnLowMemory; _mObjectPoolService = null; } - /// - /// 获取所有对象池。 - /// - /// 是否根据对象池的优先级排序。 - /// 所有对象池。 + private void OnLowMemory() + { + if (_mObjectPoolService is ObjectPoolService svc) + svc.OnLowMemory(); + } + public ObjectPoolBase[] GetAllObjectPools(bool sort) { return _mObjectPoolService.GetAllObjectPools(sort); } } } - diff --git a/Runtime/ABase/ObjectPool/ObjectPoolService.Object.cs b/Runtime/ABase/ObjectPool/ObjectPoolService.Object.cs deleted file mode 100644 index 0c7edec..0000000 --- a/Runtime/ABase/ObjectPool/ObjectPoolService.Object.cs +++ /dev/null @@ -1,180 +0,0 @@ -using System; -using System.Collections.Generic; -using AlicizaX; - -namespace AlicizaX.ObjectPool -{ - internal sealed partial class ObjectPoolService : IObjectPoolService - { - /// - /// 内部对象。 - /// - /// 对象类型。 - private sealed class Object : IMemory where T : ObjectBase - { - private string m_Name; - private T m_Object; - private int m_SpawnCount; - private LinkedListNode> m_NameNode; - - /// - /// 初始化内部对象的新实例。 - /// - public Object() - { - m_Name = null; - m_Object = null; - m_SpawnCount = 0; - m_NameNode = null; - } - - /// - /// 获取对象名称。 - /// - public string Name - { - get { return m_Name; } - } - - /// - /// 获取对象是否被加锁。 - /// - public bool Locked - { - get { return m_Object.Locked; } - internal set { m_Object.Locked = value; } - } - - /// - /// 获取对象的优先级。 - /// - public int Priority - { - get { return m_Object.Priority; } - internal set { m_Object.Priority = value; } - } - - /// - /// 获取自定义释放检查标记。 - /// - public bool CustomCanReleaseFlag - { - get { return m_Object.CustomCanReleaseFlag; } - } - - /// - /// 获取对象上次使用时间。 - /// - public DateTime LastUseTime - { - get { return m_Object.LastUseTime; } - } - - /// - /// 获取对象是否正在使用。 - /// - public bool IsInUse - { - get { return m_SpawnCount > 0; } - } - - /// - /// 获取对象的获取计数。 - /// - public int SpawnCount - { - get { return m_SpawnCount; } - } - - /// - /// 获取或设置对象在名字桶中的链表结点。 - /// - public LinkedListNode> NameNode - { - get { return m_NameNode; } - internal set { m_NameNode = value; } - } - - /// - /// 创建内部对象。 - /// - /// 对象。 - /// 对象是否已被获取。 - /// 创建的内部对象。 - public static Object Create(T obj, bool spawned) - { - if (obj == null) - { - throw new GameFrameworkException("Object is invalid."); - } - - Object internalObject = MemoryPool.Acquire>(); - internalObject.m_Name = obj.Name; - internalObject.m_Object = obj; - internalObject.m_SpawnCount = spawned ? 1 : 0; - if (spawned) - { - obj.OnSpawn(); - } - - return internalObject; - } - - /// - /// 清理内部对象。 - /// - public void Clear() - { - m_Name = null; - m_Object = null; - m_SpawnCount = 0; - m_NameNode = null; - } - - /// - /// 查看对象。 - /// - /// 对象。 - public T Peek() - { - return m_Object; - } - - /// - /// 获取对象。 - /// - /// 对象。 - public T Spawn() - { - m_SpawnCount++; - m_Object.LastUseTime = DateTime.UtcNow; - m_Object.OnSpawn(); - return m_Object; - } - - /// - /// 回收对象。 - /// - public void Unspawn() - { - m_Object.LastUseTime = DateTime.UtcNow; - m_Object.OnUnspawn(); - m_SpawnCount--; - if (m_SpawnCount < 0) - { - throw new GameFrameworkException(Utility.Text.Format("Object '{0}' spawn count is less than 0.", Name)); - } - } - - /// - /// 释放对象。 - /// - /// 是否是关闭对象池时触发。 - public void Release(bool isShutdown) - { - m_Object.Release(isShutdown); - MemoryPool.Release(m_Object); - } - } - } -} diff --git a/Runtime/ABase/ObjectPool/ObjectPoolService.Object.cs.meta b/Runtime/ABase/ObjectPool/ObjectPoolService.Object.cs.meta deleted file mode 100644 index 6f0fcb9..0000000 --- a/Runtime/ABase/ObjectPool/ObjectPoolService.Object.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 35ccf480f8b7a42a4ba523c51d58e544 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/ABase/ObjectPool/ObjectPoolService.ObjectPool.cs b/Runtime/ABase/ObjectPool/ObjectPoolService.ObjectPool.cs index 40e60c8..8b7c6d1 100644 --- a/Runtime/ABase/ObjectPool/ObjectPoolService.ObjectPool.cs +++ b/Runtime/ABase/ObjectPool/ObjectPoolService.ObjectPool.cs @@ -1,22 +1,48 @@ using System; using System.Collections.Generic; -using AlicizaX; +using System.Runtime.CompilerServices; +using UnityEngine; namespace AlicizaX.ObjectPool { - internal sealed partial class ObjectPoolService : IObjectPoolService + internal sealed partial class ObjectPoolService { /// - /// 对象池。 + /// Unity main-thread object pool. Array-slot storage + IntOpenHashMap + /// + object-based spawn/unspawn + frame-spread release. /// - /// 对象类型。 private sealed class ObjectPool : ObjectPoolBase, IObjectPool where T : ObjectBase { - private readonly GameFrameworkMultiDictionary> m_Objects; - private readonly Dictionary> m_ObjectMap; - private readonly List> m_CachedCanReleaseObjects; - private readonly List> m_CachedToReleaseObjects; - private readonly IComparer> m_ReleaseObjectComparer; + private struct ObjectSlot + { + public T Obj; + public int SpawnCount; + public float LastUseTime; + public int NameHash; + public int NextSameName; + public int PrevUnused; + public int NextUnused; + public byte Flags; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool IsAlive() => (Flags & 1) != 0; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetAlive(bool alive) + { + if (alive) Flags |= 1; + else Flags = 0; + } + } + + private ObjectSlot[] m_Slots; + private int m_SlotCount; + private int[] m_FreeStack; + private int m_FreeTop; + + private readonly Dictionary m_TargetMap; + private IntOpenHashMap m_NameMap; + private readonly bool m_AllowMultiSpawn; private float m_AutoReleaseInterval; private int m_Capacity; @@ -24,650 +50,565 @@ namespace AlicizaX.ObjectPool private int m_Priority; private float m_AutoReleaseTime; - /// - /// 初始化对象池的新实例。 - /// - /// 对象池名称。 - /// 是否允许对象被多次获取。 - /// 对象池自动释放可释放对象的间隔秒数。 - /// 对象池的容量。 - /// 对象池对象过期秒数。 - /// 对象池的优先级。 - public ObjectPool(string name, bool allowMultiSpawn, float autoReleaseInterval, int capacity, float expireTime, int priority) + private int m_PendingReleaseCount; + private int m_ReleasePerFrameBudget; + private int m_UnusedHead; + private int m_UnusedTail; + private int m_LastBudgetScanStart; + private bool m_IsShuttingDown; + + private const int DefaultReleasePerFrame = 8; + private const int InitSlotCapacity = 16; + + public ObjectPool(string name, bool allowMultiSpawn, + float autoReleaseInterval, int capacity, float expireTime, int priority) : base(name) { - m_Objects = new GameFrameworkMultiDictionary>(); - m_ObjectMap = new Dictionary>(); - m_CachedCanReleaseObjects = new List>(); - m_CachedToReleaseObjects = new List>(); - m_ReleaseObjectComparer = Comparer>.Create(ReleaseObjectComparer); + int initCap = Math.Min(Math.Max(capacity, 1), InitSlotCapacity); + m_Slots = new ObjectSlot[initCap]; + m_FreeStack = new int[initCap]; + m_TargetMap = new Dictionary(initCap, AlicizaX.ReferenceComparer.Instance); + m_NameMap = new IntOpenHashMap(initCap); m_AllowMultiSpawn = allowMultiSpawn; m_AutoReleaseInterval = autoReleaseInterval; - Capacity = capacity; - ExpireTime = expireTime; + m_Capacity = capacity; + m_ExpireTime = expireTime; m_Priority = priority; m_AutoReleaseTime = 0f; + m_PendingReleaseCount = 0; + m_ReleasePerFrameBudget = DefaultReleasePerFrame; + m_UnusedHead = -1; + m_UnusedTail = -1; + m_LastBudgetScanStart = -1; + m_IsShuttingDown = false; } - /// - /// 获取对象池对象类型。 - /// - public override Type ObjectType - { - get { return typeof(T); } - } + public override Type ObjectType => typeof(T); + public override int Count => m_TargetMap.Count; + public override bool AllowMultiSpawn => m_AllowMultiSpawn; - /// - /// 获取对象池中对象的数量。 - /// - public override int Count - { - get { return m_ObjectMap.Count; } - } - - /// - /// 获取对象池中能被释放的对象的数量。 - /// - public override int CanReleaseCount - { - get - { - int count = 0; - foreach (KeyValuePair> kv in m_ObjectMap) - { - Object obj = kv.Value; - if (!obj.IsInUse && !obj.Locked && obj.CustomCanReleaseFlag) - count++; - } - return count; - } - } - - /// - /// 获取是否允许对象被多次获取。 - /// - public override bool AllowMultiSpawn - { - get { return m_AllowMultiSpawn; } - } - - /// - /// 获取或设置对象池自动释放可释放对象的间隔秒数。 - /// public override float AutoReleaseInterval { - get { return m_AutoReleaseInterval; } - set { m_AutoReleaseInterval = value; } + get => m_AutoReleaseInterval; + set + { + if (value < 0f) throw new GameFrameworkException("AutoReleaseInterval is invalid."); + m_AutoReleaseInterval = value; + } } - /// - /// 获取或设置对象池的容量。 - /// public override int Capacity { - get { return m_Capacity; } + get => m_Capacity; set { - if (value < 0) - { - throw new GameFrameworkException("Capacity is invalid."); - } - - if (m_Capacity == value) - { - return; - } - + if (value < 0) throw new GameFrameworkException("Capacity is invalid."); m_Capacity = value; - Release(); + if (Count > m_Capacity) MarkRelease(Count - m_Capacity); } } - /// - /// 获取或设置对象池对象过期秒数。 - /// public override float ExpireTime { - get { return m_ExpireTime; } - + get => m_ExpireTime; set { - if (value < 0f) - { - throw new GameFrameworkException("ExpireTime is invalid."); - } - - if (ExpireTime == value) - { - return; - } - + if (value < 0f) throw new GameFrameworkException("ExpireTime is invalid."); m_ExpireTime = value; - Release(); } } - /// - /// 获取或设置对象池的优先级。 - /// public override int Priority { - get { return m_Priority; } - set { m_Priority = value; } + get => m_Priority; + set => m_Priority = value; + } + + public override int ReleasePerFrameBudget + { + get => m_ReleasePerFrameBudget; + set => m_ReleasePerFrameBudget = Math.Max(1, value); } - /// - /// 创建对象。 - /// - /// 对象。 - /// 对象是否已被获取。 public void Register(T obj, bool spawned) { - if (obj == null) - { - throw new GameFrameworkException("Object is invalid."); - } + if (obj == null) throw new GameFrameworkException("Object is invalid."); + if (obj.Target == null) throw new GameFrameworkException("Object target is invalid."); + if (m_TargetMap.TryGetValue(obj.Target, out int existingIdx) && m_Slots[existingIdx].IsAlive()) + throw new GameFrameworkException( + $"Target '{obj.Target.GetType().FullName}' is already registered in pool '{FullName}'."); - Object internalObject = Object.Create(obj, spawned); - internalObject.NameNode = m_Objects.Add(internalObject.Name, internalObject); - m_ObjectMap.Add(obj.Target, internalObject); + int idx = AllocSlot(); + ref var slot = ref m_Slots[idx]; + slot.Obj = obj; + slot.SpawnCount = spawned ? 1 : 0; + slot.LastUseTime = Time.realtimeSinceStartup; + slot.NameHash = (obj.Name ?? string.Empty).GetHashCode(); + slot.NextSameName = -1; + slot.PrevUnused = -1; + slot.NextUnused = -1; + slot.SetAlive(true); - if (Count > m_Capacity) - { - Release(); - } + m_TargetMap[obj.Target] = idx; + + if (m_NameMap.TryGetValue(slot.NameHash, out int existingHead)) + slot.NextSameName = existingHead; + m_NameMap.AddOrUpdate(slot.NameHash, idx); + + obj.LastUseTime = slot.LastUseTime; + if (spawned) + obj.OnSpawn(); + else + AddToUnusedList(idx); + + if (Count > m_Capacity) MarkRelease(Count - m_Capacity); } - /// - /// 检查对象。 - /// - /// 要检查的对象是否存在。 - public bool CanSpawn() - { - return CanSpawn(string.Empty); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T Spawn() => Spawn(string.Empty); - /// - /// 检查对象。 - /// - /// 对象名称。 - /// 要检查的对象是否存在。 - public bool CanSpawn(string name) - { - if (name == null) - { - throw new GameFrameworkException("Name is invalid."); - } - - GameFrameworkLinkedListRange> objectRange = default(GameFrameworkLinkedListRange>); - if (m_Objects.TryGetValue(name, out objectRange)) - { - foreach (Object internalObject in objectRange) - { - if (m_AllowMultiSpawn || !internalObject.IsInUse) - { - return true; - } - } - } - - return false; - } - - /// - /// 获取对象。 - /// - /// 要获取的对象。 - public T Spawn() - { - return Spawn(string.Empty); - } - - /// - /// 获取对象。 - /// - /// 对象名称。 - /// 要获取的对象。 public T Spawn(string name) { - if (name == null) - { - throw new GameFrameworkException("Name is invalid."); - } + if (name == null) throw new GameFrameworkException("Name is invalid."); + int nameHash = name.GetHashCode(); + if (!m_NameMap.TryGetValue(nameHash, out int head)) return null; - GameFrameworkLinkedListRange> objectRange = default(GameFrameworkLinkedListRange>); - if (m_Objects.TryGetValue(name, out objectRange)) + float now = Time.realtimeSinceStartup; + int current = head; + while (current >= 0) { - foreach (Object internalObject in objectRange) + ref var slot = ref m_Slots[current]; + if (slot.IsAlive() && string.Equals(slot.Obj.Name, name) + && (m_AllowMultiSpawn || slot.SpawnCount == 0)) { - if (m_AllowMultiSpawn || !internalObject.IsInUse) - { - return internalObject.Spawn(); - } + SpawnSlot(current, now); + return slot.Obj; } + + current = slot.NextSameName; } return null; } - /// - /// 回收对象。 - /// - /// 要回收的对象。 - public void Unspawn(T obj) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool CanSpawn() => CanSpawn(string.Empty); + + public bool CanSpawn(string name) { - if (obj == null) + if (name == null) throw new GameFrameworkException("Name is invalid."); + int nameHash = name.GetHashCode(); + if (!m_NameMap.TryGetValue(nameHash, out int head)) return false; + + int current = head; + while (current >= 0) { - throw new GameFrameworkException("Object is invalid."); + ref var slot = ref m_Slots[current]; + if (slot.IsAlive() && string.Equals(slot.Obj.Name, name) + && (m_AllowMultiSpawn || slot.SpawnCount == 0)) + return true; + current = slot.NextSameName; } + return false; + } + + public void Unspawn(T obj) + { + if (obj == null) throw new GameFrameworkException("Object is invalid."); Unspawn(obj.Target); } - /// - /// 回收对象。 - /// - /// 要回收的对象。 public void Unspawn(object target) { - if (target == null) + if (target == null) throw new GameFrameworkException("Target is invalid."); + if (!m_TargetMap.TryGetValue(target, out int idx)) { - throw new GameFrameworkException("Target is invalid."); + if (m_IsShuttingDown) return; + throw new GameFrameworkException( + $"Cannot find target in pool '{Name}', type='{target.GetType().FullName}'"); } - Object internalObject = GetObject(target); - if (internalObject != null) - { - internalObject.Unspawn(); - if (Count > m_Capacity && internalObject.SpawnCount <= 0) - { - Release(); - } - } - else - { - throw new GameFrameworkException(Utility.Text.Format("Can not find target in object pool '{0}', target type is '{1}', target value is '{2}'.", new TypeNamePair(typeof(T), Name), target.GetType().FullName, target)); - } + UnspawnSlot(idx); } - /// - /// 设置对象是否被加锁。 - /// - /// 要设置被加锁的对象。 - /// 是否被加锁。 - public void SetLocked(T obj, bool locked) - { - if (obj == null) - { - throw new GameFrameworkException("Object is invalid."); - } - - SetLocked(obj.Target, locked); - } - - /// - /// 设置对象是否被加锁。 - /// - /// 要设置被加锁的对象。 - /// 是否被加锁。 - public void SetLocked(object target, bool locked) - { - if (target == null) - { - throw new GameFrameworkException("Target is invalid."); - } - - Object internalObject = GetObject(target); - if (internalObject != null) - { - internalObject.Locked = locked; - } - else - { - throw new GameFrameworkException(Utility.Text.Format("Can not find target in object pool '{0}', target type is '{1}', target value is '{2}'.", new TypeNamePair(typeof(T), Name), target.GetType().FullName, target)); - } - } - - /// - /// 设置对象的优先级。 - /// - /// 要设置优先级的对象。 - /// 优先级。 - public void SetPriority(T obj, int priority) - { - if (obj == null) - { - throw new GameFrameworkException("Object is invalid."); - } - - SetPriority(obj.Target, priority); - } - - /// - /// 设置对象的优先级。 - /// - /// 要设置优先级的对象。 - /// 优先级。 - public void SetPriority(object target, int priority) - { - if (target == null) - { - throw new GameFrameworkException("Target is invalid."); - } - - Object internalObject = GetObject(target); - if (internalObject != null) - { - internalObject.Priority = priority; - } - else - { - throw new GameFrameworkException(Utility.Text.Format("Can not find target in object pool '{0}', target type is '{1}', target value is '{2}'.", new TypeNamePair(typeof(T), Name), target.GetType().FullName, target)); - } - } - - /// - /// 释放对象。 - /// - /// 要释放的对象。 - /// 释放对象是否成功。 - public bool ReleaseObject(T obj) - { - if (obj == null) - { - throw new GameFrameworkException("Object is invalid."); - } - - return ReleaseObject(obj.Target); - } - - /// - /// 释放对象。 - /// - /// 要释放的对象。 - /// 释放对象是否成功。 - public bool ReleaseObject(object target) - { - if (target == null) - { - throw new GameFrameworkException("Target is invalid."); - } - - Object internalObject = GetObject(target); - if (internalObject == null) - { - return false; - } - - return ReleaseObject(internalObject); - } - - /// - /// 释放对象池中的可释放对象。 - /// public override void Release() { - ReleaseWithDefaultFilter(Count - m_Capacity); + MarkRelease(Count - m_Capacity); } - /// - /// 释放对象池中的可释放对象。 - /// - /// 尝试释放对象数量。 public override void Release(int toReleaseCount) { - ReleaseWithDefaultFilter(toReleaseCount); + MarkRelease(toReleaseCount); } - /// - /// 释放对象池中的可释放对象。 - /// - /// 释放对象筛选函数。 - public void Release(ReleaseObjectFilterCallback releaseObjectFilterCallback) - { - Release(Count - m_Capacity, releaseObjectFilterCallback); - } - - /// - /// 释放对象池中的可释放对象。 - /// - /// 尝试释放对象数量。 - /// 释放对象筛选函数。 - public void Release(int toReleaseCount, ReleaseObjectFilterCallback releaseObjectFilterCallback) - { - if (releaseObjectFilterCallback == null) - { - ReleaseWithDefaultFilter(toReleaseCount); - return; - } - - if (toReleaseCount < 0) - { - toReleaseCount = 0; - } - - DateTime expireTime = DateTime.MinValue; - if (m_ExpireTime < float.MaxValue) - { - expireTime = DateTime.UtcNow.AddSeconds(-m_ExpireTime); - } - - m_AutoReleaseTime = 0f; - GetCanReleaseObjects(m_CachedCanReleaseObjects); - List candidateTargets = new List(m_CachedCanReleaseObjects.Count); - foreach (Object internalObject in m_CachedCanReleaseObjects) - { - candidateTargets.Add(internalObject.Peek()); - } - - List toReleaseObjects = releaseObjectFilterCallback(candidateTargets, toReleaseCount, expireTime); - if (toReleaseObjects == null || toReleaseObjects.Count <= 0) - { - return; - } - - foreach (T toReleaseObject in toReleaseObjects) - { - ReleaseObject(toReleaseObject); - } - } - - /// - /// 释放对象池中的所有未使用对象。 - /// public override void ReleaseAllUnused() { - m_AutoReleaseTime = 0f; - GetCanReleaseObjects(m_CachedCanReleaseObjects); - foreach (Object toReleaseObject in m_CachedCanReleaseObjects) + // Strong clear: release every currently unused releasable object, + // ignoring frame budget and capacity target. + int released = 0; + int current = m_UnusedHead; + while (current >= 0) { - ReleaseObject(toReleaseObject); - } - } - - /// - /// 获取所有对象信息。 - /// - /// 所有对象信息。 - public override ObjectInfo[] GetAllObjectInfos() - { - List results = new List(); - GetAllObjectInfos(results); - return results.ToArray(); - } - - public override void GetAllObjectInfos(List results) - { - if (results == null) - { - throw new GameFrameworkException("Results is invalid."); - } - - results.Clear(); - foreach (KeyValuePair>> objectRanges in m_Objects) - { - foreach (Object internalObject in objectRanges.Value) + int next = m_Slots[current].NextUnused; + ref var slot = ref m_Slots[current]; + if (CanReleaseSlot(ref slot)) { - results.Add(new ObjectInfo(internalObject.Name, internalObject.Locked, internalObject.CustomCanReleaseFlag, internalObject.Priority, internalObject.LastUseTime, internalObject.SpawnCount)); + ReleaseSlot(current); + released++; } + current = next; + } + + if (released > 0) + { + m_PendingReleaseCount = Math.Max(0, m_PendingReleaseCount - released); + ShrinkStorageIfEmpty(); } } internal override void Update(float elapseSeconds, float realElapseSeconds) { m_AutoReleaseTime += realElapseSeconds; - if (m_AutoReleaseTime < m_AutoReleaseInterval) + if (m_AutoReleaseTime >= m_AutoReleaseInterval) { - return; + m_AutoReleaseTime = 0f; + MarkRelease(Count - m_Capacity); } - Release(); + bool checkExpire = m_ExpireTime < float.MaxValue; + if (m_PendingReleaseCount <= 0 && !checkExpire) return; + + float now = Time.realtimeSinceStartup; + float expireThreshold = checkExpire ? now - m_ExpireTime : float.MinValue; + if (m_PendingReleaseCount > 0) + { + int releaseBudget = Math.Min(m_ReleasePerFrameBudget, m_PendingReleaseCount); + int releasedByBudget = ReleaseUnused(releaseBudget, false, float.MinValue); + m_PendingReleaseCount = Math.Max(0, m_PendingReleaseCount - releasedByBudget); + } + else if (checkExpire) + { + ReleaseExpired(m_ReleasePerFrameBudget, expireThreshold); + } } internal override void Shutdown() { - foreach (KeyValuePair> objectInMap in m_ObjectMap) + m_IsShuttingDown = true; + for (int i = 0; i < m_SlotCount; i++) { - objectInMap.Value.Release(true); - MemoryPool.Release(objectInMap.Value); + ref var slot = ref m_Slots[i]; + if (!slot.IsAlive()) continue; + slot.Obj.Release(true); + MemoryPool.Release(slot.Obj); + slot.Obj = null; + slot.SetAlive(false); } - m_Objects.Clear(); - m_ObjectMap.Clear(); - m_CachedCanReleaseObjects.Clear(); - m_CachedToReleaseObjects.Clear(); + m_TargetMap.Clear(); + m_NameMap.Clear(); + m_SlotCount = 0; + m_FreeTop = 0; + m_PendingReleaseCount = 0; + m_UnusedHead = -1; + m_UnusedTail = -1; + m_LastBudgetScanStart = -1; + m_IsShuttingDown = false; } - private Object GetObject(object target) + public override ObjectInfo[] GetAllObjectInfos() { - if (target == null) + var list = new ObjectInfo[m_TargetMap.Count]; + int write = 0; + for (int i = 0; i < m_SlotCount && write < list.Length; i++) { - throw new GameFrameworkException("Target is invalid."); + ref var slot = ref m_Slots[i]; + if (!slot.IsAlive()) continue; + list[write++] = new ObjectInfo(slot.Obj.Name, slot.Obj.Locked, + slot.Obj.CustomCanReleaseFlag, + slot.Obj.LastUseTime, slot.SpawnCount); } - Object internalObject = null; - if (m_ObjectMap.TryGetValue(target, out internalObject)) - { - return internalObject; - } - - return null; + return list; } - private bool ReleaseObject(Object internalObject) + public override void GetAllObjectInfos(List results) { - if (internalObject == null) - { - return false; - } - - if (internalObject.IsInUse || internalObject.Locked || !internalObject.CustomCanReleaseFlag) - { - return false; - } - - T targetObject = internalObject.Peek(); - if (targetObject == null) - { - return false; - } - - m_Objects.Remove(internalObject.Name, internalObject.NameNode); - - internalObject.NameNode = null; - m_ObjectMap.Remove(targetObject.Target); - - internalObject.Release(false); - MemoryPool.Release(internalObject); - return true; - } - - private void ReleaseWithDefaultFilter(int toReleaseCount) - { - if (toReleaseCount < 0) - { - toReleaseCount = 0; - } - - DateTime expireTime = DateTime.MinValue; - bool checkExpire = m_ExpireTime < float.MaxValue; - if (checkExpire) - { - expireTime = DateTime.UtcNow.AddSeconds(-m_ExpireTime); - } - - m_AutoReleaseTime = 0f; - if (Count <= 0 || (toReleaseCount <= 0 && !checkExpire)) - { - return; - } - - GetCanReleaseObjects(m_CachedCanReleaseObjects); - if (m_CachedCanReleaseObjects.Count <= 0) - { - return; - } - - m_CachedToReleaseObjects.Clear(); - int remainingCount = 0; - for (int i = 0; i < m_CachedCanReleaseObjects.Count; i++) - { - Object candidateObject = m_CachedCanReleaseObjects[i]; - if (checkExpire && candidateObject.LastUseTime <= expireTime) - { - m_CachedToReleaseObjects.Add(candidateObject); - continue; - } - - m_CachedCanReleaseObjects[remainingCount++] = candidateObject; - } - - int additionalReleaseCount = toReleaseCount - m_CachedToReleaseObjects.Count; - if (additionalReleaseCount > 0 && remainingCount > 0) - { - m_CachedCanReleaseObjects.Sort(0, remainingCount, m_ReleaseObjectComparer); - int takeCount = additionalReleaseCount < remainingCount ? additionalReleaseCount : remainingCount; - for (int i = 0; i < takeCount; i++) - { - m_CachedToReleaseObjects.Add(m_CachedCanReleaseObjects[i]); - } - } - - foreach (Object toReleaseObject in m_CachedToReleaseObjects) - { - ReleaseObject(toReleaseObject); - } - } - - private void GetCanReleaseObjects(List> results) - { - if (results == null) - { - throw new GameFrameworkException("Results is invalid."); - } - + if (results == null) throw new GameFrameworkException("Results is invalid."); results.Clear(); - foreach (KeyValuePair> objectInMap in m_ObjectMap) + for (int i = 0; i < m_SlotCount; i++) { - Object internalObject = objectInMap.Value; - if (internalObject.IsInUse || internalObject.Locked || !internalObject.CustomCanReleaseFlag) - { - continue; - } - - results.Add(internalObject); + ref var slot = ref m_Slots[i]; + if (!slot.IsAlive()) continue; + results.Add(new ObjectInfo(slot.Obj.Name, slot.Obj.Locked, + slot.Obj.CustomCanReleaseFlag, + slot.Obj.LastUseTime, slot.SpawnCount)); } } - private static int ReleaseObjectComparer(Object a, Object b) + internal override void OnLowMemory() { - int priorityCompare = a.Priority.CompareTo(b.Priority); - if (priorityCompare != 0) + ReleaseAllUnused(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void SpawnSlot(int idx, float now) + { + ref var slot = ref m_Slots[idx]; + if (slot.SpawnCount == 0) + RemoveFromUnusedList(idx); + + slot.SpawnCount++; + slot.LastUseTime = now; + slot.Obj.LastUseTime = now; + slot.Obj.OnSpawn(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void UnspawnSlot(int idx) + { + ref var slot = ref m_Slots[idx]; + float now = Time.realtimeSinceStartup; + slot.LastUseTime = now; + slot.Obj.LastUseTime = now; + slot.Obj.OnUnspawn(); + slot.SpawnCount--; + if (slot.SpawnCount < 0) + throw new GameFrameworkException($"Object '{slot.Obj.Name}' spawn count < 0."); + if (slot.SpawnCount == 0) + AddToUnusedList(idx); + if (Count > m_Capacity && slot.SpawnCount == 0) + MarkRelease(Count - m_Capacity); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void MarkRelease(int count) + { + if (count > 0) + m_PendingReleaseCount = Math.Max(m_PendingReleaseCount, count); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int AllocSlot() + { + if (m_FreeTop > 0) + return m_FreeStack[--m_FreeTop]; + + if (m_SlotCount >= m_Slots.Length) + GrowSlots(); + + return m_SlotCount++; + } + + private void GrowSlots() + { + int newCap = Math.Max(m_Slots.Length * 2, InitSlotCapacity); + Array.Resize(ref m_Slots, newCap); + Array.Resize(ref m_FreeStack, newCap); + } + + private void ReleaseSlot(int idx) + { + ref var slot = ref m_Slots[idx]; + if (!slot.IsAlive()) return; + + T obj = slot.Obj; + if (slot.SpawnCount == 0) + RemoveFromUnusedList(idx); + + RemoveFromNameChain(idx); + m_TargetMap.Remove(obj.Target); + + obj.Release(false); + MemoryPool.Release(obj); + + slot.Obj = null; + slot.SetAlive(false); + slot.SpawnCount = 0; + slot.NameHash = 0; + slot.NextSameName = -1; + slot.PrevUnused = -1; + slot.NextUnused = -1; + + if (m_FreeTop >= m_FreeStack.Length) + Array.Resize(ref m_FreeStack, m_FreeStack.Length * 2); + m_FreeStack[m_FreeTop++] = idx; + + ShrinkStorageIfEmpty(); + } + + private void RemoveFromNameChain(int idx) + { + ref var slot = ref m_Slots[idx]; + int nameHash = slot.NameHash; + if (!m_NameMap.TryGetValue(nameHash, out int head)) return; + + if (head == idx) { - return priorityCompare; + m_NameMap.Remove(nameHash); + if (slot.NextSameName >= 0) + m_NameMap.AddOrUpdate(nameHash, slot.NextSameName); + } + else + { + int current = head; + while (current >= 0) + { + ref var chainSlot = ref m_Slots[current]; + if (chainSlot.NextSameName == idx) + { + chainSlot.NextSameName = slot.NextSameName; + break; + } + current = chainSlot.NextSameName; + } } - return a.LastUseTime.CompareTo(b.LastUseTime); + slot.NextSameName = -1; + } + + private int ReleaseUnused(int maxReleaseCount, bool requireExpired, float expireThreshold) + { + int released = 0; + int current = requireExpired ? m_UnusedHead : GetBudgetScanStart(); + + while (current >= 0 && released < maxReleaseCount) + { + ref var slot = ref m_Slots[current]; + int next = slot.NextUnused; + + if (requireExpired && slot.LastUseTime > expireThreshold) + { + break; + } + + if (CanReleaseSlot(ref slot)) + { + ReleaseSlot(current); + released++; + } + + current = next; + } + + if (!requireExpired) + { + m_LastBudgetScanStart = current >= 0 ? current : m_UnusedHead; + } + + return released; + } + + private void ReleaseExpired(int maxReleaseCount, float expireThreshold) + { + ReleaseUnused(maxReleaseCount, true, expireThreshold); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int GetBudgetScanStart() + { + if (m_LastBudgetScanStart >= 0) + { + ref var slot = ref m_Slots[m_LastBudgetScanStart]; + if (slot.IsAlive() && slot.SpawnCount == 0) + { + return m_LastBudgetScanStart; + } + } + + return m_UnusedHead; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool CanReleaseSlot(ref ObjectSlot slot) + { + return slot.IsAlive() + && slot.SpawnCount == 0 + && !slot.Obj.Locked + && slot.Obj.CustomCanReleaseFlag; + } + + private void ShrinkStorageIfEmpty() + { + if (m_TargetMap.Count > 0 || m_Slots.Length <= InitSlotCapacity) + return; + + m_Slots = new ObjectSlot[InitSlotCapacity]; + m_FreeStack = new int[InitSlotCapacity]; + m_NameMap = new IntOpenHashMap(InitSlotCapacity); + m_SlotCount = 0; + m_FreeTop = 0; + m_UnusedHead = -1; + m_UnusedTail = -1; + m_LastBudgetScanStart = -1; + } + + private void AddToUnusedList(int idx) + { + ref var slot = ref m_Slots[idx]; + if (m_UnusedHead == idx || slot.PrevUnused >= 0 || slot.NextUnused >= 0) + return; + + if (m_UnusedTail >= 0 && m_Slots[m_UnusedTail].LastUseTime <= slot.LastUseTime) + { + m_Slots[m_UnusedTail].NextUnused = idx; + slot.PrevUnused = m_UnusedTail; + slot.NextUnused = -1; + m_UnusedTail = idx; + } + else + { + int current = m_UnusedHead; + int prev = -1; + while (current >= 0 && m_Slots[current].LastUseTime <= slot.LastUseTime) + { + prev = current; + current = m_Slots[current].NextUnused; + } + + slot.PrevUnused = prev; + slot.NextUnused = current; + + if (prev >= 0) + m_Slots[prev].NextUnused = idx; + else + m_UnusedHead = idx; + + if (current >= 0) + m_Slots[current].PrevUnused = idx; + else + m_UnusedTail = idx; + + if (m_UnusedTail < 0) + m_UnusedTail = idx; + } + } + + private void RemoveFromUnusedList(int idx) + { + ref var slot = ref m_Slots[idx]; + if (m_UnusedHead != idx && slot.PrevUnused < 0 && slot.NextUnused < 0) + return; + + int prev = slot.PrevUnused; + int next = slot.NextUnused; + + if (prev >= 0) + m_Slots[prev].NextUnused = next; + else + m_UnusedHead = next; + + if (next >= 0) + m_Slots[next].PrevUnused = prev; + else + m_UnusedTail = prev; + + slot.PrevUnused = -1; + slot.NextUnused = -1; + + if (m_LastBudgetScanStart == idx) + m_LastBudgetScanStart = next >= 0 ? next : m_UnusedHead; } } } diff --git a/Runtime/ABase/ObjectPool/ObjectPoolService.cs b/Runtime/ABase/ObjectPool/ObjectPoolService.cs index 1eb194f..c78ec2e 100644 --- a/Runtime/ABase/ObjectPool/ObjectPoolService.cs +++ b/Runtime/ABase/ObjectPool/ObjectPoolService.cs @@ -1,28 +1,21 @@ -using System; +using System; using System.Collections.Generic; -using AlicizaX; using UnityEngine; namespace AlicizaX.ObjectPool { - /// - /// 对象池管理器。 - /// + [UnityEngine.Scripting.Preserve] internal sealed partial class ObjectPoolService : ServiceBase, IObjectPoolService, IServiceTickable { private const int DefaultCapacity = int.MaxValue; private const float DefaultExpireTime = float.MaxValue; - private const int DefaultPriority = 0; private readonly Dictionary m_ObjectPools; private readonly List m_ObjectPoolList; private readonly List m_CachedAllObjectPools; private readonly Comparison m_ObjectPoolComparer; - /// - /// 初始化对象池管理器的新实例。 - /// public ObjectPoolService() { m_ObjectPools = new Dictionary(); @@ -31,1291 +24,214 @@ namespace AlicizaX.ObjectPool m_ObjectPoolComparer = ObjectPoolComparer; } - /// - /// 获取游戏框架模块优先级。 - /// - /// 优先级较高的模块会优先轮询,并且关闭操作会后进行。 public int Priority => 1; + public int Count => m_ObjectPools.Count; - /// - /// 获取对象池数量。 - /// - public int Count - { - get { return m_ObjectPools.Count; } - } - - /// - /// 对象池管理器轮询。 - /// - /// 逻辑流逝时间,以秒为单位。 - /// 真实流逝时间,以秒为单位。 void IServiceTickable.Tick(float deltaTime) { for (int i = 0; i < m_ObjectPoolList.Count; i++) - { m_ObjectPoolList[i].Update(deltaTime, Time.unscaledDeltaTime); - } } - /// - /// 关闭并清理对象池管理器。 - /// protected override void OnInitialize() { } protected override void OnDestroyService() { - for (int i = 0; i < m_ObjectPoolList.Count; i++) - { + for (int i = m_ObjectPoolList.Count - 1; i >= 0; i--) m_ObjectPoolList[i].Shutdown(); - } - m_ObjectPools.Clear(); m_ObjectPoolList.Clear(); m_CachedAllObjectPools.Clear(); } - /// - /// 检查是否存在对象池。 - /// - /// 对象类型。 - /// 是否存在对象池。 - public bool HasObjectPool() where T : ObjectBase - { - return InternalHasObjectPool(new TypeNamePair(typeof(T))); - } + // ========== Has ========== + + public bool HasObjectPool() where T : ObjectBase + => m_ObjectPools.ContainsKey(new TypeNamePair(typeof(T))); + + public bool HasObjectPool(string name) where T : ObjectBase + => m_ObjectPools.ContainsKey(new TypeNamePair(typeof(T), name)); - /// - /// 检查是否存在对象池。 - /// - /// 对象类型。 - /// 是否存在对象池。 public bool HasObjectPool(Type objectType) { - if (objectType == null) - { - throw new GameFrameworkException("Object type is invalid."); - } - - if (!typeof(ObjectBase).IsAssignableFrom(objectType)) - { - throw new GameFrameworkException(Utility.Text.Format("Object type '{0}' is invalid.", objectType.FullName)); - } - - return InternalHasObjectPool(new TypeNamePair(objectType)); + ValidateObjectType(objectType); + return m_ObjectPools.ContainsKey(new TypeNamePair(objectType)); } - /// - /// 检查是否存在对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 是否存在对象池。 - public bool HasObjectPool(string name) where T : ObjectBase - { - return InternalHasObjectPool(new TypeNamePair(typeof(T), name)); - } - - /// - /// 检查是否存在对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 是否存在对象池。 public bool HasObjectPool(Type objectType, string name) { - if (objectType == null) - { - throw new GameFrameworkException("Object type is invalid."); - } - - if (!typeof(ObjectBase).IsAssignableFrom(objectType)) - { - throw new GameFrameworkException(Utility.Text.Format("Object type '{0}' is invalid.", objectType.FullName)); - } - - return InternalHasObjectPool(new TypeNamePair(objectType, name)); + ValidateObjectType(objectType); + return m_ObjectPools.ContainsKey(new TypeNamePair(objectType, name)); } - /// - /// 检查是否存在对象池。 - /// - /// 要检查的条件。 - /// 是否存在对象池。 - public bool HasObjectPool(Predicate condition) - { - if (condition == null) - { - throw new GameFrameworkException("Condition is invalid."); - } + // ========== Get ========== - for (int i = 0; i < m_ObjectPoolList.Count; i++) - { - if (condition(m_ObjectPoolList[i])) - { - return true; - } - } - - return false; - } - - /// - /// 获取对象池。 - /// - /// 对象类型。 - /// 要获取的对象池。 public IObjectPool GetObjectPool() where T : ObjectBase - { - return (IObjectPool)InternalGetObjectPool(new TypeNamePair(typeof(T))); - } + => (IObjectPool)InternalGet(new TypeNamePair(typeof(T))); + + public IObjectPool GetObjectPool(string name) where T : ObjectBase + => (IObjectPool)InternalGet(new TypeNamePair(typeof(T), name)); - /// - /// 获取对象池。 - /// - /// 对象类型。 - /// 要获取的对象池。 public ObjectPoolBase GetObjectPool(Type objectType) { - if (objectType == null) - { - throw new GameFrameworkException("Object type is invalid."); - } - - if (!typeof(ObjectBase).IsAssignableFrom(objectType)) - { - throw new GameFrameworkException(Utility.Text.Format("Object type '{0}' is invalid.", objectType.FullName)); - } - - return InternalGetObjectPool(new TypeNamePair(objectType)); + ValidateObjectType(objectType); + return InternalGet(new TypeNamePair(objectType)); } - /// - /// 获取对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 要获取的对象池。 - public IObjectPool GetObjectPool(string name) where T : ObjectBase - { - return (IObjectPool)InternalGetObjectPool(new TypeNamePair(typeof(T), name)); - } - - /// - /// 获取对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 要获取的对象池。 public ObjectPoolBase GetObjectPool(Type objectType, string name) { - if (objectType == null) - { - throw new GameFrameworkException("Object type is invalid."); - } - - if (!typeof(ObjectBase).IsAssignableFrom(objectType)) - { - throw new GameFrameworkException(Utility.Text.Format("Object type '{0}' is invalid.", objectType.FullName)); - } - - return InternalGetObjectPool(new TypeNamePair(objectType, name)); + ValidateObjectType(objectType); + return InternalGet(new TypeNamePair(objectType, name)); } - /// - /// 获取对象池。 - /// - /// 要检查的条件。 - /// 要获取的对象池。 - public ObjectPoolBase GetObjectPool(Predicate condition) + // ========== GetAll ========== + + public ObjectPoolBase[] GetAllObjectPools() => m_ObjectPoolList.ToArray(); + + public ObjectPoolBase[] GetAllObjectPools(bool sort) { - if (condition == null) - { - throw new GameFrameworkException("Condition is invalid."); - } - - for (int i = 0; i < m_ObjectPoolList.Count; i++) - { - if (condition(m_ObjectPoolList[i])) - { - return m_ObjectPoolList[i]; - } - } - - return null; - } - - /// - /// 获取对象池。 - /// - /// 要检查的条件。 - /// 要获取的对象池。 - public ObjectPoolBase[] GetObjectPools(Predicate condition) - { - if (condition == null) - { - throw new GameFrameworkException("Condition is invalid."); - } - - List results = new List(); - for (int i = 0; i < m_ObjectPoolList.Count; i++) - { - if (condition(m_ObjectPoolList[i])) - { - results.Add(m_ObjectPoolList[i]); - } - } - + if (!sort) return m_ObjectPoolList.ToArray(); + var results = new List(m_ObjectPoolList); + results.Sort(m_ObjectPoolComparer); return results.ToArray(); } - /// - /// 获取对象池。 - /// - /// 要检查的条件。 - /// 要获取的对象池。 - public void GetObjectPools(Predicate condition, List results) - { - if (condition == null) - { - throw new GameFrameworkException("Condition is invalid."); - } + public void GetAllObjectPools(List results) => GetAllObjectPools(false, results); - if (results == null) - { - throw new GameFrameworkException("Results is invalid."); - } - - results.Clear(); - for (int i = 0; i < m_ObjectPoolList.Count; i++) - { - if (condition(m_ObjectPoolList[i])) - { - results.Add(m_ObjectPoolList[i]); - } - } - } - - /// - /// 获取所有对象池。 - /// - /// 所有对象池。 - public ObjectPoolBase[] GetAllObjectPools() - { - return GetAllObjectPools(false); - } - - /// - /// 获取所有对象池。 - /// - /// 所有对象池。 - public void GetAllObjectPools(List results) - { - GetAllObjectPools(false, results); - } - - /// - /// 获取所有对象池。 - /// - /// 是否根据对象池的优先级排序。 - /// 所有对象池。 - public ObjectPoolBase[] GetAllObjectPools(bool sort) - { - if (sort) - { - List results = new List(m_ObjectPoolList); - results.Sort(m_ObjectPoolComparer); - return results.ToArray(); - } - else - { - return m_ObjectPoolList.ToArray(); - } - } - - /// - /// 获取所有对象池。 - /// - /// 是否根据对象池的优先级排序。 - /// 所有对象池。 public void GetAllObjectPools(bool sort, List results) { - if (results == null) - { - throw new GameFrameworkException("Results is invalid."); - } - + if (results == null) throw new GameFrameworkException("Results is invalid."); results.Clear(); results.AddRange(m_ObjectPoolList); - - if (sort) - { - results.Sort(m_ObjectPoolComparer); - } + if (sort) results.Sort(m_ObjectPoolComparer); } + // ========== Create (single entry point) ========== + public IObjectPool CreatePool(ObjectPoolCreateOptions options = default) where T : ObjectBase { - return InternalCreateObjectPool( - options.Name, + var key = new TypeNamePair(typeof(T), options.Name); + if (m_ObjectPools.ContainsKey(key)) + throw new GameFrameworkException($"Already exist object pool '{key}'."); + + var pool = new ObjectPool( + options.Name ?? string.Empty, options.AllowMultiSpawn, - NormalizeAutoReleaseInterval(options.AutoReleaseInterval), - NormalizeCapacity(options.Capacity), - NormalizeExpireTime(options.ExpireTime), + options.AutoReleaseInterval ?? DefaultExpireTime, + options.Capacity ?? DefaultCapacity, + options.ExpireTime ?? DefaultExpireTime, options.Priority); + + m_ObjectPools.Add(key, pool); + m_ObjectPoolList.Add(pool); + return pool; } public ObjectPoolBase CreatePool(Type objectType, ObjectPoolCreateOptions options = default) { - return InternalCreateObjectPool( - objectType, - options.Name, + ValidateObjectType(objectType); + var key = new TypeNamePair(objectType, options.Name); + if (m_ObjectPools.ContainsKey(key)) + throw new GameFrameworkException($"Already exist object pool '{key}'."); + + var poolType = typeof(ObjectPool<>).MakeGenericType(objectType); + var pool = (ObjectPoolBase)Activator.CreateInstance(poolType, + options.Name ?? string.Empty, options.AllowMultiSpawn, - NormalizeAutoReleaseInterval(options.AutoReleaseInterval), - NormalizeCapacity(options.Capacity), - NormalizeExpireTime(options.ExpireTime), + options.AutoReleaseInterval ?? DefaultExpireTime, + options.Capacity ?? DefaultCapacity, + options.ExpireTime ?? DefaultExpireTime, options.Priority); + + m_ObjectPools.Add(key, pool); + m_ObjectPoolList.Add(pool); + return pool; } - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 要创建的允许单次获取的对象池。 - public IObjectPool CreateSingleSpawnObjectPool() where T : ObjectBase - { - return InternalCreateObjectPool(string.Empty, false, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority); - } + // ========== Destroy ========== - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 要创建的允许单次获取的对象池。 - public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType) - { - return InternalCreateObjectPool(objectType, string.Empty, false, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 要创建的允许单次获取的对象池。 - public IObjectPool CreateSingleSpawnObjectPool(string name) where T : ObjectBase - { - return InternalCreateObjectPool(name, false, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 要创建的允许单次获取的对象池。 - public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name) - { - return InternalCreateObjectPool(objectType, name, false, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池的容量。 - /// 要创建的允许单次获取的对象池。 - public IObjectPool CreateSingleSpawnObjectPool(int capacity) where T : ObjectBase - { - return InternalCreateObjectPool(string.Empty, false, DefaultExpireTime, capacity, DefaultExpireTime, DefaultPriority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池的容量。 - /// 要创建的允许单次获取的对象池。 - public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity) - { - return InternalCreateObjectPool(objectType, string.Empty, false, DefaultExpireTime, capacity, DefaultExpireTime, DefaultPriority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池对象过期秒数。 - /// 要创建的允许单次获取的对象池。 - public IObjectPool CreateSingleSpawnObjectPool(float expireTime) where T : ObjectBase - { - return InternalCreateObjectPool(string.Empty, false, expireTime, DefaultCapacity, expireTime, DefaultPriority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池对象过期秒数。 - /// 要创建的允许单次获取的对象池。 - public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, float expireTime) - { - return InternalCreateObjectPool(objectType, string.Empty, false, expireTime, DefaultCapacity, expireTime, DefaultPriority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池的容量。 - /// 要创建的允许单次获取的对象池。 - public IObjectPool CreateSingleSpawnObjectPool(string name, int capacity) where T : ObjectBase - { - return InternalCreateObjectPool(name, false, DefaultExpireTime, capacity, DefaultExpireTime, DefaultPriority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池的容量。 - /// 要创建的允许单次获取的对象池。 - public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity) - { - return InternalCreateObjectPool(objectType, name, false, DefaultExpireTime, capacity, DefaultExpireTime, DefaultPriority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池对象过期秒数。 - /// 要创建的允许单次获取的对象池。 - public IObjectPool CreateSingleSpawnObjectPool(string name, float expireTime) where T : ObjectBase - { - return InternalCreateObjectPool(name, false, expireTime, DefaultCapacity, expireTime, DefaultPriority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池对象过期秒数。 - /// 要创建的允许单次获取的对象池。 - public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, float expireTime) - { - return InternalCreateObjectPool(objectType, name, false, expireTime, DefaultCapacity, expireTime, DefaultPriority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池的容量。 - /// 对象池对象过期秒数。 - /// 要创建的允许单次获取的对象池。 - public IObjectPool CreateSingleSpawnObjectPool(int capacity, float expireTime) where T : ObjectBase - { - return InternalCreateObjectPool(string.Empty, false, expireTime, capacity, expireTime, DefaultPriority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池的容量。 - /// 对象池对象过期秒数。 - /// 要创建的允许单次获取的对象池。 - public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity, float expireTime) - { - return InternalCreateObjectPool(objectType, string.Empty, false, expireTime, capacity, expireTime, DefaultPriority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池的容量。 - /// 对象池的优先级。 - /// 要创建的允许单次获取的对象池。 - public IObjectPool CreateSingleSpawnObjectPool(int capacity, int priority) where T : ObjectBase - { - return InternalCreateObjectPool(string.Empty, false, DefaultExpireTime, capacity, DefaultExpireTime, priority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池的容量。 - /// 对象池的优先级。 - /// 要创建的允许单次获取的对象池。 - public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity, int priority) - { - return InternalCreateObjectPool(objectType, string.Empty, false, DefaultExpireTime, capacity, DefaultExpireTime, priority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池对象过期秒数。 - /// 对象池的优先级。 - /// 要创建的允许单次获取的对象池。 - public IObjectPool CreateSingleSpawnObjectPool(float expireTime, int priority) where T : ObjectBase - { - return InternalCreateObjectPool(string.Empty, false, expireTime, DefaultCapacity, expireTime, priority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池对象过期秒数。 - /// 对象池的优先级。 - /// 要创建的允许单次获取的对象池。 - public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, float expireTime, int priority) - { - return InternalCreateObjectPool(objectType, string.Empty, false, expireTime, DefaultCapacity, expireTime, priority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池的容量。 - /// 对象池对象过期秒数。 - /// 要创建的允许单次获取的对象池。 - public IObjectPool CreateSingleSpawnObjectPool(string name, int capacity, float expireTime) where T : ObjectBase - { - return InternalCreateObjectPool(name, false, expireTime, capacity, expireTime, DefaultPriority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池的容量。 - /// 对象池对象过期秒数。 - /// 要创建的允许单次获取的对象池。 - public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity, float expireTime) - { - return InternalCreateObjectPool(objectType, name, false, expireTime, capacity, expireTime, DefaultPriority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池的容量。 - /// 对象池的优先级。 - /// 要创建的允许单次获取的对象池。 - public IObjectPool CreateSingleSpawnObjectPool(string name, int capacity, int priority) where T : ObjectBase - { - return InternalCreateObjectPool(name, false, DefaultExpireTime, capacity, DefaultExpireTime, priority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池的容量。 - /// 对象池的优先级。 - /// 要创建的允许单次获取的对象池。 - public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity, int priority) - { - return InternalCreateObjectPool(objectType, name, false, DefaultExpireTime, capacity, DefaultExpireTime, priority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池对象过期秒数。 - /// 对象池的优先级。 - /// 要创建的允许单次获取的对象池。 - public IObjectPool CreateSingleSpawnObjectPool(string name, float expireTime, int priority) where T : ObjectBase - { - return InternalCreateObjectPool(name, false, expireTime, DefaultCapacity, expireTime, priority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池对象过期秒数。 - /// 对象池的优先级。 - /// 要创建的允许单次获取的对象池。 - public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, float expireTime, int priority) - { - return InternalCreateObjectPool(objectType, name, false, expireTime, DefaultCapacity, expireTime, priority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池的容量。 - /// 对象池对象过期秒数。 - /// 对象池的优先级。 - /// 要创建的允许单次获取的对象池。 - public IObjectPool CreateSingleSpawnObjectPool(int capacity, float expireTime, int priority) where T : ObjectBase - { - return InternalCreateObjectPool(string.Empty, false, expireTime, capacity, expireTime, priority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池的容量。 - /// 对象池对象过期秒数。 - /// 对象池的优先级。 - /// 要创建的允许单次获取的对象池。 - public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity, float expireTime, int priority) - { - return InternalCreateObjectPool(objectType, string.Empty, false, expireTime, capacity, expireTime, priority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池的容量。 - /// 对象池对象过期秒数。 - /// 对象池的优先级。 - /// 要创建的允许单次获取的对象池。 - public IObjectPool CreateSingleSpawnObjectPool(string name, int capacity, float expireTime, int priority) where T : ObjectBase - { - return InternalCreateObjectPool(name, false, expireTime, capacity, expireTime, priority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池的容量。 - /// 对象池对象过期秒数。 - /// 对象池的优先级。 - /// 要创建的允许单次获取的对象池。 - public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity, float expireTime, int priority) - { - return InternalCreateObjectPool(objectType, name, false, expireTime, capacity, expireTime, priority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池自动释放可释放对象的间隔秒数。 - /// 对象池的容量。 - /// 对象池对象过期秒数。 - /// 对象池的优先级。 - /// 要创建的允许单次获取的对象池。 - public IObjectPool CreateSingleSpawnObjectPool(string name, float autoReleaseInterval, int capacity, float expireTime, int priority) where T : ObjectBase - { - return InternalCreateObjectPool(name, false, autoReleaseInterval, capacity, expireTime, priority); - } - - /// - /// 创建允许单次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池自动释放可释放对象的间隔秒数。 - /// 对象池的容量。 - /// 对象池对象过期秒数。 - /// 对象池的优先级。 - /// 要创建的允许单次获取的对象池。 - public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, float autoReleaseInterval, int capacity, float expireTime, int priority) - { - return InternalCreateObjectPool(objectType, name, false, autoReleaseInterval, capacity, expireTime, priority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 要创建的允许多次获取的对象池。 - public IObjectPool CreateMultiSpawnObjectPool() where T : ObjectBase - { - return InternalCreateObjectPool(string.Empty, true, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 要创建的允许多次获取的对象池。 - public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType) - { - return InternalCreateObjectPool(objectType, string.Empty, true, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 要创建的允许多次获取的对象池。 - public IObjectPool CreateMultiSpawnObjectPool(string name) where T : ObjectBase - { - return InternalCreateObjectPool(name, true, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 要创建的允许多次获取的对象池。 - public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name) - { - return InternalCreateObjectPool(objectType, name, true, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池的容量。 - /// 要创建的允许多次获取的对象池。 - public IObjectPool CreateMultiSpawnObjectPool(int capacity) where T : ObjectBase - { - return InternalCreateObjectPool(string.Empty, true, DefaultExpireTime, capacity, DefaultExpireTime, DefaultPriority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池的容量。 - /// 要创建的允许多次获取的对象池。 - public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity) - { - return InternalCreateObjectPool(objectType, string.Empty, true, DefaultExpireTime, capacity, DefaultExpireTime, DefaultPriority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池对象过期秒数。 - /// 要创建的允许多次获取的对象池。 - public IObjectPool CreateMultiSpawnObjectPool(float expireTime) where T : ObjectBase - { - return InternalCreateObjectPool(string.Empty, true, expireTime, DefaultCapacity, expireTime, DefaultPriority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池对象过期秒数。 - /// 要创建的允许多次获取的对象池。 - public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, float expireTime) - { - return InternalCreateObjectPool(objectType, string.Empty, true, expireTime, DefaultCapacity, expireTime, DefaultPriority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池的容量。 - /// 要创建的允许多次获取的对象池。 - public IObjectPool CreateMultiSpawnObjectPool(string name, int capacity) where T : ObjectBase - { - return InternalCreateObjectPool(name, true, DefaultExpireTime, capacity, DefaultExpireTime, DefaultPriority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池的容量。 - /// 要创建的允许多次获取的对象池。 - public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity) - { - return InternalCreateObjectPool(objectType, name, true, DefaultExpireTime, capacity, DefaultExpireTime, DefaultPriority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池对象过期秒数。 - /// 要创建的允许多次获取的对象池。 - public IObjectPool CreateMultiSpawnObjectPool(string name, float expireTime) where T : ObjectBase - { - return InternalCreateObjectPool(name, true, expireTime, DefaultCapacity, expireTime, DefaultPriority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池对象过期秒数。 - /// 要创建的允许多次获取的对象池。 - public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, float expireTime) - { - return InternalCreateObjectPool(objectType, name, true, expireTime, DefaultCapacity, expireTime, DefaultPriority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池的容量。 - /// 对象池对象过期秒数。 - /// 要创建的允许多次获取的对象池。 - public IObjectPool CreateMultiSpawnObjectPool(int capacity, float expireTime) where T : ObjectBase - { - return InternalCreateObjectPool(string.Empty, true, expireTime, capacity, expireTime, DefaultPriority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池的容量。 - /// 对象池对象过期秒数。 - /// 要创建的允许多次获取的对象池。 - public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity, float expireTime) - { - return InternalCreateObjectPool(objectType, string.Empty, true, expireTime, capacity, expireTime, DefaultPriority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池的容量。 - /// 对象池的优先级。 - /// 要创建的允许多次获取的对象池。 - public IObjectPool CreateMultiSpawnObjectPool(int capacity, int priority) where T : ObjectBase - { - return InternalCreateObjectPool(string.Empty, true, DefaultExpireTime, capacity, DefaultExpireTime, priority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池的容量。 - /// 对象池的优先级。 - /// 要创建的允许多次获取的对象池。 - public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity, int priority) - { - return InternalCreateObjectPool(objectType, string.Empty, true, DefaultExpireTime, capacity, DefaultExpireTime, priority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池对象过期秒数。 - /// 对象池的优先级。 - /// 要创建的允许多次获取的对象池。 - public IObjectPool CreateMultiSpawnObjectPool(float expireTime, int priority) where T : ObjectBase - { - return InternalCreateObjectPool(string.Empty, true, expireTime, DefaultCapacity, expireTime, priority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池对象过期秒数。 - /// 对象池的优先级。 - /// 要创建的允许多次获取的对象池。 - public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, float expireTime, int priority) - { - return InternalCreateObjectPool(objectType, string.Empty, true, expireTime, DefaultCapacity, expireTime, priority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池的容量。 - /// 对象池对象过期秒数。 - /// 要创建的允许多次获取的对象池。 - public IObjectPool CreateMultiSpawnObjectPool(string name, int capacity, float expireTime) where T : ObjectBase - { - return InternalCreateObjectPool(name, true, expireTime, capacity, expireTime, DefaultPriority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池的容量。 - /// 对象池对象过期秒数。 - /// 要创建的允许多次获取的对象池。 - public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity, float expireTime) - { - return InternalCreateObjectPool(objectType, name, true, expireTime, capacity, expireTime, DefaultPriority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池的容量。 - /// 对象池的优先级。 - /// 要创建的允许多次获取的对象池。 - public IObjectPool CreateMultiSpawnObjectPool(string name, int capacity, int priority) where T : ObjectBase - { - return InternalCreateObjectPool(name, true, DefaultExpireTime, capacity, DefaultExpireTime, priority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池的容量。 - /// 对象池的优先级。 - /// 要创建的允许多次获取的对象池。 - public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity, int priority) - { - return InternalCreateObjectPool(objectType, name, true, DefaultExpireTime, capacity, DefaultExpireTime, priority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池对象过期秒数。 - /// 对象池的优先级。 - /// 要创建的允许多次获取的对象池。 - public IObjectPool CreateMultiSpawnObjectPool(string name, float expireTime, int priority) where T : ObjectBase - { - return InternalCreateObjectPool(name, true, expireTime, DefaultCapacity, expireTime, priority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池对象过期秒数。 - /// 对象池的优先级。 - /// 要创建的允许多次获取的对象池。 - public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, float expireTime, int priority) - { - return InternalCreateObjectPool(objectType, name, true, expireTime, DefaultCapacity, expireTime, priority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池的容量。 - /// 对象池对象过期秒数。 - /// 对象池的优先级。 - /// 要创建的允许多次获取的对象池。 - public IObjectPool CreateMultiSpawnObjectPool(int capacity, float expireTime, int priority) where T : ObjectBase - { - return InternalCreateObjectPool(string.Empty, true, expireTime, capacity, expireTime, priority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池的容量。 - /// 对象池对象过期秒数。 - /// 对象池的优先级。 - /// 要创建的允许多次获取的对象池。 - public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity, float expireTime, int priority) - { - return InternalCreateObjectPool(objectType, string.Empty, true, expireTime, capacity, expireTime, priority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池的容量。 - /// 对象池对象过期秒数。 - /// 对象池的优先级。 - /// 要创建的允许多次获取的对象池。 - public IObjectPool CreateMultiSpawnObjectPool(string name, int capacity, float expireTime, int priority) where T : ObjectBase - { - return InternalCreateObjectPool(name, true, expireTime, capacity, expireTime, priority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池的容量。 - /// 对象池对象过期秒数。 - /// 对象池的优先级。 - /// 要创建的允许多次获取的对象池。 - public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity, float expireTime, int priority) - { - return InternalCreateObjectPool(objectType, name, true, expireTime, capacity, expireTime, priority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池自动释放可释放对象的间隔秒数。 - /// 对象池的容量。 - /// 对象池对象过期秒数。 - /// 对象池的优先级。 - /// 要创建的允许多次获取的对象池。 - public IObjectPool CreateMultiSpawnObjectPool(string name, float autoReleaseInterval, int capacity, float expireTime, int priority) where T : ObjectBase - { - return InternalCreateObjectPool(name, true, autoReleaseInterval, capacity, expireTime, priority); - } - - /// - /// 创建允许多次获取的对象池。 - /// - /// 对象类型。 - /// 对象池名称。 - /// 对象池自动释放可释放对象的间隔秒数。 - /// 对象池的容量。 - /// 对象池对象过期秒数。 - /// 对象池的优先级。 - /// 要创建的允许多次获取的对象池。 - public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, float autoReleaseInterval, int capacity, float expireTime, int priority) - { - return InternalCreateObjectPool(objectType, name, true, autoReleaseInterval, capacity, expireTime, priority); - } - - /// - /// 销毁对象池。 - /// - /// 对象类型。 - /// 是否销毁对象池成功。 public bool DestroyObjectPool() where T : ObjectBase - { - return InternalDestroyObjectPool(new TypeNamePair(typeof(T))); - } + => InternalDestroy(new TypeNamePair(typeof(T))); + + public bool DestroyObjectPool(string name) where T : ObjectBase + => InternalDestroy(new TypeNamePair(typeof(T), name)); - /// - /// 销毁对象池。 - /// - /// 对象类型。 - /// 是否销毁对象池成功。 public bool DestroyObjectPool(Type objectType) { - if (objectType == null) - { - throw new GameFrameworkException("Object type is invalid."); - } - - if (!typeof(ObjectBase).IsAssignableFrom(objectType)) - { - throw new GameFrameworkException(Utility.Text.Format("Object type '{0}' is invalid.", objectType.FullName)); - } - - return InternalDestroyObjectPool(new TypeNamePair(objectType)); + ValidateObjectType(objectType); + return InternalDestroy(new TypeNamePair(objectType)); } - /// - /// 销毁对象池。 - /// - /// 对象类型。 - /// 要销毁的对象池名称。 - /// 是否销毁对象池成功。 - public bool DestroyObjectPool(string name) where T : ObjectBase - { - return InternalDestroyObjectPool(new TypeNamePair(typeof(T), name)); - } - - /// - /// 销毁对象池。 - /// - /// 对象类型。 - /// 要销毁的对象池名称。 - /// 是否销毁对象池成功。 public bool DestroyObjectPool(Type objectType, string name) { - if (objectType == null) - { - throw new GameFrameworkException("Object type is invalid."); - } - - if (!typeof(ObjectBase).IsAssignableFrom(objectType)) - { - throw new GameFrameworkException(Utility.Text.Format("Object type '{0}' is invalid.", objectType.FullName)); - } - - return InternalDestroyObjectPool(new TypeNamePair(objectType, name)); + ValidateObjectType(objectType); + return InternalDestroy(new TypeNamePair(objectType, name)); } - /// - /// 销毁对象池。 - /// - /// 对象类型。 - /// 要销毁的对象池。 - /// 是否销毁对象池成功。 public bool DestroyObjectPool(IObjectPool objectPool) where T : ObjectBase { - if (objectPool == null) - { - throw new GameFrameworkException("Object pool is invalid."); - } - - return InternalDestroyObjectPool(new TypeNamePair(typeof(T), objectPool.Name)); + if (objectPool == null) throw new GameFrameworkException("Object pool is invalid."); + return InternalDestroy(new TypeNamePair(typeof(T), objectPool.Name)); } - /// - /// 销毁对象池。 - /// - /// 要销毁的对象池。 - /// 是否销毁对象池成功。 public bool DestroyObjectPool(ObjectPoolBase objectPool) { - if (objectPool == null) - { - throw new GameFrameworkException("Object pool is invalid."); - } - - return InternalDestroyObjectPool(new TypeNamePair(objectPool.ObjectType, objectPool.Name)); + if (objectPool == null) throw new GameFrameworkException("Object pool is invalid."); + return InternalDestroy(new TypeNamePair(objectPool.ObjectType, objectPool.Name)); } - /// - /// 释放对象池中的可释放对象。 - /// + // ========== Release ========== + public void Release() { GetAllObjectPools(true, m_CachedAllObjectPools); - foreach (ObjectPoolBase objectPool in m_CachedAllObjectPools) - { - objectPool.Release(); - } + for (int i = 0; i < m_CachedAllObjectPools.Count; i++) + m_CachedAllObjectPools[i].Release(); } - /// - /// 释放对象池中的所有未使用对象。 - /// public void ReleaseAllUnused() { GetAllObjectPools(true, m_CachedAllObjectPools); - foreach (ObjectPoolBase objectPool in m_CachedAllObjectPools) + for (int i = 0; i < m_CachedAllObjectPools.Count; i++) + m_CachedAllObjectPools[i].ReleaseAllUnused(); + } + + // ========== Low memory ========== + + public void OnLowMemory() + { + for (int i = 0; i < m_ObjectPoolList.Count; i++) + m_ObjectPoolList[i].OnLowMemory(); + } + + // ========== Internal ========== + + private ObjectPoolBase InternalGet(TypeNamePair key) + { + m_ObjectPools.TryGetValue(key, out var pool); + return pool; + } + + private bool InternalDestroy(TypeNamePair key) + { + if (m_ObjectPools.TryGetValue(key, out var pool)) { - objectPool.ReleaseAllUnused(); + pool.Shutdown(); + m_ObjectPoolList.Remove(pool); + return m_ObjectPools.Remove(key); } - } - - private bool InternalHasObjectPool(TypeNamePair typeNamePair) - { - return m_ObjectPools.ContainsKey(typeNamePair); - } - - private static float NormalizeAutoReleaseInterval(float autoReleaseInterval) - { - return autoReleaseInterval == default ? DefaultExpireTime : autoReleaseInterval; - } - - private static int NormalizeCapacity(int capacity) - { - return capacity == default ? DefaultCapacity : capacity; - } - - private static float NormalizeExpireTime(float expireTime) - { - return expireTime == default ? DefaultExpireTime : expireTime; - } - - private ObjectPoolBase InternalGetObjectPool(TypeNamePair typeNamePair) - { - ObjectPoolBase objectPool = null; - if (m_ObjectPools.TryGetValue(typeNamePair, out objectPool)) - { - return objectPool; - } - - return null; - } - - private IObjectPool InternalCreateObjectPool(string name, bool allowMultiSpawn, float autoReleaseInterval, int capacity, float expireTime, int priority) where T : ObjectBase - { - TypeNamePair typeNamePair = new TypeNamePair(typeof(T), name); - if (HasObjectPool(name)) - { - throw new GameFrameworkException(Utility.Text.Format("Already exist object pool '{0}'.", typeNamePair)); - } - - ObjectPool objectPool = new ObjectPool(name, allowMultiSpawn, autoReleaseInterval, capacity, expireTime, priority); - m_ObjectPools.Add(typeNamePair, objectPool); - m_ObjectPoolList.Add(objectPool); - return objectPool; - } - - private ObjectPoolBase InternalCreateObjectPool(Type objectType, string name, bool allowMultiSpawn, float autoReleaseInterval, int capacity, float expireTime, int priority) - { - if (objectType == null) - { - throw new GameFrameworkException("Object type is invalid."); - } - - if (!typeof(ObjectBase).IsAssignableFrom(objectType)) - { - throw new GameFrameworkException(Utility.Text.Format("Object type '{0}' is invalid.", objectType.FullName)); - } - - TypeNamePair typeNamePair = new TypeNamePair(objectType, name); - if (HasObjectPool(objectType, name)) - { - throw new GameFrameworkException(Utility.Text.Format("Already exist object pool '{0}'.", typeNamePair)); - } - - Type objectPoolType = typeof(ObjectPool<>).MakeGenericType(objectType); - ObjectPoolBase objectPool = (ObjectPoolBase)Activator.CreateInstance(objectPoolType, name, allowMultiSpawn, autoReleaseInterval, capacity, expireTime, priority); - m_ObjectPools.Add(typeNamePair, objectPool); - m_ObjectPoolList.Add(objectPool); - return objectPool; - } - - private bool InternalDestroyObjectPool(TypeNamePair typeNamePair) - { - ObjectPoolBase objectPool = null; - if (m_ObjectPools.TryGetValue(typeNamePair, out objectPool)) - { - objectPool.Shutdown(); - m_ObjectPoolList.Remove(objectPool); - return m_ObjectPools.Remove(typeNamePair); - } - return false; } - private static int ObjectPoolComparer(ObjectPoolBase a, ObjectPoolBase b) + private static void ValidateObjectType(Type objectType) { - return a.Priority.CompareTo(b.Priority); + if (objectType == null) + throw new GameFrameworkException("Object type is invalid."); + if (!typeof(ObjectBase).IsAssignableFrom(objectType)) + throw new GameFrameworkException($"Object type '{objectType.FullName}' is invalid."); } + + private static int ObjectPoolComparer(ObjectPoolBase a, ObjectPoolBase b) + => a.Priority.CompareTo(b.Priority); } } diff --git a/Runtime/ABase/ObjectPool/ReleaseObjectFilterCallback.cs b/Runtime/ABase/ObjectPool/ReleaseObjectFilterCallback.cs deleted file mode 100644 index 8a7f7ff..0000000 --- a/Runtime/ABase/ObjectPool/ReleaseObjectFilterCallback.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace AlicizaX.ObjectPool -{ - /// - /// 释放对象筛选函数。 - /// - /// 对象类型。 - /// 要筛选的对象集合。 - /// 需要释放的对象数量。 - /// 对象过期参考时间。 - /// 经筛选需要释放的对象集合。 - public delegate List ReleaseObjectFilterCallback(List candidateObjects, int toReleaseCount, DateTime expireTime) where T : ObjectBase; -} diff --git a/Runtime/ABase/ObjectPool/ReleaseObjectFilterCallback.cs.meta b/Runtime/ABase/ObjectPool/ReleaseObjectFilterCallback.cs.meta deleted file mode 100644 index 06edf9e..0000000 --- a/Runtime/ABase/ObjectPool/ReleaseObjectFilterCallback.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 7109de176e3874b1d863ca0d2cdba894 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Debugger/DebuggerComponent.ObjectPoolInformationWindow.cs b/Runtime/Debugger/DebuggerComponent.ObjectPoolInformationWindow.cs index f8ed6e8..e94bac4 100644 --- a/Runtime/Debugger/DebuggerComponent.ObjectPoolInformationWindow.cs +++ b/Runtime/Debugger/DebuggerComponent.ObjectPoolInformationWindow.cs @@ -36,7 +36,6 @@ namespace AlicizaX.Debugger.Runtime card.Add(CreateRow("Auto Release Interval", objectPool.AutoReleaseInterval.ToString())); card.Add(CreateRow("Capacity", objectPool.Capacity.ToString())); card.Add(CreateRow("Used Count", objectPool.Count.ToString())); - card.Add(CreateRow("Can Release Count", objectPool.CanReleaseCount.ToString())); card.Add(CreateRow("Expire Time", objectPool.ExpireTime.ToString())); card.Add(CreateRow("Priority", objectPool.Priority.ToString())); @@ -52,13 +51,12 @@ namespace AlicizaX.Debugger.Runtime ObjectInfo info = objectInfos[j]; string title = string.IsNullOrEmpty(info.Name) ? "" : info.Name; string content = Utility.Text.Format( - "Locked {0} | {1} {2} | Flag {3} | Priority {4} | Last Use {5}", + "Locked {0} | {1} {2} | Flag {3} | Last Use {4}", info.Locked, objectPool.AllowMultiSpawn ? "Count" : "InUse", objectPool.AllowMultiSpawn ? info.SpawnCount.ToString() : info.IsInUse.ToString(), info.CustomCanReleaseFlag, - info.Priority, - info.LastUseTime.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss")); + Utility.Text.Format("{0:F1}s ago", Time.realtimeSinceStartup - info.LastUseTime)); card.Add(CreateRow(title, content)); } } diff --git a/Runtime/Resource/Resource/Extension/AssetItemObject.cs b/Runtime/Resource/Resource/Extension/AssetItemObject.cs index fb38326..38557dd 100644 --- a/Runtime/Resource/Resource/Extension/AssetItemObject.cs +++ b/Runtime/Resource/Resource/Extension/AssetItemObject.cs @@ -15,12 +15,7 @@ namespace AlicizaX.Resource.Runtime protected internal override void Release(bool isShutdown) { - if (Target == null) - { - return; - } - - AppServices.Require().UnloadAsset(Target); + // Asset handle cleanup is owned by ResourceExtComponent/ResourceService. } } } diff --git a/Runtime/Resource/Resource/Extension/ResourceExtComponent.cs b/Runtime/Resource/Resource/Extension/ResourceExtComponent.cs index 45becb8..b68fbe7 100644 --- a/Runtime/Resource/Resource/Extension/ResourceExtComponent.cs +++ b/Runtime/Resource/Resource/Extension/ResourceExtComponent.cs @@ -204,9 +204,10 @@ namespace AlicizaX.Resource.Runtime _trackedAssetNodes.Remove(trackedObject); } - if (releaseAsset && node.Value.AssetTarget != null && _assetItemPool != null) + if (releaseAsset && node.Value.AssetTarget != null) { - _assetItemPool.Unspawn(node.Value.AssetTarget); + _resourceService?.UnloadAsset(node.Value.AssetTarget); + _assetItemPool?.Unspawn(node.Value.AssetTarget); } if (node.Value.AssetObject != null) diff --git a/Runtime/Resource/Resource/ResourceService.AssetObject.cs b/Runtime/Resource/Resource/ResourceService.AssetObject.cs index 5a8d1d6..9eeeda0 100644 --- a/Runtime/Resource/Resource/ResourceService.AssetObject.cs +++ b/Runtime/Resource/Resource/ResourceService.AssetObject.cs @@ -14,7 +14,6 @@ namespace AlicizaX.Resource.Runtime private sealed class AssetObject : ObjectBase { private AssetHandle m_AssetHandle; - private IResourceService _resourceService; public AssetObject() @@ -22,22 +21,16 @@ namespace AlicizaX.Resource.Runtime m_AssetHandle = null; } - public static AssetObject Create(string name, object target, object assetHandle, IResourceService resourceService) + public static AssetObject Create(string name, object target, object assetHandle) { if (assetHandle == null) { throw new GameFrameworkException("Resource is invalid."); } - if (resourceService == null) - { - throw new GameFrameworkException("Resource Manager is invalid."); - } - AssetObject assetObject = MemoryPool.Acquire(); assetObject.Initialize(name, target); assetObject.m_AssetHandle = (AssetHandle)assetHandle; - assetObject._resourceService = resourceService; return assetObject; } @@ -61,7 +54,6 @@ namespace AlicizaX.Resource.Runtime { handle.Dispose(); } - handle = null; } } } diff --git a/Runtime/Resource/Resource/ResourceService.cs b/Runtime/Resource/Resource/ResourceService.cs index eb148b1..1efaa98 100644 --- a/Runtime/Resource/Resource/ResourceService.cs +++ b/Runtime/Resource/Resource/ResourceService.cs @@ -601,7 +601,7 @@ namespace AlicizaX.Resource.Runtime T ret = handle.AssetObject as T; - assetObject = AssetObject.Create(assetObjectKey, handle.AssetObject, handle, this); + assetObject = AssetObject.Create(assetObjectKey, handle.AssetObject, handle); _assetPool.Register(assetObject, true); return ret; @@ -631,7 +631,7 @@ namespace AlicizaX.Resource.Runtime GameObject gameObject = AssetsReference.Instantiate(handle.AssetObject as GameObject, parent, this).gameObject; - assetObject = AssetObject.Create(assetObjectKey, handle.AssetObject, handle, this); + assetObject = AssetObject.Create(assetObjectKey, handle.AssetObject, handle); _assetPool.Register(assetObject, true); return gameObject; @@ -951,7 +951,7 @@ namespace AlicizaX.Resource.Runtime throw new GameFrameworkException(Utility.Text.Format("Can not load asset '{0}'.", location)); } - var assetObject = AssetObject.Create(assetObjectKey, handle.AssetObject, handle, this); + var assetObject = AssetObject.Create(assetObjectKey, handle.AssetObject, handle); _assetPool.Register(assetObject, true); CompleteLoading(assetObjectKey); return handle.AssetObject as UnityEngine.Object;