< Summary

Class:DCL.Pool
Assembly:PoolManager
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/PoolManager/Pool.cs
Covered lines:93
Uncovered lines:42
Coverable lines:135
Total lines:335
Line coverage:68.8% (93 of 135)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
Pool(...)0%220100%
ForcePrewarm()0%6.283028.57%
Get()0%64050%
Extract()0%110100%
Instantiate()0%110100%
InstantiateAsOriginal()0%220100%
SetupPoolableObject(...)0%3.113076.92%
Release(...)0%4.184077.78%
ReleaseAll()0%220100%
AddToPool(...)0%20400%
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%6200%
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
 97238        private readonly LinkedList<PoolableObject> unusedObjects = new LinkedList<PoolableObject>();
 97239        private readonly LinkedList<PoolableObject> usedObjects = new LinkedList<PoolableObject>();
 40
 41        private int maxPrewarmCount = 0;
 42
 043        public float lastGetTime { get; private set; }
 44
 045        public int objectsCount => unusedObjectsCount + usedObjectsCount;
 46
 047        public int unusedObjectsCount { get { return unusedObjects.Count; } }
 48
 049        public int usedObjectsCount { get { return usedObjects.Count; } }
 50
 97251        public Pool(string name, int maxPrewarmCount)
 52        {
 53#if UNITY_EDITOR
 97254            Application.quitting += OnIsQuitting;
 55#endif
 97256            if (PoolManager.USE_POOL_CONTAINERS)
 97257                container = new GameObject("Pool - " + name);
 58
 97259            this.maxPrewarmCount = maxPrewarmCount;
 97260        }
 61
 62        public void ForcePrewarm()
 63        {
 62764            if (maxPrewarmCount <= objectsCount)
 62765                return;
 66
 067            for (int i = 0; i < Mathf.Max(0, maxPrewarmCount - objectsCount); i++)
 68            {
 069                Instantiate();
 70            }
 071        }
 72
 73        public PoolableObject Get()
 74        {
 75            // These extra instantiations during initialization are to populate pools that will be used a lot later
 67276            if (PoolManager.i.initializing)
 77            {
 078                int count = usedObjectsCount;
 79
 080                for (int i = unusedObjectsCount; i < Mathf.Min(count * PREWARM_ACTIVE_MULTIPLIER, maxPrewarmCount); i++)
 81                {
 082                    Instantiate();
 83                }
 84
 085                Instantiate();
 086            }
 67287            else if (unusedObjects.Count == 0)
 88            {
 63689                Instantiate();
 90            }
 91
 67292            PoolableObject poolable = Extract();
 93
 67294            EnablePoolableObject(poolable);
 67295            poolable.OnPoolGet();
 67296            return poolable;
 97        }
 98
 99        private PoolableObject Extract()
 100        {
 672101            PoolableObject po = null;
 672102            po = unusedObjects.First.Value;
 672103            unusedObjects.RemoveFirst();
 672104            po.node = usedObjects.AddFirst(po);
 105
 106#if UNITY_EDITOR
 672107            RefreshName();
 108#endif
 672109            return po;
 110        }
 111
 112        public PoolableObject Instantiate()
 113        {
 636114            var gameObject = InstantiateAsOriginal();
 636115            return SetupPoolableObject(gameObject);
 116        }
 117
 118        public GameObject InstantiateAsOriginal()
 119        {
 658120            Assert.IsTrue(original != null, "Original should never be null here");
 121
 658122            GameObject gameObject = null;
 123
 658124            if (instantiator != null)
 77125                gameObject = instantiator.Instantiate(original);
 126            else
 581127                gameObject = GameObject.Instantiate(original);
 128
 658129            gameObject.SetActive(true);
 130
 658131            return gameObject;
 132        }
 133
 134        private PoolableObject SetupPoolableObject(GameObject gameObject, bool active = false)
 135        {
 636136            if (PoolManager.i.poolables.ContainsKey(gameObject))
 0137                return PoolManager.i.GetPoolable(gameObject);
 138
 636139            PoolableObject poolable = new PoolableObject(this, gameObject);
 636140            PoolManager.i.poolables.Add(gameObject, poolable);
 636141            PoolManager.i.poolableValues.Add(poolable);
 142
 636143            if (!active)
 144            {
 636145                DisablePoolableObject(poolable);
 636146                poolable.node = unusedObjects.AddFirst(poolable);
 636147            }
 148            else
 149            {
 0150                EnablePoolableObject(poolable);
 0151                poolable.node = usedObjects.AddFirst(poolable);
 152            }
 153
 154#if UNITY_EDITOR
 636155            RefreshName();
 156#endif
 636157            return poolable;
 158        }
 159
 160        public void Release(PoolableObject poolable)
 161        {
 162#if UNITY_EDITOR
 672163            if (isQuitting)
 0164                return;
 165#endif
 166
 672167            if (poolable == null || !PoolManager.i.HasPoolable(poolable))
 0168                return;
 169
 672170            DisablePoolableObject(poolable);
 171
 672172            poolable.node.List.Remove(poolable.node);
 672173            poolable.node = unusedObjects.AddFirst(poolable);
 174
 175#if UNITY_EDITOR
 672176            RefreshName();
 177#endif
 672178        }
 179
 180        public void ReleaseAll()
 181        {
 1042182            while (usedObjects.Count > 0)
 183            {
 69184                usedObjects.First.Value.Release();
 185            }
 973186        }
 187
 188        /// <summary>
 189        /// This will add a gameObject that is not on any pool to this pool.
 190        /// </summary>
 191        /// <param name="gameObject"></param>
 192        public void AddToPool(GameObject gameObject, bool addActive = true)
 193        {
 0194            if (instantiator != null && !instantiator.IsValid(gameObject))
 195            {
 0196                Debug.LogError($"ERROR: Trying to add invalid gameObject to pool! -- {gameObject.name}", gameObject);
 0197                return;
 198            }
 199
 0200            PoolableObject obj = PoolManager.i.GetPoolable(gameObject);
 201
 0202            if (obj != null)
 203            {
 0204                Debug.LogError($"ERROR: gameObject is already being tracked by a pool! -- {gameObject.name}", gameObject
 0205                return;
 206            }
 207
 0208            SetupPoolableObject(gameObject, addActive);
 0209        }
 210
 211        public void RemoveFromPool(PoolableObject poolable)
 212        {
 1213            if (poolable.node != null)
 214            {
 1215                if (poolable.node.List != null)
 0216                    poolable.node.List.Remove(poolable);
 217
 1218                poolable.node = null;
 219            }
 220
 1221            PoolManager.i.poolables.Remove(poolable.gameObject);
 1222            PoolManager.i.poolableValues.Remove(poolable);
 223#if UNITY_EDITOR
 1224            RefreshName();
 225#endif
 1226        }
 227
 228        public void Cleanup()
 229        {
 972230            ReleaseAll();
 231
 1608232            while (unusedObjects.Count > 0)
 233            {
 636234                PoolManager.i.poolables.Remove(unusedObjects.First.Value.gameObject);
 636235                PoolManager.i.poolableValues.Remove(unusedObjects.First.Value);
 636236                unusedObjects.RemoveFirst();
 237            }
 238
 972239            while (usedObjects.Count > 0)
 240            {
 0241                PoolManager.i.poolables.Remove(usedObjects.First.Value.gameObject);
 0242                PoolManager.i.poolableValues.Remove(usedObjects.First.Value);
 0243                usedObjects.RemoveFirst();
 244            }
 245
 972246            unusedObjects.Clear();
 972247            usedObjects.Clear();
 248
 972249            Object.Destroy(this.original);
 250
 972251            if (PoolManager.USE_POOL_CONTAINERS)
 972252                Object.Destroy(this.container);
 253
 972254            OnCleanup?.Invoke(this);
 71255        }
 256
 257        public void EnablePoolableObject(PoolableObject poolable)
 258        {
 672259            GameObject go = poolable.gameObject;
 260
 672261            if (go == null)
 0262                return;
 263
 672264            if (!go.activeSelf)
 672265                go.SetActive(true);
 266
 672267            go.transform.ResetLocalTRS();
 268
 672269            lastGetTime = Time.unscaledTime;
 672270        }
 271
 272        public void DisablePoolableObject(PoolableObject poolable)
 273        {
 274#if UNITY_EDITOR
 1308275            if (isQuitting)
 0276                return;
 277#endif
 1308278            GameObject go = poolable.gameObject;
 279
 1308280            if (go == null)
 31281                return;
 282
 1277283            if (go.activeSelf)
 850284                go.SetActive(false);
 285
 1277286            if (PoolManager.USE_POOL_CONTAINERS)
 287            {
 1277288                if (container != null)
 289                {
 1277290                    go.transform.SetParent(container.transform);
 291                }
 1277292            }
 293            else
 294            {
 0295                go.transform.SetParent(null);
 296            }
 0297        }
 298
 299#if UNITY_EDITOR
 300        private void RefreshName()
 301        {
 1981302            if (this.container != null)
 1975303                this.container.name = $"in: {unusedObjectsCount} out: {usedObjectsCount} id: {id} persistent: {persisten
 1981304        }
 305#endif
 306        public static bool FindPoolInGameObject(GameObject gameObject, out Pool pool)
 307        {
 0308            pool = null;
 309
 0310            if (PoolManager.i.poolables.TryGetValue(gameObject, out PoolableObject poolable))
 311            {
 0312                pool = poolable.pool;
 0313                return true;
 314            }
 315
 0316            return false;
 317        }
 318
 10319        public bool IsValid() { return original != null; }
 320
 321#if UNITY_EDITOR
 322        // In production it will always be false
 323        private bool isQuitting = false;
 324
 325        // We need to check if application is quitting in editor
 326        // to prevent the pool from releasing objects that are
 327        // being destroyed
 328        void OnIsQuitting()
 329        {
 0330            Application.quitting -= OnIsQuitting;
 0331            isQuitting = true;
 0332        }
 333#endif
 334    }
 335};