// Copyright (c) 2015 - 2023 Doozy Entertainment. All Rights Reserved.
// This code can only be used under the standard Unity Asset Store End User License Agreement
// A Copy of the EULA APPENDIX 1 is available at http://unity3d.com/company/legal/as_terms
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnassignedField.Global
namespace Doozy.Runtime.Pooler
{
/// Pooling system for anything that implements the interface
/// Any type that implements the interface
public class PoolService where T : IPoolable, new()
{
/// Maximum number of items this pool can manage
public int maxPoolSize { get; private set; }
///
/// Action invoked every time an operation is performed on the pool
/// ActionsEnabled needs to be TRUE for this action to work
///
public UnityAction OnPoolUpdate;
///
/// Action invoked every time an item is added to the pool
/// ActionsEnabled needs to be TRUE for this action to work
///
public UnityAction OnItemAddedToPool;
///
/// Action invoked every time an item is retrieved from the pool (includes newly created items)
/// ActionsEnabled needs to be TRUE for this action to work
///
public UnityAction OnItemRetrievedFromPool;
/// Flag used to enable/disable the pool's callbacks
public bool CallbacksEnabled = false;
/// All pooled items. Use Get() to retrieve an item for the pool!
private List pool { get; set; } = new List();
private bool initialized { get; set; }
private void Initialize()
{
if (initialized) return;
pool ??= new List();
maxPoolSize = -1;
initialized = true;
}
/// Get an item either from the pool or a new one, if the pool does not contain it
public T Get()
{
Initialize();
RemoveNulls();
var item = default(T);
bool itemFoundInPool = false;
foreach (T pooledItem in pool)
{
if (!(pooledItem is {} castedItem)) continue;
pool.Remove(castedItem);
item = castedItem;
itemFoundInPool = true;
break;
}
// item = itemFoundInPool ? item : Activator.CreateInstance();
item = itemFoundInPool ? item : new T();
item.inPool = false;
item.Reset();
if (!CallbacksEnabled)
return item;
OnPoolUpdate?.Invoke();
OnItemRetrievedFromPool?.Invoke(item);
return item;
}
/// Add item to pool
public void AddToPool(T item)
{
Initialize();
if (item == null)
return;
if (maxPoolSize > 0 && pool.Count > maxPoolSize)
{
item.Dispose();
return;
}
item.Reset();
if (!pool.Contains(item)) pool.Add(item);
item.inPool = true;
if (!CallbacksEnabled)
return;
OnPoolUpdate?.Invoke();
OnItemAddedToPool?.Invoke(item);
}
/// Create a given number of new items and add them to the pool
/// Number of items to be created and added to the pool
public void PreloadPool(int numberOfItems)
{
Initialize();
numberOfItems = Mathf.Max(0, numberOfItems);
for (int i = 0; i < numberOfItems; i++)
{
// T newItem = Activator.CreateInstance();
var newItem = new T
{
inPool = false
};
AddToPool(newItem);
}
if (CallbacksEnabled) OnPoolUpdate?.Invoke();
}
/// Resize the pool to the given size. Destroy and remove items from the pool until it reaches the desired size.
/// Maximum number of items left in the pool after this method run
public void TrimPool(int targetPoolSize)
{
Initialize();
targetPoolSize = Mathf.Max(0, targetPoolSize);
if (pool.Count <= targetPoolSize) return;
while (pool.Count > targetPoolSize)
{
int lastPoolItemIndex = pool.Count - 1;
pool[lastPoolItemIndex].Dispose();
pool.RemoveAt(lastPoolItemIndex);
}
if (CallbacksEnabled) OnPoolUpdate?.Invoke();
}
/// Set a maximum pool size. If the pool size reaches the maximum value, any new item added to the pool will get automatically destroyed
/// This also resizes the pool (to save memory)
public void SetMaximumPoolSize(int size)
{
Initialize();
maxPoolSize = size;
TrimPool(maxPoolSize);
if (CallbacksEnabled) OnPoolUpdate?.Invoke();
}
/// Clears the maximum pool size limitation
public void ClearMaxPoolSize()
{
Initialize();
maxPoolSize = -1;
}
/// Call Destroy on all pooled items and then clear the pool
/// Clear the maximum pool size limitation
public void ClearPool(bool clearMaxPoolSize = false)
{
Initialize();
foreach (T item in pool)
item.Dispose();
pool.Clear();
if (clearMaxPoolSize) ClearMaxPoolSize();
if (CallbacksEnabled) OnPoolUpdate?.Invoke();
}
private void RemoveNulls()
{
Initialize();
for (int i = pool.Count - 1; i >= 0; i--)
if (pool[i] == null)
pool.RemoveAt(i);
}
}
}