< Summary

Class:DCL.Pool
Assembly:PoolManager
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/PoolManager/Pool.cs
Covered lines:110
Uncovered lines:27
Coverable lines:137
Total lines:333
Line coverage:80.2% (110 of 137)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
Pool(...)0%220100%
ForcePrewarm()0%6.83025%
Get()0%5.075085.71%
Extract()0%110100%
PrewarmAsync()0%11.445036.36%
Instantiate()0%110100%
InstantiateAsOriginal()0%220100%
SetupPoolableObject(...)0%33092.31%
Release(...)0%330100%
ReleaseAll()0%220100%
AddToPool(...)0%5.44055.56%
RemoveFromPool(...)0%3.023087.5%
Cleanup()0%5.165081.25%
EnablePoolableObject(...)0%3.023087.5%
DisablePoolableObject(...)0%6.446076.92%
RefreshName()0%220100%
FindPoolInGameObject(...)0%2.262060%
IsValid()0%110100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/PoolManager/Pool.cs

#LineLine coverage
 1using System.Collections.Generic;
 2using System.Threading;
 3using Cysharp.Threading.Tasks;
 4using UnityEngine;
 5using DCL.Helpers;
 6using UnityEngine.Assertions;
 7
 8namespace DCL
 9{
 10    public interface IPooledObjectInstantiator
 11    {
 12        bool IsValid(GameObject original);
 13        GameObject Instantiate(GameObject gameObject);
 14    }
 15
 16    public class Pool : ICleanable
 17    {
 18        public delegate void OnReleaseAllDlg(Pool pool);
 19
 20        public const int PREWARM_ACTIVE_MULTIPLIER = 2;
 21        public object id;
 22        public GameObject original;
 23        public GameObject container;
 24
 25        public bool persistent = false;
 26
 27        /// <summary>
 28        /// If this is set to true, all Unity components in the poolable gameObject implementing ILifecycleHandler
 29        /// will be registered and called when necessary.
 30        ///
 31        /// The interface call responsibility lies in the PoolableObject class.
 32        /// </summary>
 33        public bool useLifecycleHandlers = false;
 34
 35        public System.Action<Pool> OnCleanup;
 36
 37        public IPooledObjectInstantiator instantiator;
 38
 164139        private readonly LinkedList<PoolableObject> unusedObjects = new LinkedList<PoolableObject>();
 164140        private readonly LinkedList<PoolableObject> usedObjects = new LinkedList<PoolableObject>();
 41
 42        private readonly int maxPrewarmCount;
 43
 44        private bool isInitialized;
 45
 046        public float lastGetTime { get; private set; }
 47
 048        public int objectsCount => unusedObjectsCount + usedObjectsCount;
 49
 050        public int unusedObjectsCount => unusedObjects.Count;
 51
 052        public int usedObjectsCount => usedObjects.Count;
 53
 164154        public Pool(string name, int maxPrewarmCount)
 55        {
 164156            if (PoolManager.USE_POOL_CONTAINERS)
 164157                container = new GameObject("Pool - " + name);
 58
 164159            this.maxPrewarmCount = maxPrewarmCount;
 164160        }
 61
 62        public void ForcePrewarm()
 63        {
 117564            if (maxPrewarmCount <= objectsCount)
 117565                return;
 66
 067            int objectsToInstantiate = Mathf.Max(0, maxPrewarmCount - objectsCount);
 068            for (int i = 0; i < objectsToInstantiate; i++)
 69            {
 070                Instantiate();
 71            }
 072        }
 73
 74        /// <summary>
 75        /// This will return an instance of the poolable object
 76        /// </summary>
 77        /// <returns></returns>
 78        public PoolableObject Get()
 79        {
 80            // These extra instantiations during initialization are to populate pools that will be used a lot later
 192281            if (PoolManager.i.initializing && !isInitialized)
 82            {
 56283                isInitialized = true;
 84
 112485                for (int i = unusedObjectsCount; i < Mathf.Min(usedObjectsCount * PREWARM_ACTIVE_MULTIPLIER, maxPrewarmC
 086                    Instantiate();
 87
 56288                Instantiate();
 56289            }
 136090            else if (unusedObjects.Count == 0)
 91            {
 126092                Instantiate();
 93            }
 94
 192295            PoolableObject poolable = Extract();
 96
 192297            EnablePoolableObject(poolable);
 192298            poolable.OnPoolGet();
 192299            return poolable;
 100        }
 101
 102        private PoolableObject Extract()
 103        {
 1922104            PoolableObject po = null;
 1922105            po = unusedObjects.First.Value;
 1922106            unusedObjects.RemoveFirst();
 1922107            po.node = usedObjects.AddFirst(po);
 108
 109#if UNITY_EDITOR
 1922110            RefreshName();
 111#endif
 1922112            return po;
 113        }
 114
 115        public async UniTask PrewarmAsync(int prewarmCount, CancellationToken cancellationToken)
 116        {
 4117            cancellationToken.ThrowIfCancellationRequested();
 118
 4119            if (unusedObjects.Count >= prewarmCount)
 4120                return;
 121
 0122            for (int i = 0; i < prewarmCount; i++)
 123            {
 0124                Instantiate();
 0125                await UniTask.NextFrame(cancellationToken);
 126            }
 4127        }
 128
 129        public PoolableObject Instantiate()
 130        {
 1822131            var gameObject = InstantiateAsOriginal();
 1822132            return SetupPoolableObject(gameObject);
 133        }
 134
 135        public GameObject InstantiateAsOriginal()
 136        {
 1844137            Assert.IsTrue(original != null, $"Original should never be null here ({id})");
 138
 1844139            GameObject gameObject = null;
 140
 1844141            if (instantiator != null)
 141142                gameObject = instantiator.Instantiate(original);
 143            else
 1703144                gameObject = GameObject.Instantiate(original);
 145
 1844146            gameObject.SetActive(true);
 147
 1844148            return gameObject;
 149        }
 150
 151        private PoolableObject SetupPoolableObject(GameObject gameObject, bool active = false)
 152        {
 1825153            if (PoolManager.i.poolables.ContainsKey(gameObject))
 0154                return PoolManager.i.GetPoolable(gameObject);
 155
 1825156            PoolableObject poolable = new PoolableObject(this, gameObject);
 1825157            PoolManager.i.poolables.Add(gameObject, poolable);
 1825158            PoolManager.i.poolableValues.Add(poolable);
 159
 1825160            if (!active)
 161            {
 1822162                DisablePoolableObject(poolable);
 1822163                poolable.node = unusedObjects.AddFirst(poolable);
 1822164            }
 165            else
 166            {
 3167                EnablePoolableObject(poolable);
 3168                poolable.node = usedObjects.AddFirst(poolable);
 169            }
 170
 171#if UNITY_EDITOR
 1825172            RefreshName();
 173#endif
 1825174            return poolable;
 175        }
 176
 177        public void Release(PoolableObject poolable)
 178        {
 2413179            if (poolable == null || !PoolManager.i.HasPoolable(poolable))
 508180                return;
 181
 1905182            DisablePoolableObject(poolable);
 183
 1905184            poolable.node.List.Remove(poolable.node);
 1905185            poolable.node = unusedObjects.AddFirst(poolable);
 186
 187#if UNITY_EDITOR
 1905188            RefreshName();
 189#endif
 1905190        }
 191
 192        public void ReleaseAll()
 193        {
 3596194            while (usedObjects.Count > 0)
 195            {
 1696196                usedObjects.First.Value.Release();
 197            }
 1900198        }
 199
 200        /// <summary>
 201        /// This will add a gameObject that is not on any pool to this pool.
 202        /// </summary>
 203        /// <param name="gameObject"></param>
 204        public void AddToPool(GameObject gameObject, bool addActive = true)
 205        {
 3206            if (instantiator != null && !instantiator.IsValid(gameObject))
 207            {
 0208                Debug.LogError($"ERROR: Trying to add invalid gameObject to pool! -- {gameObject.name}", gameObject);
 0209                return;
 210            }
 211
 3212            PoolableObject obj = PoolManager.i.GetPoolable(gameObject);
 213
 3214            if (obj != null)
 215            {
 0216                Debug.LogError($"ERROR: gameObject is already being tracked by a pool! -- {gameObject.name}", gameObject
 0217                return;
 218            }
 219
 3220            SetupPoolableObject(gameObject, addActive);
 3221        }
 222
 223        public void RemoveFromPool(PoolableObject poolable)
 224        {
 5225            if (poolable.node != null)
 226            {
 5227                if (poolable.node.List != null)
 0228                    poolable.node.List.Remove(poolable);
 229
 5230                poolable.node = null;
 231            }
 232
 5233            PoolManager.i.poolables.Remove(poolable.gameObject);
 5234            PoolManager.i.poolableValues.Remove(poolable);
 235#if UNITY_EDITOR
 5236            RefreshName();
 237#endif
 5238        }
 239
 240        public void Cleanup()
 241        {
 1623242            ReleaseAll();
 243
 3419244            while (unusedObjects.Count > 0)
 245            {
 1796246                PoolManager.i.poolables.Remove(unusedObjects.First.Value.gameObject);
 1796247                PoolManager.i.poolableValues.Remove(unusedObjects.First.Value);
 1796248                unusedObjects.RemoveFirst();
 249            }
 250
 1623251            while (usedObjects.Count > 0)
 252            {
 0253                PoolManager.i.poolables.Remove(usedObjects.First.Value.gameObject);
 0254                PoolManager.i.poolableValues.Remove(usedObjects.First.Value);
 0255                usedObjects.RemoveFirst();
 256            }
 257
 1623258            unusedObjects.Clear();
 1623259            usedObjects.Clear();
 260
 1623261            Object.Destroy(this.original);
 262
 1623263            if (PoolManager.USE_POOL_CONTAINERS)
 1623264                Object.Destroy(this.container);
 265
 1623266            OnCleanup?.Invoke(this);
 128267        }
 268
 269        public void EnablePoolableObject(PoolableObject poolable)
 270        {
 1925271            GameObject go = poolable.gameObject;
 272
 1925273            if (go == null)
 0274                return;
 275
 1925276            if (!go.activeSelf)
 1922277                go.SetActive(true);
 278
 1925279            go.transform.ResetLocalTRS();
 280
 1925281            lastGetTime = Time.unscaledTime;
 1925282        }
 283
 284        public void DisablePoolableObject(PoolableObject poolable)
 285        {
 286#if UNITY_STANDALONE || UNITY_EDITOR
 3727287            if (DataStore.i.common.isApplicationQuitting.Get())
 0288                return;
 289#endif
 3727290            GameObject go = poolable.gameObject;
 291
 3727292            if (go == null)
 29293                return;
 294
 3698295            if (go.activeSelf)
 3695296                go.SetActive(false);
 297
 3698298            if (PoolManager.USE_POOL_CONTAINERS)
 299            {
 3698300                if (container != null)
 301                {
 3698302                    go.transform.SetParent(container.transform);
 303                }
 3698304            }
 305            else
 306            {
 0307                go.transform.SetParent(null);
 308            }
 0309        }
 310
 311#if UNITY_EDITOR
 312        private void RefreshName()
 313        {
 5657314            if (this.container != null)
 5657315                this.container.name = $"in: {unusedObjectsCount} out: {usedObjectsCount} id: {id} persistent: {persisten
 5657316        }
 317#endif
 318        public static bool FindPoolInGameObject(GameObject gameObject, out Pool pool)
 319        {
 3320            pool = null;
 321
 3322            if (PoolManager.i.poolables.TryGetValue(gameObject, out PoolableObject poolable))
 323            {
 0324                pool = poolable.pool;
 0325                return true;
 326            }
 327
 3328            return false;
 329        }
 330
 15331        public bool IsValid() { return original != null; }
 332    }
 333};