123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637 |
- //------------------------------------------------------------
- // Game Framework
- // Copyright © 2013-2021 loyalsoft. All rights reserved.
- // Homepage: http://www.game7000.com/
- // Feedback: http://www.game7000.com/
- //------------------------------------------------------------
- using System;
- using System.Collections.Generic;
- namespace GameFramework.ObjectPool
- {
- internal sealed partial class ObjectPoolManager : GameFrameworkModule, IObjectPoolManager
- {
- /// <summary>
- /// 对象池。
- /// </summary>
- /// <typeparam name="T">对象类型。</typeparam>
- private sealed class ObjectPool<T> : ObjectPoolBase, IObjectPool<T> where T : ObjectBase
- {
- private readonly GameFrameworkMultiDictionary<string, Object<T>> m_Objects;
- private readonly Dictionary<object, Object<T>> m_ObjectMap;
- private readonly ReleaseObjectFilterCallback<T> m_DefaultReleaseObjectFilterCallback;
- private readonly List<T> m_CachedCanReleaseObjects;
- private readonly List<T> m_CachedToReleaseObjects;
- private readonly bool m_AllowMultiSpawn;
- private float m_AutoReleaseInterval;
- private int m_Capacity;
- private float m_ExpireTime;
- private int m_Priority;
- private float m_AutoReleaseTime;
- /// <summary>
- /// 初始化对象池的新实例。
- /// </summary>
- /// <param name="name">对象池名称。</param>
- /// <param name="allowMultiSpawn">是否允许对象被多次获取。</param>
- /// <param name="autoReleaseInterval">对象池自动释放可释放对象的间隔秒数。</param>
- /// <param name="capacity">对象池的容量。</param>
- /// <param name="expireTime">对象池对象过期秒数。</param>
- /// <param name="priority">对象池的优先级。</param>
- public ObjectPool(string name, bool allowMultiSpawn, float autoReleaseInterval, int capacity, float expireTime, int priority)
- : base(name)
- {
- m_Objects = new GameFrameworkMultiDictionary<string, Object<T>>();
- m_ObjectMap = new Dictionary<object, Object<T>>();
- m_DefaultReleaseObjectFilterCallback = DefaultReleaseObjectFilterCallback;
- m_CachedCanReleaseObjects = new List<T>();
- m_CachedToReleaseObjects = new List<T>();
- m_AllowMultiSpawn = allowMultiSpawn;
- m_AutoReleaseInterval = autoReleaseInterval;
- Capacity = capacity;
- ExpireTime = expireTime;
- m_Priority = priority;
- m_AutoReleaseTime = 0f;
- }
- /// <summary>
- /// 获取对象池对象类型。
- /// </summary>
- public override Type ObjectType
- {
- get
- {
- return typeof(T);
- }
- }
- /// <summary>
- /// 获取对象池中对象的数量。
- /// </summary>
- public override int Count
- {
- get
- {
- return m_ObjectMap.Count;
- }
- }
- /// <summary>
- /// 获取对象池中能被释放的对象的数量。
- /// </summary>
- public override int CanReleaseCount
- {
- get
- {
- GetCanReleaseObjects(m_CachedCanReleaseObjects);
- return m_CachedCanReleaseObjects.Count;
- }
- }
- /// <summary>
- /// 获取是否允许对象被多次获取。
- /// </summary>
- public override bool AllowMultiSpawn
- {
- get
- {
- return m_AllowMultiSpawn;
- }
- }
- /// <summary>
- /// 获取或设置对象池自动释放可释放对象的间隔秒数。
- /// </summary>
- public override float AutoReleaseInterval
- {
- get
- {
- return m_AutoReleaseInterval;
- }
- set
- {
- m_AutoReleaseInterval = value;
- }
- }
- /// <summary>
- /// 获取或设置对象池的容量。
- /// </summary>
- public override int Capacity
- {
- get
- {
- return m_Capacity;
- }
- set
- {
- if (value < 0)
- {
- throw new GameFrameworkException("Capacity is invalid.");
- }
- if (m_Capacity == value)
- {
- return;
- }
- m_Capacity = value;
- Release();
- }
- }
- /// <summary>
- /// 获取或设置对象池对象过期秒数。
- /// </summary>
- public override float ExpireTime
- {
- get
- {
- return m_ExpireTime;
- }
- set
- {
- if (value < 0f)
- {
- throw new GameFrameworkException("ExpireTime is invalid.");
- }
- if (ExpireTime == value)
- {
- return;
- }
- m_ExpireTime = value;
- Release();
- }
- }
- /// <summary>
- /// 获取或设置对象池的优先级。
- /// </summary>
- public override int Priority
- {
- get
- {
- return m_Priority;
- }
- set
- {
- m_Priority = value;
- }
- }
- /// <summary>
- /// 创建对象。
- /// </summary>
- /// <param name="obj">对象。</param>
- /// <param name="spawned">对象是否已被获取。</param>
- public void Register(T obj, bool spawned)
- {
- if (obj == null)
- {
- throw new GameFrameworkException("Object is invalid.");
- }
- Object<T> internalObject = Object<T>.Create(obj, spawned);
- m_Objects.Add(obj.Name, internalObject);
- m_ObjectMap.Add(obj.Target, internalObject);
- if (Count > m_Capacity)
- {
- Release();
- }
- }
- /// <summary>
- /// 检查对象。
- /// </summary>
- /// <returns>要检查的对象是否存在。</returns>
- public bool CanSpawn()
- {
- return CanSpawn(string.Empty);
- }
- /// <summary>
- /// 检查对象。
- /// </summary>
- /// <param name="name">对象名称。</param>
- /// <returns>要检查的对象是否存在。</returns>
- public bool CanSpawn(string name)
- {
- if (name == null)
- {
- throw new GameFrameworkException("Name is invalid.");
- }
- GameFrameworkLinkedListRange<Object<T>> objectRange = default(GameFrameworkLinkedListRange<Object<T>>);
- if (m_Objects.TryGetValue(name, out objectRange))
- {
- foreach (Object<T> internalObject in objectRange)
- {
- if (m_AllowMultiSpawn || !internalObject.IsInUse)
- {
- return true;
- }
- }
- }
- return false;
- }
- /// <summary>
- /// 获取对象。
- /// </summary>
- /// <returns>要获取的对象。</returns>
- public T Spawn()
- {
- return Spawn(string.Empty);
- }
- /// <summary>
- /// 获取对象。
- /// </summary>
- /// <param name="name">对象名称。</param>
- /// <returns>要获取的对象。</returns>
- public T Spawn(string name)
- {
- if (name == null)
- {
- throw new GameFrameworkException("Name is invalid.");
- }
- GameFrameworkLinkedListRange<Object<T>> objectRange = default(GameFrameworkLinkedListRange<Object<T>>);
- if (m_Objects.TryGetValue(name, out objectRange))
- {
- foreach (Object<T> internalObject in objectRange)
- {
- if (m_AllowMultiSpawn || !internalObject.IsInUse)
- {
- return internalObject.Spawn();
- }
- }
- }
- return null;
- }
- /// <summary>
- /// 回收对象。
- /// </summary>
- /// <param name="obj">要回收的对象。</param>
- public void Unspawn(T obj)
- {
- if (obj == null)
- {
- throw new GameFrameworkException("Object is invalid.");
- }
- Unspawn(obj.Target);
- }
- /// <summary>
- /// 回收对象。
- /// </summary>
- /// <param name="target">要回收的对象。</param>
- public void Unspawn(object target)
- {
- if (target == null)
- {
- throw new GameFrameworkException("Target is invalid.");
- }
- Object<T> 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));
- }
- }
- /// <summary>
- /// 设置对象是否被加锁。
- /// </summary>
- /// <param name="obj">要设置被加锁的对象。</param>
- /// <param name="locked">是否被加锁。</param>
- public void SetLocked(T obj, bool locked)
- {
- if (obj == null)
- {
- throw new GameFrameworkException("Object is invalid.");
- }
- SetLocked(obj.Target, locked);
- }
- /// <summary>
- /// 设置对象是否被加锁。
- /// </summary>
- /// <param name="target">要设置被加锁的对象。</param>
- /// <param name="locked">是否被加锁。</param>
- public void SetLocked(object target, bool locked)
- {
- if (target == null)
- {
- throw new GameFrameworkException("Target is invalid.");
- }
- Object<T> 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));
- }
- }
- /// <summary>
- /// 设置对象的优先级。
- /// </summary>
- /// <param name="obj">要设置优先级的对象。</param>
- /// <param name="priority">优先级。</param>
- public void SetPriority(T obj, int priority)
- {
- if (obj == null)
- {
- throw new GameFrameworkException("Object is invalid.");
- }
- SetPriority(obj.Target, priority);
- }
- /// <summary>
- /// 设置对象的优先级。
- /// </summary>
- /// <param name="target">要设置优先级的对象。</param>
- /// <param name="priority">优先级。</param>
- public void SetPriority(object target, int priority)
- {
- if (target == null)
- {
- throw new GameFrameworkException("Target is invalid.");
- }
- Object<T> 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));
- }
- }
- /// <summary>
- /// 释放对象。
- /// </summary>
- /// <param name="obj">要释放的对象。</param>
- /// <returns>释放对象是否成功。</returns>
- public bool ReleaseObject(T obj)
- {
- if (obj == null)
- {
- throw new GameFrameworkException("Object is invalid.");
- }
- return ReleaseObject(obj.Target);
- }
- /// <summary>
- /// 释放对象。
- /// </summary>
- /// <param name="target">要释放的对象。</param>
- /// <returns>释放对象是否成功。</returns>
- public bool ReleaseObject(object target)
- {
- if (target == null)
- {
- throw new GameFrameworkException("Target is invalid.");
- }
- Object<T> internalObject = GetObject(target);
- if (internalObject == null)
- {
- return false;
- }
- if (internalObject.IsInUse || internalObject.Locked || !internalObject.CustomCanReleaseFlag)
- {
- return false;
- }
- m_Objects.Remove(internalObject.Name, internalObject);
- m_ObjectMap.Remove(internalObject.Peek().Target);
- internalObject.Release(false);
- ReferencePool.Release(internalObject);
- return true;
- }
- /// <summary>
- /// 释放对象池中的可释放对象。
- /// </summary>
- public override void Release()
- {
- Release(Count - m_Capacity, m_DefaultReleaseObjectFilterCallback);
- }
- /// <summary>
- /// 释放对象池中的可释放对象。
- /// </summary>
- /// <param name="toReleaseCount">尝试释放对象数量。</param>
- public override void Release(int toReleaseCount)
- {
- Release(toReleaseCount, m_DefaultReleaseObjectFilterCallback);
- }
- /// <summary>
- /// 释放对象池中的可释放对象。
- /// </summary>
- /// <param name="releaseObjectFilterCallback">释放对象筛选函数。</param>
- public void Release(ReleaseObjectFilterCallback<T> releaseObjectFilterCallback)
- {
- Release(Count - m_Capacity, releaseObjectFilterCallback);
- }
- /// <summary>
- /// 释放对象池中的可释放对象。
- /// </summary>
- /// <param name="toReleaseCount">尝试释放对象数量。</param>
- /// <param name="releaseObjectFilterCallback">释放对象筛选函数。</param>
- public void Release(int toReleaseCount, ReleaseObjectFilterCallback<T> releaseObjectFilterCallback)
- {
- if (releaseObjectFilterCallback == null)
- {
- throw new GameFrameworkException("Release object filter callback is invalid.");
- }
- 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<T> toReleaseObjects = releaseObjectFilterCallback(m_CachedCanReleaseObjects, toReleaseCount, expireTime);
- if (toReleaseObjects == null || toReleaseObjects.Count <= 0)
- {
- return;
- }
- foreach (T toReleaseObject in toReleaseObjects)
- {
- ReleaseObject(toReleaseObject);
- }
- }
- /// <summary>
- /// 释放对象池中的所有未使用对象。
- /// </summary>
- public override void ReleaseAllUnused()
- {
- m_AutoReleaseTime = 0f;
- GetCanReleaseObjects(m_CachedCanReleaseObjects);
- foreach (T toReleaseObject in m_CachedCanReleaseObjects)
- {
- ReleaseObject(toReleaseObject);
- }
- }
- /// <summary>
- /// 获取所有对象信息。
- /// </summary>
- /// <returns>所有对象信息。</returns>
- public override ObjectInfo[] GetAllObjectInfos()
- {
- List<ObjectInfo> results = new List<ObjectInfo>();
- foreach (KeyValuePair<string, GameFrameworkLinkedListRange<Object<T>>> objectRanges in m_Objects)
- {
- foreach (Object<T> internalObject in objectRanges.Value)
- {
- results.Add(new ObjectInfo(internalObject.Name, internalObject.Locked, internalObject.CustomCanReleaseFlag, internalObject.Priority, internalObject.LastUseTime, internalObject.SpawnCount));
- }
- }
- return results.ToArray();
- }
- internal override void Update(float elapseSeconds, float realElapseSeconds)
- {
- m_AutoReleaseTime += realElapseSeconds;
- if (m_AutoReleaseTime < m_AutoReleaseInterval)
- {
- return;
- }
- Release();
- }
- internal override void Shutdown()
- {
- foreach (KeyValuePair<object, Object<T>> objectInMap in m_ObjectMap)
- {
- objectInMap.Value.Release(true);
- ReferencePool.Release(objectInMap.Value);
- }
- m_Objects.Clear();
- m_ObjectMap.Clear();
- m_CachedCanReleaseObjects.Clear();
- m_CachedToReleaseObjects.Clear();
- }
- private Object<T> GetObject(object target)
- {
- if (target == null)
- {
- throw new GameFrameworkException("Target is invalid.");
- }
- Object<T> internalObject = null;
- if (m_ObjectMap.TryGetValue(target, out internalObject))
- {
- return internalObject;
- }
- return null;
- }
- private void GetCanReleaseObjects(List<T> results)
- {
- if (results == null)
- {
- throw new GameFrameworkException("Results is invalid.");
- }
- results.Clear();
- foreach (KeyValuePair<object, Object<T>> objectInMap in m_ObjectMap)
- {
- Object<T> internalObject = objectInMap.Value;
- if (internalObject.IsInUse || internalObject.Locked || !internalObject.CustomCanReleaseFlag)
- {
- continue;
- }
- results.Add(internalObject.Peek());
- }
- }
- private List<T> DefaultReleaseObjectFilterCallback(List<T> candidateObjects, int toReleaseCount, DateTime expireTime)
- {
- m_CachedToReleaseObjects.Clear();
- if (expireTime > DateTime.MinValue)
- {
- for (int i = candidateObjects.Count - 1; i >= 0; i--)
- {
- if (candidateObjects[i].LastUseTime <= expireTime)
- {
- m_CachedToReleaseObjects.Add(candidateObjects[i]);
- candidateObjects.RemoveAt(i);
- continue;
- }
- }
- toReleaseCount -= m_CachedToReleaseObjects.Count;
- }
- for (int i = 0; toReleaseCount > 0 && i < candidateObjects.Count; i++)
- {
- for (int j = i + 1; j < candidateObjects.Count; j++)
- {
- if (candidateObjects[i].Priority > candidateObjects[j].Priority
- || candidateObjects[i].Priority == candidateObjects[j].Priority && candidateObjects[i].LastUseTime > candidateObjects[j].LastUseTime)
- {
- T temp = candidateObjects[i];
- candidateObjects[i] = candidateObjects[j];
- candidateObjects[j] = temp;
- }
- }
- m_CachedToReleaseObjects.Add(candidateObjects[i]);
- toReleaseCount--;
- }
- return m_CachedToReleaseObjects;
- }
- }
- }
- }
|