using System; using System.Collections.Generic; namespace TEngine { internal sealed partial class ObjectPoolModule : Module, IObjectPoolModule { /// /// 对象池。 /// /// 对象类型。 private sealed class ObjectPool : ObjectPoolBase, IObjectPool where T : ObjectBase { private readonly GameFrameworkMultiDictionary> _objects; private readonly Dictionary> _objectMap; private readonly ReleaseObjectFilterCallback _defaultReleaseObjectFilterCallback; private readonly List _cachedCanReleaseObjects; private readonly List _cachedToReleaseObjects; private readonly bool _allowMultiSpawn; private float _autoReleaseInterval; private int _capacity; private float _expireTime; private int _priority; private float _autoReleaseTime; /// /// 初始化对象池的新实例。 /// /// 对象池名称。 /// 是否允许对象被多次获取。 /// 对象池自动释放可释放对象的间隔秒数。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 public ObjectPool(string name, bool allowMultiSpawn, float autoReleaseInterval, int capacity, float expireTime, int priority) : base(name) { _objects = new GameFrameworkMultiDictionary>(); _objectMap = new Dictionary>(); _defaultReleaseObjectFilterCallback = DefaultReleaseObjectFilterCallback; _cachedCanReleaseObjects = new List(); _cachedToReleaseObjects = new List(); _allowMultiSpawn = allowMultiSpawn; _autoReleaseInterval = autoReleaseInterval; Capacity = capacity; ExpireTime = expireTime; _priority = priority; _autoReleaseTime = 0f; } /// /// 获取对象池对象类型。 /// public override Type ObjectType => typeof(T); /// /// 获取对象池中对象的数量。 /// public override int Count => _objectMap.Count; /// /// 获取对象池中能被释放的对象的数量。 /// public override int CanReleaseCount { get { GetCanReleaseObjects(_cachedCanReleaseObjects); return _cachedCanReleaseObjects.Count; } } /// /// 获取是否允许对象被多次获取。 /// public override bool AllowMultiSpawn => _allowMultiSpawn; /// /// 获取或设置对象池自动释放可释放对象的间隔秒数。 /// public override float AutoReleaseInterval { get => _autoReleaseInterval; set => _autoReleaseInterval = value; } /// /// 获取或设置对象池的容量。 /// public override int Capacity { get => _capacity; set { if (value < 0) { throw new GameFrameworkException("Capacity is invalid."); } if (_capacity == value) { return; } _capacity = value; Release(); } } /// /// 获取或设置对象池对象过期秒数。 /// public override float ExpireTime { get => _expireTime; set { if (value < 0f) { throw new GameFrameworkException("ExpireTime is invalid."); } if (Math.Abs(ExpireTime - value) < 0.01f) { return; } _expireTime = value; Release(); } } /// /// 获取或设置对象池的优先级。 /// public override int Priority { get => _priority; set => _priority = value; } /// /// 创建对象。 /// /// 对象。 /// 对象是否已被获取。 public void Register(T obj, bool spawned) { if (obj == null) { throw new GameFrameworkException("Object is invalid."); } Object internalObject = Object.Create(obj, spawned); _objects.Add(obj.Name, internalObject); _objectMap.Add(obj.Target, internalObject); if (Count > _capacity) { Release(); } } /// /// 检查对象。 /// /// 要检查的对象是否存在。 public bool CanSpawn() { return CanSpawn(string.Empty); } /// /// 检查对象。 /// /// 对象名称。 /// 要检查的对象是否存在。 public bool CanSpawn(string name) { if (name == null) { throw new GameFrameworkException("Name is invalid."); } GameFrameworkLinkedListRange> objectRange = default(GameFrameworkLinkedListRange>); if (_objects.TryGetValue(name, out objectRange)) { foreach (Object internalObject in objectRange) { if (_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."); } GameFrameworkLinkedListRange> objectRange = default(GameFrameworkLinkedListRange>); if (_objects.TryGetValue(name, out objectRange)) { foreach (Object internalObject in objectRange) { if (_allowMultiSpawn || !internalObject.IsInUse) { return internalObject.Spawn(); } } } return null; } /// /// 回收对象。 /// /// 要回收的对象。 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) { throw new GameFrameworkException("Target is invalid."); } Object internalObject = GetObject(target); if (internalObject != null) { internalObject.Unspawn(); if (Count > _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)); } } /// /// 设置对象是否被加锁。 /// /// 要设置被加锁的对象。 /// 是否被加锁。 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; } if (internalObject.IsInUse || internalObject.Locked || !internalObject.CustomCanReleaseFlag) { return false; } _objects.Remove(internalObject.Name, internalObject); _objectMap.Remove(internalObject.Peek().Target); internalObject.Release(false); MemoryPool.Release(internalObject); return true; } /// /// 释放对象池中的可释放对象。 /// public override void Release() { Release(Count - _capacity, _defaultReleaseObjectFilterCallback); } /// /// 释放对象池中的可释放对象。 /// /// 尝试释放对象数量。 public override void Release(int toReleaseCount) { Release(toReleaseCount, _defaultReleaseObjectFilterCallback); } /// /// 释放对象池中的可释放对象。 /// /// 释放对象筛选函数。 public void Release(ReleaseObjectFilterCallback releaseObjectFilterCallback) { Release(Count - _capacity, releaseObjectFilterCallback); } /// /// 释放对象池中的可释放对象。 /// /// 尝试释放对象数量。 /// 释放对象筛选函数。 public void Release(int toReleaseCount, ReleaseObjectFilterCallback releaseObjectFilterCallback) { if (releaseObjectFilterCallback == null) { throw new GameFrameworkException("Release object filter callback is invalid."); } if (toReleaseCount < 0) { toReleaseCount = 0; } DateTime expireTime = DateTime.MinValue; if (_expireTime < float.MaxValue) { expireTime = DateTime.UtcNow.AddSeconds(-_expireTime); } _autoReleaseTime = 0f; GetCanReleaseObjects(_cachedCanReleaseObjects); List toReleaseObjects = releaseObjectFilterCallback(_cachedCanReleaseObjects, toReleaseCount, expireTime); if (toReleaseObjects == null || toReleaseObjects.Count <= 0) { return; } foreach (T toReleaseObject in toReleaseObjects) { ReleaseObject(toReleaseObject); } } /// /// 释放对象池中的所有未使用对象。 /// public override void ReleaseAllUnused() { _autoReleaseTime = 0f; GetCanReleaseObjects(_cachedCanReleaseObjects); foreach (T toReleaseObject in _cachedCanReleaseObjects) { ReleaseObject(toReleaseObject); } } /// /// 获取所有对象信息。 /// /// 所有对象信息。 public override ObjectInfo[] GetAllObjectInfos() { List results = new List(); foreach (KeyValuePair>> objectRanges in _objects) { foreach (Object 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) { _autoReleaseTime += realElapseSeconds; if (_autoReleaseTime < _autoReleaseInterval) { return; } Release(); } internal override void Shutdown() { foreach (KeyValuePair> objectInMap in _objectMap) { objectInMap.Value.Release(true); MemoryPool.Release(objectInMap.Value); } _objects.Clear(); _objectMap.Clear(); _cachedCanReleaseObjects.Clear(); _cachedToReleaseObjects.Clear(); } private Object GetObject(object target) { if (target == null) { throw new GameFrameworkException("Target is invalid."); } Object internalObject = null; if (_objectMap.TryGetValue(target, out internalObject)) { return internalObject; } return null; } private void GetCanReleaseObjects(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (KeyValuePair> objectInMap in _objectMap) { Object internalObject = objectInMap.Value; if (internalObject.IsInUse || internalObject.Locked || !internalObject.CustomCanReleaseFlag) { continue; } results.Add(internalObject.Peek()); } } private List DefaultReleaseObjectFilterCallback(List candidateObjects, int toReleaseCount, DateTime expireTime) { _cachedToReleaseObjects.Clear(); if (expireTime > DateTime.MinValue) { for (int i = candidateObjects.Count - 1; i >= 0; i--) { if (candidateObjects[i].LastUseTime <= expireTime) { _cachedToReleaseObjects.Add(candidateObjects[i]); candidateObjects.RemoveAt(i); continue; } } toReleaseCount -= _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; } } _cachedToReleaseObjects.Add(candidateObjects[i]); toReleaseCount--; } return _cachedToReleaseObjects; } } } }