彻底重构ObjectPoolService模块

重构ObjectPoolService模块
去掉过度设计移除旧的容器列表
使用自定义Hash提高整体性能速度
单线程高吞吐
This commit is contained in:
陈思海 2026-04-22 13:04:31 +08:00
parent a08ef4be2e
commit e42be670fe
28 changed files with 873 additions and 3745 deletions

View File

@ -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) ? "<None>" : 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) ? "<None>" : objectInfo.Name,
string lastUse = Utility.Text.Format("{0:F1}s ago", UnityEngine.Time.realtimeSinceStartup - objectInfo.LastUseTime);
EditorGUILayout.LabelField(string.IsNullOrEmpty(objectInfo.Name) ? "<None>" : 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);

View File

@ -1,456 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace AlicizaX
{
/// <summary>
/// 游戏框架链表类。
/// </summary>
/// <typeparam name="T">指定链表的元素类型。</typeparam>
public sealed class GameFrameworkLinkedList<T> : ICollection<T>, IEnumerable<T>, ICollection, IEnumerable
{
private readonly LinkedList<T> m_LinkedList;
private readonly Queue<LinkedListNode<T>> m_CachedNodes;
/// <summary>
/// 初始化游戏框架链表类的新实例。
/// </summary>
public GameFrameworkLinkedList()
{
m_LinkedList = new LinkedList<T>();
m_CachedNodes = new Queue<LinkedListNode<T>>();
}
/// <summary>
/// 获取链表中实际包含的结点数量。
/// </summary>
public int Count
{
get
{
return m_LinkedList.Count;
}
}
/// <summary>
/// 获取链表结点缓存数量。
/// </summary>
public int CachedNodeCount
{
get
{
return m_CachedNodes.Count;
}
}
/// <summary>
/// 获取链表的第一个结点。
/// </summary>
public LinkedListNode<T> First
{
get
{
return m_LinkedList.First;
}
}
/// <summary>
/// 获取链表的最后一个结点。
/// </summary>
public LinkedListNode<T> Last
{
get
{
return m_LinkedList.Last;
}
}
/// <summary>
/// 获取一个值,该值指示 ICollection`1 是否为只读。
/// </summary>
public bool IsReadOnly
{
get
{
return ((ICollection<T>)m_LinkedList).IsReadOnly;
}
}
/// <summary>
/// 获取可用于同步对 ICollection 的访问的对象。
/// </summary>
public object SyncRoot
{
get
{
return ((ICollection)m_LinkedList).SyncRoot;
}
}
/// <summary>
/// 获取一个值,该值指示是否同步对 ICollection 的访问(线程安全)。
/// </summary>
public bool IsSynchronized
{
get
{
return ((ICollection)m_LinkedList).IsSynchronized;
}
}
/// <summary>
/// 在链表中指定的现有结点后添加包含指定值的新结点。
/// </summary>
/// <param name="node">指定的现有结点。</param>
/// <param name="value">指定值。</param>
/// <returns>包含指定值的新结点。</returns>
public LinkedListNode<T> AddAfter(LinkedListNode<T> node, T value)
{
LinkedListNode<T> newNode = AcquireNode(value);
m_LinkedList.AddAfter(node, newNode);
return newNode;
}
/// <summary>
/// 在链表中指定的现有结点后添加指定的新结点。
/// </summary>
/// <param name="node">指定的现有结点。</param>
/// <param name="newNode">指定的新结点。</param>
public void AddAfter(LinkedListNode<T> node, LinkedListNode<T> newNode)
{
m_LinkedList.AddAfter(node, newNode);
}
/// <summary>
/// 在链表中指定的现有结点前添加包含指定值的新结点。
/// </summary>
/// <param name="node">指定的现有结点。</param>
/// <param name="value">指定值。</param>
/// <returns>包含指定值的新结点。</returns>
public LinkedListNode<T> AddBefore(LinkedListNode<T> node, T value)
{
LinkedListNode<T> newNode = AcquireNode(value);
m_LinkedList.AddBefore(node, newNode);
return newNode;
}
/// <summary>
/// 在链表中指定的现有结点前添加指定的新结点。
/// </summary>
/// <param name="node">指定的现有结点。</param>
/// <param name="newNode">指定的新结点。</param>
public void AddBefore(LinkedListNode<T> node, LinkedListNode<T> newNode)
{
m_LinkedList.AddBefore(node, newNode);
}
/// <summary>
/// 在链表的开头处添加包含指定值的新结点。
/// </summary>
/// <param name="value">指定值。</param>
/// <returns>包含指定值的新结点。</returns>
public LinkedListNode<T> AddFirst(T value)
{
LinkedListNode<T> node = AcquireNode(value);
m_LinkedList.AddFirst(node);
return node;
}
/// <summary>
/// 在链表的开头处添加指定的新结点。
/// </summary>
/// <param name="node">指定的新结点。</param>
public void AddFirst(LinkedListNode<T> node)
{
m_LinkedList.AddFirst(node);
}
/// <summary>
/// 在链表的结尾处添加包含指定值的新结点。
/// </summary>
/// <param name="value">指定值。</param>
/// <returns>包含指定值的新结点。</returns>
public LinkedListNode<T> AddLast(T value)
{
LinkedListNode<T> node = AcquireNode(value);
m_LinkedList.AddLast(node);
return node;
}
/// <summary>
/// 在链表的结尾处添加指定的新结点。
/// </summary>
/// <param name="node">指定的新结点。</param>
public void AddLast(LinkedListNode<T> node)
{
m_LinkedList.AddLast(node);
}
/// <summary>
/// 从链表中移除所有结点。
/// </summary>
public void Clear()
{
LinkedListNode<T> current = m_LinkedList.First;
while (current != null)
{
ReleaseNode(current);
current = current.Next;
}
m_LinkedList.Clear();
}
/// <summary>
/// 清除链表结点缓存。
/// </summary>
public void ClearCachedNodes()
{
m_CachedNodes.Clear();
}
/// <summary>
/// 确定某值是否在链表中。
/// </summary>
/// <param name="value">指定值。</param>
/// <returns>某值是否在链表中。</returns>
public bool Contains(T value)
{
return m_LinkedList.Contains(value);
}
/// <summary>
/// 确定指定结点是否在链表中。
/// </summary>
/// <param name="node">要检查的结点。</param>
/// <returns>指定结点是否在链表中。</returns>
public bool Contains(LinkedListNode<T> node)
{
return node != null && node.List == m_LinkedList;
}
/// <summary>
/// 从目标数组的指定索引处开始将整个链表复制到兼容的一维数组。
/// </summary>
/// <param name="array">一维数组,它是从链表复制的元素的目标。数组必须具有从零开始的索引。</param>
/// <param name="index">array 中从零开始的索引,从此处开始复制。</param>
public void CopyTo(T[] array, int index)
{
m_LinkedList.CopyTo(array, index);
}
/// <summary>
/// 从特定的 ICollection 索引开始,将数组的元素复制到一个数组中。
/// </summary>
/// <param name="array">一维数组,它是从 ICollection 复制的元素的目标。数组必须具有从零开始的索引。</param>
/// <param name="index">array 中从零开始的索引,从此处开始复制。</param>
public void CopyTo(Array array, int index)
{
((ICollection)m_LinkedList).CopyTo(array, index);
}
/// <summary>
/// 查找包含指定值的第一个结点。
/// </summary>
/// <param name="value">要查找的指定值。</param>
/// <returns>包含指定值的第一个结点。</returns>
public LinkedListNode<T> Find(T value)
{
return m_LinkedList.Find(value);
}
/// <summary>
/// 查找包含指定值的最后一个结点。
/// </summary>
/// <param name="value">要查找的指定值。</param>
/// <returns>包含指定值的最后一个结点。</returns>
public LinkedListNode<T> FindLast(T value)
{
return m_LinkedList.FindLast(value);
}
/// <summary>
/// 从链表中移除指定值的第一个匹配项。
/// </summary>
/// <param name="value">指定值。</param>
/// <returns>是否移除成功。</returns>
public bool Remove(T value)
{
LinkedListNode<T> node = m_LinkedList.Find(value);
if (node != null)
{
m_LinkedList.Remove(node);
ReleaseNode(node);
return true;
}
return false;
}
/// <summary>
/// 从链表中移除指定的结点。
/// </summary>
/// <param name="node">指定的结点。</param>
public void Remove(LinkedListNode<T> node)
{
m_LinkedList.Remove(node);
ReleaseNode(node);
}
/// <summary>
/// 移除位于链表开头处的结点。
/// </summary>
public void RemoveFirst()
{
LinkedListNode<T> first = m_LinkedList.First;
if (first == null)
{
throw new GameFrameworkException("First is invalid.");
}
m_LinkedList.RemoveFirst();
ReleaseNode(first);
}
/// <summary>
/// 移除位于链表结尾处的结点。
/// </summary>
public void RemoveLast()
{
LinkedListNode<T> last = m_LinkedList.Last;
if (last == null)
{
throw new GameFrameworkException("Last is invalid.");
}
m_LinkedList.RemoveLast();
ReleaseNode(last);
}
/// <summary>
/// 返回循环访问集合的枚举数。
/// </summary>
/// <returns>循环访问集合的枚举数。</returns>
public Enumerator GetEnumerator()
{
return new Enumerator(m_LinkedList);
}
private LinkedListNode<T> AcquireNode(T value)
{
LinkedListNode<T> node = null;
if (m_CachedNodes.Count > 0)
{
node = m_CachedNodes.Dequeue();
node.Value = value;
}
else
{
node = new LinkedListNode<T>(value);
}
return node;
}
private void ReleaseNode(LinkedListNode<T> node)
{
node.Value = default(T);
m_CachedNodes.Enqueue(node);
}
/// <summary>
/// 将值添加到 ICollection`1 的结尾处。
/// </summary>
/// <param name="value">要添加的值。</param>
void ICollection<T>.Add(T value)
{
AddLast(value);
}
/// <summary>
/// 返回循环访问集合的枚举数。
/// </summary>
/// <returns>循环访问集合的枚举数。</returns>
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// 返回循环访问集合的枚举数。
/// </summary>
/// <returns>循环访问集合的枚举数。</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// 循环访问集合的枚举数。
/// </summary>
[StructLayout(LayoutKind.Auto)]
public struct Enumerator : IEnumerator<T>, IEnumerator
{
private LinkedList<T>.Enumerator m_Enumerator;
internal Enumerator(LinkedList<T> linkedList)
{
if (linkedList == null)
{
throw new GameFrameworkException("Linked list is invalid.");
}
m_Enumerator = linkedList.GetEnumerator();
}
/// <summary>
/// 获取当前结点。
/// </summary>
public T Current
{
get
{
return m_Enumerator.Current;
}
}
/// <summary>
/// 获取当前的枚举数。
/// </summary>
object IEnumerator.Current
{
get
{
return m_Enumerator.Current;
}
}
/// <summary>
/// 清理枚举数。
/// </summary>
public void Dispose()
{
m_Enumerator.Dispose();
}
/// <summary>
/// 获取下一个结点。
/// </summary>
/// <returns>返回下一个结点。</returns>
public bool MoveNext()
{
return m_Enumerator.MoveNext();
}
/// <summary>
/// 重置枚举数。
/// </summary>
void IEnumerator.Reset()
{
((IEnumerator<T>)m_Enumerator).Reset();
}
}
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 8662d2b0651bb46308fa9ea5a24a9f08
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,210 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace AlicizaX
{
/// <summary>
/// 游戏框架链表范围。
/// </summary>
/// <typeparam name="T">指定链表范围的元素类型。</typeparam>
[StructLayout(LayoutKind.Auto)]
public readonly struct GameFrameworkLinkedListRange<T> : IEnumerable<T>, IEnumerable
{
private readonly LinkedListNode<T> m_First;
private readonly LinkedListNode<T> m_Terminal;
/// <summary>
/// 初始化游戏框架链表范围的新实例。
/// </summary>
/// <param name="first">链表范围的开始结点。</param>
/// <param name="terminal">链表范围的终结标记结点。</param>
public GameFrameworkLinkedListRange(LinkedListNode<T> first, LinkedListNode<T> terminal)
{
if (first == null || terminal == null || first == terminal)
{
throw new GameFrameworkException("Range is invalid.");
}
m_First = first;
m_Terminal = terminal;
}
/// <summary>
/// 获取链表范围是否有效。
/// </summary>
public bool IsValid
{
get
{
return m_First != null && m_Terminal != null && m_First != m_Terminal;
}
}
/// <summary>
/// 获取链表范围的开始结点。
/// </summary>
public LinkedListNode<T> First
{
get
{
return m_First;
}
}
/// <summary>
/// 获取链表范围的终结标记结点。
/// </summary>
public LinkedListNode<T> Terminal
{
get
{
return m_Terminal;
}
}
/// <summary>
/// 获取链表范围的结点数量。
/// </summary>
public int Count
{
get
{
if (!IsValid)
{
return 0;
}
int count = 0;
for (LinkedListNode<T> current = m_First; current != null && current != m_Terminal; current = current.Next)
{
count++;
}
return count;
}
}
/// <summary>
/// 检查是否包含指定值。
/// </summary>
/// <param name="value">要检查的值。</param>
/// <returns>是否包含指定值。</returns>
public bool Contains(T value)
{
for (LinkedListNode<T> current = m_First; current != null && current != m_Terminal; current = current.Next)
{
if (current.Value.Equals(value))
{
return true;
}
}
return false;
}
/// <summary>
/// 返回循环访问集合的枚举数。
/// </summary>
/// <returns>循环访问集合的枚举数。</returns>
public Enumerator GetEnumerator()
{
return new Enumerator(this);
}
/// <summary>
/// 返回循环访问集合的枚举数。
/// </summary>
/// <returns>循环访问集合的枚举数。</returns>
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// 返回循环访问集合的枚举数。
/// </summary>
/// <returns>循环访问集合的枚举数。</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// 循环访问集合的枚举数。
/// </summary>
[StructLayout(LayoutKind.Auto)]
public struct Enumerator : IEnumerator<T>, IEnumerator
{
private readonly GameFrameworkLinkedListRange<T> m_GameFrameworkLinkedListRange;
private LinkedListNode<T> m_Current;
private T m_CurrentValue;
internal Enumerator(GameFrameworkLinkedListRange<T> range)
{
if (!range.IsValid)
{
throw new GameFrameworkException("Range is invalid.");
}
m_GameFrameworkLinkedListRange = range;
m_Current = m_GameFrameworkLinkedListRange.m_First;
m_CurrentValue = default(T);
}
/// <summary>
/// 获取当前结点。
/// </summary>
public T Current
{
get
{
return m_CurrentValue;
}
}
/// <summary>
/// 获取当前的枚举数。
/// </summary>
object IEnumerator.Current
{
get
{
return m_CurrentValue;
}
}
/// <summary>
/// 清理枚举数。
/// </summary>
public void Dispose()
{
}
/// <summary>
/// 获取下一个结点。
/// </summary>
/// <returns>返回下一个结点。</returns>
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;
}
/// <summary>
/// 重置枚举数。
/// </summary>
void IEnumerator.Reset()
{
m_Current = m_GameFrameworkLinkedListRange.m_First;
m_CurrentValue = default(T);
}
}
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 7edbebe0b1fd848418e2f1d863b611e1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,304 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace AlicizaX
{
/// <summary>
/// 游戏框架多值字典类。
/// </summary>
/// <typeparam name="TKey">指定多值字典的主键类型。</typeparam>
/// <typeparam name="TValue">指定多值字典的值类型。</typeparam>
public sealed class GameFrameworkMultiDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, GameFrameworkLinkedListRange<TValue>>>, IEnumerable
{
private readonly GameFrameworkLinkedList<TValue> m_LinkedList;
private readonly Dictionary<TKey, GameFrameworkLinkedListRange<TValue>> m_Dictionary;
/// <summary>
/// 初始化游戏框架多值字典类的新实例。
/// </summary>
public GameFrameworkMultiDictionary()
{
m_LinkedList = new GameFrameworkLinkedList<TValue>();
m_Dictionary = new Dictionary<TKey, GameFrameworkLinkedListRange<TValue>>();
}
/// <summary>
/// 获取多值字典中实际包含的主键数量。
/// </summary>
public int Count
{
get
{
return m_Dictionary.Count;
}
}
/// <summary>
/// 获取多值字典中指定主键的范围。
/// </summary>
/// <param name="key">指定的主键。</param>
/// <returns>指定主键的范围。</returns>
public GameFrameworkLinkedListRange<TValue> this[TKey key]
{
get
{
GameFrameworkLinkedListRange<TValue> range = default(GameFrameworkLinkedListRange<TValue>);
m_Dictionary.TryGetValue(key, out range);
return range;
}
}
/// <summary>
/// 清理多值字典。
/// </summary>
public void Clear()
{
m_Dictionary.Clear();
m_LinkedList.Clear();
}
/// <summary>
/// 检查多值字典中是否包含指定主键。
/// </summary>
/// <param name="key">要检查的主键。</param>
/// <returns>多值字典中是否包含指定主键。</returns>
public bool Contains(TKey key)
{
return m_Dictionary.ContainsKey(key);
}
/// <summary>
/// 检查多值字典中是否包含指定值。
/// </summary>
/// <param name="key">要检查的主键。</param>
/// <param name="value">要检查的值。</param>
/// <returns>多值字典中是否包含指定值。</returns>
public bool Contains(TKey key, TValue value)
{
GameFrameworkLinkedListRange<TValue> range = default(GameFrameworkLinkedListRange<TValue>);
if (m_Dictionary.TryGetValue(key, out range))
{
return range.Contains(value);
}
return false;
}
/// <summary>
/// 尝试获取多值字典中指定主键的范围。
/// </summary>
/// <param name="key">指定的主键。</param>
/// <param name="range">指定主键的范围。</param>
/// <returns>是否获取成功。</returns>
public bool TryGetValue(TKey key, out GameFrameworkLinkedListRange<TValue> range)
{
return m_Dictionary.TryGetValue(key, out range);
}
/// <summary>
/// 向指定的主键增加指定的值。
/// </summary>
/// <param name="key">指定的主键。</param>
/// <param name="value">指定的值。</param>
public LinkedListNode<TValue> Add(TKey key, TValue value)
{
GameFrameworkLinkedListRange<TValue> range = default(GameFrameworkLinkedListRange<TValue>);
if (m_Dictionary.TryGetValue(key, out range))
{
return m_LinkedList.AddBefore(range.Terminal, value);
}
else
{
LinkedListNode<TValue> first = m_LinkedList.AddLast(value);
LinkedListNode<TValue> terminal = m_LinkedList.AddLast(default(TValue));
m_Dictionary.Add(key, new GameFrameworkLinkedListRange<TValue>(first, terminal));
return first;
}
}
/// <summary>
/// 从指定的主键中移除指定的值。
/// </summary>
/// <param name="key">指定的主键。</param>
/// <param name="value">指定的值。</param>
/// <returns>是否移除成功。</returns>
public bool Remove(TKey key, TValue value)
{
GameFrameworkLinkedListRange<TValue> range = default(GameFrameworkLinkedListRange<TValue>);
if (m_Dictionary.TryGetValue(key, out range))
{
for (LinkedListNode<TValue> current = range.First; current != null && current != range.Terminal; current = current.Next)
{
if (current.Value.Equals(value))
{
return Remove(key, current);
}
}
}
return false;
}
/// <summary>
/// 从指定的主键中移除指定结点。
/// </summary>
/// <param name="key">指定的主键。</param>
/// <param name="node">要移除的结点。</param>
/// <returns>是否移除成功。</returns>
public bool Remove(TKey key, LinkedListNode<TValue> node)
{
if (node == null)
{
return false;
}
GameFrameworkLinkedListRange<TValue> range = default(GameFrameworkLinkedListRange<TValue>);
if (!m_Dictionary.TryGetValue(key, out range))
{
return false;
}
if (!m_LinkedList.Contains(node) || node == range.Terminal)
{
return false;
}
if (node == range.First)
{
LinkedListNode<TValue> next = node.Next;
if (next == range.Terminal)
{
m_LinkedList.Remove(next);
m_Dictionary.Remove(key);
}
else
{
m_Dictionary[key] = new GameFrameworkLinkedListRange<TValue>(next, range.Terminal);
}
}
m_LinkedList.Remove(node);
return true;
}
/// <summary>
/// 从指定的主键中移除所有的值。
/// </summary>
/// <param name="key">指定的主键。</param>
/// <returns>是否移除成功。</returns>
public bool RemoveAll(TKey key)
{
GameFrameworkLinkedListRange<TValue> range = default(GameFrameworkLinkedListRange<TValue>);
if (m_Dictionary.TryGetValue(key, out range))
{
m_Dictionary.Remove(key);
LinkedListNode<TValue> current = range.First;
while (current != null)
{
LinkedListNode<TValue> next = current != range.Terminal ? current.Next : null;
m_LinkedList.Remove(current);
current = next;
}
return true;
}
return false;
}
/// <summary>
/// 返回循环访问集合的枚举数。
/// </summary>
/// <returns>循环访问集合的枚举数。</returns>
public Enumerator GetEnumerator()
{
return new Enumerator(m_Dictionary);
}
/// <summary>
/// 返回循环访问集合的枚举数。
/// </summary>
/// <returns>循环访问集合的枚举数。</returns>
IEnumerator<KeyValuePair<TKey, GameFrameworkLinkedListRange<TValue>>> IEnumerable<KeyValuePair<TKey, GameFrameworkLinkedListRange<TValue>>>.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// 返回循环访问集合的枚举数。
/// </summary>
/// <returns>循环访问集合的枚举数。</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// 循环访问集合的枚举数。
/// </summary>
[StructLayout(LayoutKind.Auto)]
public struct Enumerator : IEnumerator<KeyValuePair<TKey, GameFrameworkLinkedListRange<TValue>>>, IEnumerator
{
private Dictionary<TKey, GameFrameworkLinkedListRange<TValue>>.Enumerator m_Enumerator;
internal Enumerator(Dictionary<TKey, GameFrameworkLinkedListRange<TValue>> dictionary)
{
if (dictionary == null)
{
throw new GameFrameworkException("Dictionary is invalid.");
}
m_Enumerator = dictionary.GetEnumerator();
}
/// <summary>
/// 获取当前结点。
/// </summary>
public KeyValuePair<TKey, GameFrameworkLinkedListRange<TValue>> Current
{
get
{
return m_Enumerator.Current;
}
}
/// <summary>
/// 获取当前的枚举数。
/// </summary>
object IEnumerator.Current
{
get
{
return m_Enumerator.Current;
}
}
/// <summary>
/// 清理枚举数。
/// </summary>
public void Dispose()
{
m_Enumerator.Dispose();
}
/// <summary>
/// 获取下一个结点。
/// </summary>
/// <returns>返回下一个结点。</returns>
public bool MoveNext()
{
return m_Enumerator.MoveNext();
}
/// <summary>
/// 重置枚举数。
/// </summary>
void IEnumerator.Reset()
{
((IEnumerator<KeyValuePair<TKey, GameFrameworkLinkedListRange<TValue>>>)m_Enumerator).Reset();
}
}
}
}

View File

@ -1,199 +0,0 @@
using System.Collections.Generic;
using System.IO;
namespace AlicizaX
{
/// <summary>
/// 游戏框架序列化器基类。
/// </summary>
/// <typeparam name="T">要序列化的数据类型。</typeparam>
public abstract class GameFrameworkSerializer<T>
{
private readonly Dictionary<byte, SerializeCallback> _serializeCallbacks;
private readonly Dictionary<byte, DeserializeCallback> _deserializeCallbacks;
private readonly Dictionary<byte, TryGetValueCallback> _tryGetValueCallbacks;
private byte _latestSerializeCallbackVersion;
/// <summary>
/// 初始化游戏框架序列化器基类的新实例。
/// </summary>
[UnityEngine.Scripting.Preserve]
public GameFrameworkSerializer()
{
_serializeCallbacks = new Dictionary<byte, SerializeCallback>();
_deserializeCallbacks = new Dictionary<byte, DeserializeCallback>();
_tryGetValueCallbacks = new Dictionary<byte, TryGetValueCallback>();
_latestSerializeCallbackVersion = 0;
}
/// <summary>
/// 序列化回调函数。
/// </summary>
/// <param name="stream">目标流。</param>
/// <param name="data">要序列化的数据。</param>
/// <returns>是否序列化数据成功。</returns>
public delegate bool SerializeCallback(Stream stream, T data);
/// <summary>
/// 反序列化回调函数。
/// </summary>
/// <param name="stream">指定流。</param>
/// <returns>反序列化的数据。</returns>
public delegate T DeserializeCallback(Stream stream);
/// <summary>
/// 尝试从指定流获取指定键的值回调函数。
/// </summary>
/// <param name="stream">指定流。</param>
/// <param name="key">指定键。</param>
/// <param name="value">指定键的值。</param>
/// <returns>是否从指定流获取指定键的值成功。</returns>
public delegate bool TryGetValueCallback(Stream stream, string key, out object value);
/// <summary>
/// 注册序列化回调函数。
/// </summary>
/// <param name="version">序列化回调函数的版本。</param>
/// <param name="callback">序列化回调函数。</param>
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;
}
}
/// <summary>
/// 注册反序列化回调函数。
/// </summary>
/// <param name="version">反序列化回调函数的版本。</param>
/// <param name="callback">反序列化回调函数。</param>
public void RegisterDeserializeCallback(byte version, DeserializeCallback callback)
{
if (callback == null)
{
throw new GameFrameworkException("Deserialize callback is invalid.");
}
_deserializeCallbacks[version] = callback;
}
/// <summary>
/// 注册尝试从指定流获取指定键的值回调函数。
/// </summary>
/// <param name="version">尝试从指定流获取指定键的值回调函数的版本。</param>
/// <param name="callback">尝试从指定流获取指定键的值回调函数。</param>
public void RegisterTryGetValueCallback(byte version, TryGetValueCallback callback)
{
if (callback == null)
{
throw new GameFrameworkException("Try get value callback is invalid.");
}
_tryGetValueCallbacks[version] = callback;
}
/// <summary>
/// 序列化数据到目标流中。
/// </summary>
/// <param name="stream">目标流。</param>
/// <param name="data">要序列化的数据。</param>
/// <returns>是否序列化数据成功。</returns>
public bool Serialize(Stream stream, T data)
{
if (_serializeCallbacks.Count <= 0)
{
throw new GameFrameworkException("No serialize callback registered.");
}
return Serialize(stream, data, _latestSerializeCallbackVersion);
}
/// <summary>
/// 序列化数据到目标流中。
/// </summary>
/// <param name="stream">目标流。</param>
/// <param name="data">要序列化的数据。</param>
/// <param name="version">序列化回调函数的版本。</param>
/// <returns>是否序列化数据成功。</returns>
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);
}
/// <summary>
/// 从指定流反序列化数据。
/// </summary>
/// <param name="stream">指定流。</param>
/// <returns>反序列化的数据。</returns>
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);
}
/// <summary>
/// 尝试从指定流获取指定键的值。
/// </summary>
/// <param name="stream">指定流。</param>
/// <param name="key">指定键。</param>
/// <param name="value">指定键的值。</param>
/// <returns>是否从指定流获取指定键的值成功。</returns>
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);
}
/// <summary>
/// 获取数据头标识。
/// </summary>
/// <returns>数据头标识。</returns>
protected abstract byte[] GetHeader();
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 2c8469a7db4474e1da10e383bc09e77f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -39,7 +39,6 @@ namespace AlicizaX
private static readonly Dictionary<Type, MemoryPoolHandle> s_Handles
= new Dictionary<Type, MemoryPoolHandle>(64);
// Tick 回调用数组缓存,避免每帧遍历 Dictionary
private static Action<int>[] s_TickArray = Array.Empty<Action<int>>();
private static int s_TickCount;
private static bool s_TickArrayDirty;

View File

@ -1,181 +1,28 @@
using System;
using System;
namespace AlicizaX.ObjectPool
{
public interface IObjectPool
public interface IObjectPool<T> where T : ObjectBase
{
}
/// <summary>
/// 对象池接口。
/// </summary>
/// <typeparam name="T">对象类型。</typeparam>
public interface IObjectPool<T> : IObjectPool where T : ObjectBase
{
/// <summary>
/// 获取对象池名称。
/// </summary>
string Name { get; }
/// <summary>
/// 获取对象池完整名称。
/// </summary>
string FullName { get; }
/// <summary>
/// 获取对象池对象类型。
/// </summary>
Type ObjectType { get; }
/// <summary>
/// 获取对象池中对象的数量。
/// </summary>
int Count { get; }
/// <summary>
/// 获取对象池中能被释放的对象的数量。
/// </summary>
int CanReleaseCount { get; }
/// <summary>
/// 获取是否允许对象被多次获取。
/// </summary>
bool AllowMultiSpawn { get; }
/// <summary>
/// 获取或设置对象池自动释放可释放对象的间隔秒数。
/// </summary>
float AutoReleaseInterval { get; set; }
/// <summary>
/// 获取或设置对象池的容量。
/// </summary>
int Capacity { get; set; }
/// <summary>
/// 获取或设置对象池对象过期秒数。
/// </summary>
float ExpireTime { get; set; }
/// <summary>
/// 获取或设置对象池的优先级。
/// </summary>
int Priority { get; set; }
/// <summary>
/// 创建对象。
/// </summary>
/// <param name="obj">对象。</param>
/// <param name="spawned">对象是否已被获取。</param>
void Register(T obj, bool spawned);
/// <summary>
/// 检查对象。
/// </summary>
/// <returns>要检查的对象是否存在。</returns>
bool CanSpawn();
/// <summary>
/// 检查对象。
/// </summary>
/// <param name="name">对象名称。</param>
/// <returns>要检查的对象是否存在。</returns>
bool CanSpawn(string name);
/// <summary>
/// 获取对象。
/// </summary>
/// <returns>要获取的对象。</returns>
T Spawn();
/// <summary>
/// 获取对象。
/// </summary>
/// <param name="name">对象名称。</param>
/// <returns>要获取的对象。</returns>
T Spawn(string name);
/// <summary>
/// 回收对象。
/// </summary>
/// <param name="obj">要回收的对象。</param>
void Unspawn(T obj);
/// <summary>
/// 回收对象。
/// </summary>
/// <param name="target">要回收的对象。</param>
void Unspawn(object target);
/// <summary>
/// 设置对象是否被加锁。
/// </summary>
/// <param name="obj">要设置被加锁的对象。</param>
/// <param name="locked">是否被加锁。</param>
void SetLocked(T obj, bool locked);
/// <summary>
/// 设置对象是否被加锁。
/// </summary>
/// <param name="target">要设置被加锁的对象。</param>
/// <param name="locked">是否被加锁。</param>
void SetLocked(object target, bool locked);
/// <summary>
/// 设置对象的优先级。
/// </summary>
/// <param name="obj">要设置优先级的对象。</param>
/// <param name="priority">优先级。</param>
void SetPriority(T obj, int priority);
/// <summary>
/// 设置对象的优先级。
/// </summary>
/// <param name="target">要设置优先级的对象。</param>
/// <param name="priority">优先级。</param>
void SetPriority(object target, int priority);
/// <summary>
/// 释放对象。
/// </summary>
/// <param name="obj">要释放的对象。</param>
/// <returns>释放对象是否成功。</returns>
bool ReleaseObject(T obj);
/// <summary>
/// 释放对象。
/// </summary>
/// <param name="target">要释放的对象。</param>
/// <returns>释放对象是否成功。</returns>
bool ReleaseObject(object target);
/// <summary>
/// 释放对象池中的可释放对象。
/// </summary>
void Release();
/// <summary>
/// 释放对象池中的可释放对象。
/// </summary>
/// <param name="toReleaseCount">尝试释放对象数量。</param>
void Release(int toReleaseCount);
/// <summary>
/// 释放对象池中的可释放对象。
/// </summary>
/// <param name="releaseObjectFilterCallback">释放对象筛选函数。</param>
void Release(ReleaseObjectFilterCallback<T> releaseObjectFilterCallback);
/// <summary>
/// 释放对象池中的可释放对象。
/// </summary>
/// <param name="toReleaseCount">尝试释放对象数量。</param>
/// <param name="releaseObjectFilterCallback">释放对象筛选函数。</param>
void Release(int toReleaseCount, ReleaseObjectFilterCallback<T> releaseObjectFilterCallback);
/// <summary>
/// 释放对象池中的所有未使用对象。
/// </summary>
void ReleaseAllUnused();
}
}

View File

@ -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);
}
/// <summary>
/// 对象池管理器。
/// </summary>
public interface IObjectPoolService : IService
{
int Count { get; }
bool HasObjectPool<T>() where T : ObjectBase;
bool HasObjectPool(Type objectType);
bool HasObjectPool<T>(string name) where T : ObjectBase;
bool HasObjectPool(Type objectType);
bool HasObjectPool(Type objectType, string name);
bool HasObjectPool(Predicate<ObjectPoolBase> condition);
IObjectPool<T> GetObjectPool<T>() where T : ObjectBase;
ObjectPoolBase GetObjectPool(Type objectType);
IObjectPool<T> GetObjectPool<T>(string name) where T : ObjectBase;
ObjectPoolBase GetObjectPool(Type objectType);
ObjectPoolBase GetObjectPool(Type objectType, string name);
ObjectPoolBase GetObjectPool(Predicate<ObjectPoolBase> condition);
ObjectPoolBase[] GetObjectPools(Predicate<ObjectPoolBase> condition);
void GetObjectPools(Predicate<ObjectPoolBase> condition, List<ObjectPoolBase> results);
ObjectPoolBase[] GetAllObjectPools();
void GetAllObjectPools(List<ObjectPoolBase> results);
ObjectPoolBase[] GetAllObjectPools(bool sort);
void GetAllObjectPools(List<ObjectPoolBase> results);
void GetAllObjectPools(bool sort, List<ObjectPoolBase> results);
IObjectPool<T> CreatePool<T>(ObjectPoolCreateOptions options = default) where T : ObjectBase;
ObjectPoolBase CreatePool(Type objectType, ObjectPoolCreateOptions options = default);
bool DestroyObjectPool<T>() where T : ObjectBase;
bool DestroyObjectPool(Type objectType);
bool DestroyObjectPool<T>(string name) where T : ObjectBase;
bool DestroyObjectPool(Type objectType);
bool DestroyObjectPool(Type objectType, string name);
bool DestroyObjectPool<T>(IObjectPool<T> objectPool) where T : ObjectBase;
bool DestroyObjectPool(ObjectPoolBase objectPool);

View File

@ -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;
}
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: ce20200ce38864c44b02e0c1ebc7fc3a
guid: 6e20a3f64bc47ae4dbf407342897a015
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -1,175 +1,57 @@
using System;
using AlicizaX;
namespace AlicizaX.ObjectPool
{
/// <summary>
/// 对象基类。
/// </summary>
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;
/// <summary>
/// 初始化对象基类的新实例。
/// </summary>
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;
/// <summary>
/// 获取对象名称。
/// </summary>
public virtual string Name
{
get { return m_Name; }
protected set { m_Name = value; }
}
/// <summary>
/// 获取对象。
/// </summary>
public object Target
{
get { return m_Target; }
}
/// <summary>
/// 获取或设置对象是否被加锁。
/// </summary>
public bool Locked
{
get { return m_Locked; }
set { m_Locked = value; }
get => m_Locked;
set => m_Locked = value;
}
/// <summary>
/// 获取或设置对象的优先级。
/// </summary>
public int Priority
public float LastUseTime
{
get { return m_Priority; }
set { m_Priority = value; }
get => m_LastUseTime;
internal set => m_LastUseTime = value;
}
/// <summary>
/// 获取自定义释放检查标记。
/// </summary>
public virtual bool CustomCanReleaseFlag
{
get { return true; }
}
public virtual bool CustomCanReleaseFlag => true;
/// <summary>
/// 获取对象上次使用时间。
/// </summary>
public DateTime LastUseTime
{
get { return m_LastUseTime; }
internal set { m_LastUseTime = value; }
}
/// <summary>
/// 初始化对象基类。
/// </summary>
/// <param name="target">对象。</param>
protected void Initialize(object target)
{
Initialize(null, target, false, 0);
Initialize(string.Empty, target, false);
}
/// <summary>
/// 初始化对象基类。
/// </summary>
/// <param name="name">对象名称。</param>
/// <param name="target">对象。</param>
protected void Initialize(string name, object target)
{
Initialize(name, target, false, 0);
Initialize(name, target, false);
}
/// <summary>
/// 初始化对象基类。
/// </summary>
/// <param name="name">对象名称。</param>
/// <param name="target">对象。</param>
/// <param name="locked">对象是否被加锁。</param>
protected void Initialize(string name, object target, bool locked)
{
Initialize(name, target, locked, 0);
}
/// <summary>
/// 初始化对象基类。
/// </summary>
/// <param name="name">对象名称。</param>
/// <param name="target">对象。</param>
/// <param name="priority">对象的优先级。</param>
protected void Initialize(string name, object target, int priority)
{
Initialize(name, target, false, priority);
}
/// <summary>
/// 初始化对象基类。
/// </summary>
/// <param name="name">对象名称。</param>
/// <param name="target">对象。</param>
/// <param name="locked">对象是否被加锁。</param>
/// <param name="priority">对象的优先级。</param>
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;
}
/// <summary>
/// 清理对象基类。
/// </summary>
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;
}
/// <summary>
/// 获取对象时的事件。
/// </summary>
protected internal virtual void OnSpawn()
{
}
/// <summary>
/// 回收对象时的事件。
/// </summary>
protected internal virtual void OnUnspawn()
{
}
/// <summary>
/// 释放对象。
/// </summary>
/// <param name="isShutdown">是否是关闭对象池时触发。</param>
protected internal abstract void Release(bool isShutdown);
}
}

View File

@ -1,115 +1,27 @@
using System;
using System.Runtime.InteropServices;
namespace AlicizaX.ObjectPool
{
/// <summary>
/// 对象信息。
/// </summary>
[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;
/// <summary>
/// 初始化对象信息的新实例。
/// </summary>
/// <param name="name">对象名称。</param>
/// <param name="locked">对象是否被加锁。</param>
/// <param name="customCanReleaseFlag">对象自定义释放检查标记。</param>
/// <param name="priority">对象的优先级。</param>
/// <param name="lastUseTime">对象上次使用时间。</param>
/// <param name="spawnCount">对象的获取计数。</param>
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;
}
/// <summary>
/// 获取对象名称。
/// </summary>
public string Name
{
get
{
return m_Name;
}
}
/// <summary>
/// 获取对象是否被加锁。
/// </summary>
public bool Locked
{
get
{
return m_Locked;
}
}
/// <summary>
/// 获取对象自定义释放检查标记。
/// </summary>
public bool CustomCanReleaseFlag
{
get
{
return m_CustomCanReleaseFlag;
}
}
/// <summary>
/// 获取对象的优先级。
/// </summary>
public int Priority
{
get
{
return m_Priority;
}
}
/// <summary>
/// 获取对象上次使用时间。
/// </summary>
public DateTime LastUseTime
{
get
{
return m_LastUseTime;
}
}
/// <summary>
/// 获取对象是否正在使用。
/// </summary>
public bool IsInUse
{
get
{
return m_SpawnCount > 0;
}
}
/// <summary>
/// 获取对象的获取计数。
/// </summary>
public int SpawnCount
{
get
{
return m_SpawnCount;
}
}
public bool IsInUse => SpawnCount > 0;
}
}

View File

@ -1,149 +1,53 @@
using System;
using System;
using System.Collections.Generic;
using AlicizaX;
namespace AlicizaX.ObjectPool
{
/// <summary>
/// 对象池基类。
/// </summary>
public abstract class ObjectPoolBase
{
private readonly string m_Name;
/// <summary>
/// 初始化对象池基类的新实例。
/// </summary>
public ObjectPoolBase()
: this(null)
{
}
public ObjectPoolBase() : this(null) { }
/// <summary>
/// 初始化对象池基类的新实例。
/// </summary>
/// <param name="name">对象池名称。</param>
public ObjectPoolBase(string name)
{
m_Name = name ?? string.Empty;
}
/// <summary>
/// 获取对象池名称。
/// </summary>
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 { }
}
/// <summary>
/// 获取对象池完整名称。
/// </summary>
public string FullName
{
get
{
return new TypeNamePair(ObjectType, m_Name).ToString();
}
}
/// <summary>
/// 获取对象池对象类型。
/// </summary>
public abstract Type ObjectType
{
get;
}
/// <summary>
/// 获取对象池中对象的数量。
/// </summary>
public abstract int Count
{
get;
}
/// <summary>
/// 获取对象池中能被释放的对象的数量。
/// </summary>
public abstract int CanReleaseCount
{
get;
}
/// <summary>
/// 获取是否允许对象被多次获取。
/// </summary>
public abstract bool AllowMultiSpawn
{
get;
}
/// <summary>
/// 获取或设置对象池自动释放可释放对象的间隔秒数。
/// </summary>
public abstract float AutoReleaseInterval
{
get;
set;
}
/// <summary>
/// 获取或设置对象池的容量。
/// </summary>
public abstract int Capacity
{
get;
set;
}
/// <summary>
/// 获取或设置对象池对象过期秒数。
/// </summary>
public abstract float ExpireTime
{
get;
set;
}
/// <summary>
/// 获取或设置对象池的优先级。
/// </summary>
public abstract int Priority
{
get;
set;
}
/// <summary>
/// 释放对象池中的可释放对象。
/// </summary>
public abstract void Release();
/// <summary>
/// 释放对象池中的可释放对象。
/// </summary>
/// <param name="toReleaseCount">尝试释放对象数量。</param>
public abstract void Release(int toReleaseCount);
/// <summary>
/// 释放对象池中的所有未使用对象。
/// </summary>
public abstract void ReleaseAllUnused();
/// <summary>
/// 获取所有对象信息。
/// </summary>
/// <returns>所有对象信息。</returns>
public abstract ObjectInfo[] GetAllObjectInfos();
public abstract void GetAllObjectInfos(List<ObjectInfo> results);
internal abstract void Update(float elapseSeconds, float realElapseSeconds);
internal abstract void Shutdown();
internal virtual void OnLowMemory()
{
ReleaseAllUnused();
}
}
}

View File

@ -3,40 +3,34 @@ using UnityEngine;
namespace AlicizaX
{
/// <summary>
/// 对象池组件。
/// </summary>
public sealed class ObjectPoolComponent : MonoBehaviour
{
private IObjectPoolService _mObjectPoolService = null;
private IObjectPoolService _mObjectPoolService;
/// <summary>
/// 获取对象池数量。
/// </summary>
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;
}
/// <summary>
/// 获取所有对象池。
/// </summary>
/// <param name="sort">是否根据对象池的优先级排序。</param>
/// <returns>所有对象池。</returns>
private void OnLowMemory()
{
if (_mObjectPoolService is ObjectPoolService svc)
svc.OnLowMemory();
}
public ObjectPoolBase[] GetAllObjectPools(bool sort)
{
return _mObjectPoolService.GetAllObjectPools(sort);
}
}
}

View File

@ -1,180 +0,0 @@
using System;
using System.Collections.Generic;
using AlicizaX;
namespace AlicizaX.ObjectPool
{
internal sealed partial class ObjectPoolService : IObjectPoolService
{
/// <summary>
/// 内部对象。
/// </summary>
/// <typeparam name="T">对象类型。</typeparam>
private sealed class Object<T> : IMemory where T : ObjectBase
{
private string m_Name;
private T m_Object;
private int m_SpawnCount;
private LinkedListNode<Object<T>> m_NameNode;
/// <summary>
/// 初始化内部对象的新实例。
/// </summary>
public Object()
{
m_Name = null;
m_Object = null;
m_SpawnCount = 0;
m_NameNode = null;
}
/// <summary>
/// 获取对象名称。
/// </summary>
public string Name
{
get { return m_Name; }
}
/// <summary>
/// 获取对象是否被加锁。
/// </summary>
public bool Locked
{
get { return m_Object.Locked; }
internal set { m_Object.Locked = value; }
}
/// <summary>
/// 获取对象的优先级。
/// </summary>
public int Priority
{
get { return m_Object.Priority; }
internal set { m_Object.Priority = value; }
}
/// <summary>
/// 获取自定义释放检查标记。
/// </summary>
public bool CustomCanReleaseFlag
{
get { return m_Object.CustomCanReleaseFlag; }
}
/// <summary>
/// 获取对象上次使用时间。
/// </summary>
public DateTime LastUseTime
{
get { return m_Object.LastUseTime; }
}
/// <summary>
/// 获取对象是否正在使用。
/// </summary>
public bool IsInUse
{
get { return m_SpawnCount > 0; }
}
/// <summary>
/// 获取对象的获取计数。
/// </summary>
public int SpawnCount
{
get { return m_SpawnCount; }
}
/// <summary>
/// 获取或设置对象在名字桶中的链表结点。
/// </summary>
public LinkedListNode<Object<T>> NameNode
{
get { return m_NameNode; }
internal set { m_NameNode = value; }
}
/// <summary>
/// 创建内部对象。
/// </summary>
/// <param name="obj">对象。</param>
/// <param name="spawned">对象是否已被获取。</param>
/// <returns>创建的内部对象。</returns>
public static Object<T> Create(T obj, bool spawned)
{
if (obj == null)
{
throw new GameFrameworkException("Object is invalid.");
}
Object<T> internalObject = MemoryPool.Acquire<Object<T>>();
internalObject.m_Name = obj.Name;
internalObject.m_Object = obj;
internalObject.m_SpawnCount = spawned ? 1 : 0;
if (spawned)
{
obj.OnSpawn();
}
return internalObject;
}
/// <summary>
/// 清理内部对象。
/// </summary>
public void Clear()
{
m_Name = null;
m_Object = null;
m_SpawnCount = 0;
m_NameNode = null;
}
/// <summary>
/// 查看对象。
/// </summary>
/// <returns>对象。</returns>
public T Peek()
{
return m_Object;
}
/// <summary>
/// 获取对象。
/// </summary>
/// <returns>对象。</returns>
public T Spawn()
{
m_SpawnCount++;
m_Object.LastUseTime = DateTime.UtcNow;
m_Object.OnSpawn();
return m_Object;
}
/// <summary>
/// 回收对象。
/// </summary>
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));
}
}
/// <summary>
/// 释放对象。
/// </summary>
/// <param name="isShutdown">是否是关闭对象池时触发。</param>
public void Release(bool isShutdown)
{
m_Object.Release(isShutdown);
MemoryPool.Release(m_Object);
}
}
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 35ccf480f8b7a42a4ba523c51d58e544
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +0,0 @@
using System;
using System.Collections.Generic;
namespace AlicizaX.ObjectPool
{
/// <summary>
/// 释放对象筛选函数。
/// </summary>
/// <typeparam name="T">对象类型。</typeparam>
/// <param name="candidateObjects">要筛选的对象集合。</param>
/// <param name="toReleaseCount">需要释放的对象数量。</param>
/// <param name="expireTime">对象过期参考时间。</param>
/// <returns>经筛选需要释放的对象集合。</returns>
public delegate List<T> ReleaseObjectFilterCallback<T>(List<T> candidateObjects, int toReleaseCount, DateTime expireTime) where T : ObjectBase;
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 7109de176e3874b1d863ca0d2cdba894
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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) ? "<None>" : 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));
}
}

View File

@ -15,12 +15,7 @@ namespace AlicizaX.Resource.Runtime
protected internal override void Release(bool isShutdown)
{
if (Target == null)
{
return;
}
AppServices.Require<IResourceService>().UnloadAsset(Target);
// Asset handle cleanup is owned by ResourceExtComponent/ResourceService.
}
}
}

View File

@ -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)

View File

@ -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>();
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;
}
}
}

View File

@ -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;