using System;
using System.Collections.Generic;
namespace OM
{
///
/// Interface for objects that want to receive spawn/despawn lifecycle callbacks from the object pool.
///
/// The type of object in the pool.
public interface IOMObjectPool
{
///
/// Called when the object is spawned from the pool.
///
/// The pool that spawned the object.
void OnSpawn(OMObjectPool pool);
///
/// Called when the object is returned (despawned) to the pool.
///
void OnDespawn();
}
///
/// A generic object pool system that supports optional spawn/despawn events and a maximum capacity.
///
/// The type of objects managed by this pool.
public class OMObjectPool
{
private readonly Func _createObjFunc;
private readonly Action _onDespawnObj;
private readonly Action _onSpawn;
private readonly bool _useIPool;
private readonly int _maxCapacity;
private readonly List _list;
private readonly List _spawned;
///
/// Gets the number of currently spawned (active) objects.
///
public int GetSpawnedCount => _spawned.Count;
///
/// Creates a new object pool.
///
/// Maximum allowed spawned objects.
/// Number of objects to pre-create and add to the pool.
/// Whether to call IOMObjectPool callbacks.
/// Delegate for creating new instances.
/// Optional callback when an object is spawned.
/// Optional callback when an object is despawned.
public OMObjectPool(int maxCapacity, int preload, bool useIPool, Func createObjFunc, Action onSpawn = null, Action onDespawn = null)
{
_createObjFunc = createObjFunc ?? throw new ArgumentNullException("Create Function is null" + nameof(createObjFunc));
_useIPool = useIPool;
_onDespawnObj = onDespawn;
_onSpawn = onSpawn;
_maxCapacity = maxCapacity;
_list = new List();
_spawned = new List();
for (var i = 0; i < preload; i++)
{
var obj = _createObjFunc();
_list.Add(obj);
}
}
///
/// Spawns an object from the pool. Creates a new one if needed.
/// Recycles old objects if max capacity is reached.
///
/// The spawned object.
public T Spawn()
{
T obj;
if (_list.Count <= 0)
{
if (_spawned.Count >= _maxCapacity)
{
obj = _spawned[0];
_spawned.RemoveAt(0);
if (_useIPool)
{
var pool = obj as IOMObjectPool;
pool?.OnDespawn();
}
}
else
{
obj = _createObjFunc();
}
}
else
{
obj = _list[0];
_list.RemoveAt(0);
}
_onSpawn?.Invoke(obj);
if (_useIPool)
{
var pool = obj as IOMObjectPool;
pool?.OnSpawn(this);
}
_spawned.Add(obj);
return obj;
}
///
/// Returns an object back to the pool.
///
/// The object to despawn.
public void Despawn(T obj)
{
_onDespawnObj?.Invoke(obj);
if (_useIPool)
{
var pool = obj as IOMObjectPool;
pool?.OnDespawn();
}
_list.Add(obj);
_spawned.Remove(obj);
}
}
}