< Summary

Class:DCL.Pool
Assembly:PoolManager
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/PoolManager/Pool.cs
Covered lines:107
Uncovered lines:24
Coverable lines:131
Total lines:320
Line coverage:81.6% (107 of 131)
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.065086.67%
Extract()0%110100%
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;
 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
 162038        private readonly LinkedList<PoolableObject> unusedObjects = new LinkedList<PoolableObject>();
 162039        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
 162052        public Pool(string name, int maxPrewarmCount)
 53        {
 162054            if (PoolManager.USE_POOL_CONTAINERS)
 162055                container = new GameObject("Pool - " + name);
 56
 162057            this.maxPrewarmCount = maxPrewarmCount;
 162058        }
 59
 60        public void ForcePrewarm()
 61        {
 116962            if (maxPrewarmCount <= objectsCount)
 116963                return;
 64
 065            int objectsToInstantiate = Mathf.Max(0, maxPrewarmCount - objectsCount);
 066            for (int i = 0; i < objectsToInstantiate; i++)
 67            {
 068                Instantiate();
 69            }
 070        }
 71
 72        /// <summary>
 73        /// This will return an instance of the poolable object
 74        /// </summary>
 75        /// <returns></returns>
 76        public PoolableObject Get()
 77        {
 78            // These extra instantiations during initialization are to populate pools that will be used a lot later
 184579            if (PoolManager.i.initializing && !isInitialized)
 80            {
 54081                isInitialized = true;
 54082                int count = usedObjectsCount;
 83
 108084                for (int i = unusedObjectsCount; i < Mathf.Min(count * PREWARM_ACTIVE_MULTIPLIER, maxPrewarmCount); i++)
 85                {
 086                    Instantiate();
 87                }
 88
 54089                Instantiate();
 54090            }
 130591            else if (unusedObjects.Count == 0)
 92            {
 124293                Instantiate();
 94            }
 95
 184596            PoolableObject poolable = Extract();
 97
 184598            EnablePoolableObject(poolable);
 184599            poolable.OnPoolGet();
 1845100            return poolable;
 101        }
 102
 103        private PoolableObject Extract()
 104        {
 1845105            PoolableObject po = null;
 1845106            po = unusedObjects.First.Value;
 1845107            unusedObjects.RemoveFirst();
 1845108            po.node = usedObjects.AddFirst(po);
 109
 110#if UNITY_EDITOR
 1845111            RefreshName();
 112#endif
 1845113            return po;
 114        }
 115
 116        public PoolableObject Instantiate()
 117        {
 1782118            var gameObject = InstantiateAsOriginal();
 1782119            return SetupPoolableObject(gameObject);
 120        }
 121
 122        public GameObject InstantiateAsOriginal()
 123        {
 1804124            Assert.IsTrue(original != null, $"Original should never be null here ({id})");
 125
 1804126            GameObject gameObject = null;
 127
 1804128            if (instantiator != null)
 131129                gameObject = instantiator.Instantiate(original);
 130            else
 1673131                gameObject = GameObject.Instantiate(original);
 132
 1804133            gameObject.SetActive(true);
 134
 1804135            return gameObject;
 136        }
 137
 138        private PoolableObject SetupPoolableObject(GameObject gameObject, bool active = false)
 139        {
 1785140            if (PoolManager.i.poolables.ContainsKey(gameObject))
 0141                return PoolManager.i.GetPoolable(gameObject);
 142
 1785143            PoolableObject poolable = new PoolableObject(this, gameObject);
 1785144            PoolManager.i.poolables.Add(gameObject, poolable);
 1785145            PoolManager.i.poolableValues.Add(poolable);
 146
 1785147            if (!active)
 148            {
 1782149                DisablePoolableObject(poolable);
 1782150                poolable.node = unusedObjects.AddFirst(poolable);
 1782151            }
 152            else
 153            {
 3154                EnablePoolableObject(poolable);
 3155                poolable.node = usedObjects.AddFirst(poolable);
 156            }
 157
 158#if UNITY_EDITOR
 1785159            RefreshName();
 160#endif
 1785161            return poolable;
 162        }
 163
 164        public void Release(PoolableObject poolable)
 165        {
 2319166            if (poolable == null || !PoolManager.i.HasPoolable(poolable))
 497167                return;
 168
 1822169            DisablePoolableObject(poolable);
 170
 1822171            poolable.node.List.Remove(poolable.node);
 1822172            poolable.node = unusedObjects.AddFirst(poolable);
 173
 174#if UNITY_EDITOR
 1822175            RefreshName();
 176#endif
 1822177        }
 178
 179        public void ReleaseAll()
 180        {
 3512181            while (usedObjects.Count > 0)
 182            {
 1640183                usedObjects.First.Value.Release();
 184            }
 1872185        }
 186
 187        /// <summary>
 188        /// This will add a gameObject that is not on any pool to this pool.
 189        /// </summary>
 190        /// <param name="gameObject"></param>
 191        public void AddToPool(GameObject gameObject, bool addActive = true)
 192        {
 3193            if (instantiator != null && !instantiator.IsValid(gameObject))
 194            {
 0195                Debug.LogError($"ERROR: Trying to add invalid gameObject to pool! -- {gameObject.name}", gameObject);
 0196                return;
 197            }
 198
 3199            PoolableObject obj = PoolManager.i.GetPoolable(gameObject);
 200
 3201            if (obj != null)
 202            {
 0203                Debug.LogError($"ERROR: gameObject is already being tracked by a pool! -- {gameObject.name}", gameObject
 0204                return;
 205            }
 206
 3207            SetupPoolableObject(gameObject, addActive);
 3208        }
 209
 210        public void RemoveFromPool(PoolableObject poolable)
 211        {
 5212            if (poolable.node != null)
 213            {
 5214                if (poolable.node.List != null)
 0215                    poolable.node.List.Remove(poolable);
 216
 5217                poolable.node = null;
 218            }
 219
 5220            PoolManager.i.poolables.Remove(poolable.gameObject);
 5221            PoolManager.i.poolableValues.Remove(poolable);
 222#if UNITY_EDITOR
 5223            RefreshName();
 224#endif
 5225        }
 226
 227        public void Cleanup()
 228        {
 1605229            ReleaseAll();
 230
 3363231            while (unusedObjects.Count > 0)
 232            {
 1758233                PoolManager.i.poolables.Remove(unusedObjects.First.Value.gameObject);
 1758234                PoolManager.i.poolableValues.Remove(unusedObjects.First.Value);
 1758235                unusedObjects.RemoveFirst();
 236            }
 237
 1605238            while (usedObjects.Count > 0)
 239            {
 0240                PoolManager.i.poolables.Remove(usedObjects.First.Value.gameObject);
 0241                PoolManager.i.poolableValues.Remove(usedObjects.First.Value);
 0242                usedObjects.RemoveFirst();
 243            }
 244
 1605245            unusedObjects.Clear();
 1605246            usedObjects.Clear();
 247
 1605248            Object.Destroy(this.original);
 249
 1605250            if (PoolManager.USE_POOL_CONTAINERS)
 1605251                Object.Destroy(this.container);
 252
 1605253            OnCleanup?.Invoke(this);
 118254        }
 255
 256        public void EnablePoolableObject(PoolableObject poolable)
 257        {
 1848258            GameObject go = poolable.gameObject;
 259
 1848260            if (go == null)
 0261                return;
 262
 1848263            if (!go.activeSelf)
 1845264                go.SetActive(true);
 265
 1848266            go.transform.ResetLocalTRS();
 267
 1848268            lastGetTime = Time.unscaledTime;
 1848269        }
 270
 271        public void DisablePoolableObject(PoolableObject poolable)
 272        {
 273#if UNITY_STANDALONE || UNITY_EDITOR
 3604274            if (DataStore.i.common.isApplicationQuitting.Get())
 0275                return;
 276#endif
 3604277            GameObject go = poolable.gameObject;
 278
 3604279            if (go == null)
 25280                return;
 281
 3579282            if (go.activeSelf)
 3577283                go.SetActive(false);
 284
 3579285            if (PoolManager.USE_POOL_CONTAINERS)
 286            {
 3579287                if (container != null)
 288                {
 3579289                    go.transform.SetParent(container.transform);
 290                }
 3579291            }
 292            else
 293            {
 0294                go.transform.SetParent(null);
 295            }
 0296        }
 297
 298#if UNITY_EDITOR
 299        private void RefreshName()
 300        {
 5457301            if (this.container != null)
 5457302                this.container.name = $"in: {unusedObjectsCount} out: {usedObjectsCount} id: {id} persistent: {persisten
 5457303        }
 304#endif
 305        public static bool FindPoolInGameObject(GameObject gameObject, out Pool pool)
 306        {
 3307            pool = null;
 308
 3309            if (PoolManager.i.poolables.TryGetValue(gameObject, out PoolableObject poolable))
 310            {
 0311                pool = poolable.pool;
 0312                return true;
 313            }
 314
 3315            return false;
 316        }
 317
 15318        public bool IsValid() { return original != null; }
 319    }
 320};