< Summary

Class:DCL.Pool
Assembly:PoolManager
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/PoolManager/Pool.cs
Covered lines:103
Uncovered lines:34
Coverable lines:137
Total lines:338
Line coverage:75.1% (103 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%8.795046.67%
Extract()0%110100%
Instantiate()0%110100%
InstantiateAsOriginal()0%220100%
SetupPoolableObject(...)0%33092.31%
Release(...)0%4.184077.78%
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%
OnIsQuitting()0%2100%

File(s)

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

#LineLine coverage
 1using System.Collections;
 2using System.Collections.Generic;
 3using UnityEngine;
 4using DCL.Helpers;
 5using UnityEngine.Assertions;
 6
 7namespace DCL
 8{
 9    public interface IPooledObjectInstantiator
 10    {
 11        bool IsValid(GameObject original);
 12        GameObject Instantiate(GameObject gameObject);
 13    }
 14
 15    public class Pool : ICleanable
 16    {
 17        public delegate void OnReleaseAllDlg(Pool pool);
 18
 19        public const int PREWARM_ACTIVE_MULTIPLIER = 2;
 20        public object id;
 21        public GameObject original;
 22        public GameObject container;
 23
 24        public bool persistent = false;
 25
 26        /// <summary>
 27        /// If this is set to true, all Unity components in the poolable gameObject implementing ILifecycleHandler
 28        /// will be registered and called when necessary.
 29        ///
 30        /// The interface call responsibility lies in the PoolableObject class.
 31        /// </summary>
 32        public bool useLifecycleHandlers = false;
 33
 34        public System.Action<Pool> OnCleanup;
 35
 36        public IPooledObjectInstantiator instantiator;
 37
 117138        private readonly LinkedList<PoolableObject> unusedObjects = new LinkedList<PoolableObject>();
 117139        private readonly LinkedList<PoolableObject> usedObjects = new LinkedList<PoolableObject>();
 40
 41        private int maxPrewarmCount = 0;
 42        private bool isInitialized;
 43
 044        public float lastGetTime { get; private set; }
 45
 046        public int objectsCount => unusedObjectsCount + usedObjectsCount;
 47
 048        public int unusedObjectsCount { get { return unusedObjects.Count; } }
 49
 050        public int usedObjectsCount { get { return usedObjects.Count; } }
 51
 117152        public Pool(string name, int maxPrewarmCount)
 53        {
 54#if UNITY_EDITOR
 117155            Application.quitting += OnIsQuitting;
 56#endif
 117157            if (PoolManager.USE_POOL_CONTAINERS)
 117158                container = new GameObject("Pool - " + name);
 59
 117160            this.maxPrewarmCount = maxPrewarmCount;
 117161        }
 62
 63        public void ForcePrewarm()
 64        {
 80365            if (maxPrewarmCount <= objectsCount)
 80366                return;
 67
 068            int objectsToInstantiate = Mathf.Max(0, maxPrewarmCount - objectsCount);
 069            for (int i = 0; i < objectsToInstantiate; i++)
 70            {
 071                Instantiate();
 72            }
 073        }
 74
 75        public PoolableObject Get()
 76        {
 77            // These extra instantiations during initialization are to populate pools that will be used a lot later
 82778            if (PoolManager.i.initializing && !isInitialized)
 79            {
 080                isInitialized = true;
 081                int count = usedObjectsCount;
 82
 083                for (int i = unusedObjectsCount; i < Mathf.Min(count * PREWARM_ACTIVE_MULTIPLIER, maxPrewarmCount); i++)
 84                {
 085                    Instantiate();
 86                }
 87
 088                Instantiate();
 089            }
 82790            else if (unusedObjects.Count == 0)
 91            {
 78592                Instantiate();
 93            }
 94
 82795            PoolableObject poolable = Extract();
 96
 82797            EnablePoolableObject(poolable);
 82798            poolable.OnPoolGet();
 82799            return poolable;
 100        }
 101
 102        private PoolableObject Extract()
 103        {
 827104            PoolableObject po = null;
 827105            po = unusedObjects.First.Value;
 827106            unusedObjects.RemoveFirst();
 827107            po.node = usedObjects.AddFirst(po);
 108
 109#if UNITY_EDITOR
 827110            RefreshName();
 111#endif
 827112            return po;
 113        }
 114
 115        public PoolableObject Instantiate()
 116        {
 785117            var gameObject = InstantiateAsOriginal();
 785118            return SetupPoolableObject(gameObject);
 119        }
 120
 121        public GameObject InstantiateAsOriginal()
 122        {
 807123            Assert.IsTrue(original != null, $"Original should never be null here ({id})");
 124
 807125            GameObject gameObject = null;
 126
 807127            if (instantiator != null)
 130128                gameObject = instantiator.Instantiate(original);
 129            else
 677130                gameObject = GameObject.Instantiate(original);
 131
 807132            gameObject.SetActive(true);
 133
 807134            return gameObject;
 135        }
 136
 137        private PoolableObject SetupPoolableObject(GameObject gameObject, bool active = false)
 138        {
 786139            if (PoolManager.i.poolables.ContainsKey(gameObject))
 0140                return PoolManager.i.GetPoolable(gameObject);
 141
 786142            PoolableObject poolable = new PoolableObject(this, gameObject);
 786143            PoolManager.i.poolables.Add(gameObject, poolable);
 786144            PoolManager.i.poolableValues.Add(poolable);
 145
 786146            if (!active)
 147            {
 785148                DisablePoolableObject(poolable);
 785149                poolable.node = unusedObjects.AddFirst(poolable);
 785150            }
 151            else
 152            {
 1153                EnablePoolableObject(poolable);
 1154                poolable.node = usedObjects.AddFirst(poolable);
 155            }
 156
 157#if UNITY_EDITOR
 786158            RefreshName();
 159#endif
 786160            return poolable;
 161        }
 162
 163        public void Release(PoolableObject poolable)
 164        {
 165#if UNITY_EDITOR
 828166            if (isQuitting)
 0167                return;
 168#endif
 169
 828170            if (poolable == null || !PoolManager.i.HasPoolable(poolable))
 0171                return;
 172
 828173            DisablePoolableObject(poolable);
 174
 828175            poolable.node.List.Remove(poolable.node);
 828176            poolable.node = unusedObjects.AddFirst(poolable);
 177
 178#if UNITY_EDITOR
 828179            RefreshName();
 180#endif
 828181        }
 182
 183        public void ReleaseAll()
 184        {
 1478185            while (usedObjects.Count > 0)
 186            {
 159187                usedObjects.First.Value.Release();
 188            }
 1319189        }
 190
 191        /// <summary>
 192        /// This will add a gameObject that is not on any pool to this pool.
 193        /// </summary>
 194        /// <param name="gameObject"></param>
 195        public void AddToPool(GameObject gameObject, bool addActive = true)
 196        {
 1197            if (instantiator != null && !instantiator.IsValid(gameObject))
 198            {
 0199                Debug.LogError($"ERROR: Trying to add invalid gameObject to pool! -- {gameObject.name}", gameObject);
 0200                return;
 201            }
 202
 1203            PoolableObject obj = PoolManager.i.GetPoolable(gameObject);
 204
 1205            if (obj != null)
 206            {
 0207                Debug.LogError($"ERROR: gameObject is already being tracked by a pool! -- {gameObject.name}", gameObject
 0208                return;
 209            }
 210
 1211            SetupPoolableObject(gameObject, addActive);
 1212        }
 213
 214        public void RemoveFromPool(PoolableObject poolable)
 215        {
 2216            if (poolable.node != null)
 217            {
 2218                if (poolable.node.List != null)
 0219                    poolable.node.List.Remove(poolable);
 220
 2221                poolable.node = null;
 222            }
 223
 2224            PoolManager.i.poolables.Remove(poolable.gameObject);
 2225            PoolManager.i.poolableValues.Remove(poolable);
 226#if UNITY_EDITOR
 2227            RefreshName();
 228#endif
 2229        }
 230
 231        public void Cleanup()
 232        {
 1171233            ReleaseAll();
 234
 1957235            while (unusedObjects.Count > 0)
 236            {
 786237                PoolManager.i.poolables.Remove(unusedObjects.First.Value.gameObject);
 786238                PoolManager.i.poolableValues.Remove(unusedObjects.First.Value);
 786239                unusedObjects.RemoveFirst();
 240            }
 241
 1171242            while (usedObjects.Count > 0)
 243            {
 0244                PoolManager.i.poolables.Remove(usedObjects.First.Value.gameObject);
 0245                PoolManager.i.poolableValues.Remove(usedObjects.First.Value);
 0246                usedObjects.RemoveFirst();
 247            }
 248
 1171249            unusedObjects.Clear();
 1171250            usedObjects.Clear();
 251
 1171252            Object.Destroy(this.original);
 253
 1171254            if (PoolManager.USE_POOL_CONTAINERS)
 1171255                Object.Destroy(this.container);
 256
 1171257            OnCleanup?.Invoke(this);
 121258        }
 259
 260        public void EnablePoolableObject(PoolableObject poolable)
 261        {
 828262            GameObject go = poolable.gameObject;
 263
 828264            if (go == null)
 0265                return;
 266
 828267            if (!go.activeSelf)
 827268                go.SetActive(true);
 269
 828270            go.transform.ResetLocalTRS();
 271
 828272            lastGetTime = Time.unscaledTime;
 828273        }
 274
 275        public void DisablePoolableObject(PoolableObject poolable)
 276        {
 277#if UNITY_EDITOR
 1613278            if (isQuitting)
 0279                return;
 280#endif
 1613281            GameObject go = poolable.gameObject;
 282
 1613283            if (go == null)
 36284                return;
 285
 1577286            if (go.activeSelf)
 1133287                go.SetActive(false);
 288
 1577289            if (PoolManager.USE_POOL_CONTAINERS)
 290            {
 1577291                if (container != null)
 292                {
 1577293                    go.transform.SetParent(container.transform);
 294                }
 1577295            }
 296            else
 297            {
 0298                go.transform.SetParent(null);
 299            }
 0300        }
 301
 302#if UNITY_EDITOR
 303        private void RefreshName()
 304        {
 2443305            if (this.container != null)
 2443306                this.container.name = $"in: {unusedObjectsCount} out: {usedObjectsCount} id: {id} persistent: {persisten
 2443307        }
 308#endif
 309        public static bool FindPoolInGameObject(GameObject gameObject, out Pool pool)
 310        {
 1311            pool = null;
 312
 1313            if (PoolManager.i.poolables.TryGetValue(gameObject, out PoolableObject poolable))
 314            {
 0315                pool = poolable.pool;
 0316                return true;
 317            }
 318
 1319            return false;
 320        }
 321
 12322        public bool IsValid() { return original != null; }
 323
 324#if UNITY_EDITOR
 325        // In production it will always be false
 326        private bool isQuitting = false;
 327
 328        // We need to check if application is quitting in editor
 329        // to prevent the pool from releasing objects that are
 330        // being destroyed
 331        void OnIsQuitting()
 332        {
 0333            Application.quitting -= OnIsQuitting;
 0334            isQuitting = true;
 0335        }
 336#endif
 337    }
 338};