// 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); } } }