< Summary

Class:DCL.Pool
Assembly:PoolManager
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/PoolManager/Pool.cs
Covered lines:101
Uncovered lines:30
Coverable lines:131
Total lines:316
Line coverage:77% (101 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%8.795046.67%
Extract()0%110100%
Instantiate()0%110100%
InstantiateAsOriginal()0%220100%
SetupPoolableObject(...)0%33092.31%
Release(...)0%3.033085.71%
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
 179638        private readonly LinkedList<PoolableObject> unusedObjects = new LinkedList<PoolableObject>();
 179639        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
 179652        public Pool(string name, int maxPrewarmCount)
 53        {
 179654            if (PoolManager.USE_POOL_CONTAINERS)
 179655                container = new GameObject("Pool - " + name);
 56
 179657            this.maxPrewarmCount = maxPrewarmCount;
 179658        }
 59
 60        public void ForcePrewarm()
 61        {
 216162            if (maxPrewarmCount <= objectsCount)
 216163                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        public PoolableObject Get()
 73        {
 74            // These extra instantiations during initialization are to populate pools that will be used a lot later
 85275            if (PoolManager.i.initializing && !isInitialized)
 76            {
 077                isInitialized = true;
 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            }
 85287            else if (unusedObjects.Count == 0)
 88            {
 80589                Instantiate();
 90            }
 91
 85292            PoolableObject poolable = Extract();
 93
 85294            EnablePoolableObject(poolable);
 85295            poolable.OnPoolGet();
 85296            return poolable;
 97        }
 98
 99        private PoolableObject Extract()
 100        {
 852101            PoolableObject po = null;
 852102            po = unusedObjects.First.Value;
 852103            unusedObjects.RemoveFirst();
 852104            po.node = usedObjects.AddFirst(po);
 105
 106#if UNITY_EDITOR
 852107            RefreshName();
 108#endif
 852109            return po;
 110        }
 111
 112        public PoolableObject Instantiate()
 113        {
 805114            var gameObject = InstantiateAsOriginal();
 805115            return SetupPoolableObject(gameObject);
 116        }
 117
 118        public GameObject InstantiateAsOriginal()
 119        {
 827120            Assert.IsTrue(original != null, $"Original should never be null here ({id})");
 121
 827122            GameObject gameObject = null;
 123
 827124            if (instantiator != null)
 122125                gameObject = instantiator.Instantiate(original);
 126            else
 705127                gameObject = GameObject.Instantiate(original);
 128
 827129            gameObject.SetActive(true);
 130
 827131            return gameObject;
 132        }
 133
 134        private PoolableObject SetupPoolableObject(GameObject gameObject, bool active = false)
 135        {
 806136            if (PoolManager.i.poolables.ContainsKey(gameObject))
 0137                return PoolManager.i.GetPoolable(gameObject);
 138
 806139            PoolableObject poolable = new PoolableObject(this, gameObject);
 806140            PoolManager.i.poolables.Add(gameObject, poolable);
 806141            PoolManager.i.poolableValues.Add(poolable);
 142
 806143            if (!active)
 144            {
 805145                DisablePoolableObject(poolable);
 805146                poolable.node = unusedObjects.AddFirst(poolable);
 805147            }
 148            else
 149            {
 1150                EnablePoolableObject(poolable);
 1151                poolable.node = usedObjects.AddFirst(poolable);
 152            }
 153
 154#if UNITY_EDITOR
 806155            RefreshName();
 156#endif
 806157            return poolable;
 158        }
 159
 160        public void Release(PoolableObject poolable)
 161        {
 853162            if (poolable == null || !PoolManager.i.HasPoolable(poolable))
 0163                return;
 164
 853165            DisablePoolableObject(poolable);
 166
 853167            poolable.node.List.Remove(poolable.node);
 853168            poolable.node = unusedObjects.AddFirst(poolable);
 169
 170#if UNITY_EDITOR
 853171            RefreshName();
 172#endif
 853173        }
 174
 175        public void ReleaseAll()
 176        {
 2604177            while (usedObjects.Count > 0)
 178            {
 655179                usedObjects.First.Value.Release();
 180            }
 1949181        }
 182
 183        /// <summary>
 184        /// This will add a gameObject that is not on any pool to this pool.
 185        /// </summary>
 186        /// <param name="gameObject"></param>
 187        public void AddToPool(GameObject gameObject, bool addActive = true)
 188        {
 1189            if (instantiator != null && !instantiator.IsValid(gameObject))
 190            {
 0191                Debug.LogError($"ERROR: Trying to add invalid gameObject to pool! -- {gameObject.name}", gameObject);
 0192                return;
 193            }
 194
 1195            PoolableObject obj = PoolManager.i.GetPoolable(gameObject);
 196
 1197            if (obj != null)
 198            {
 0199                Debug.LogError($"ERROR: gameObject is already being tracked by a pool! -- {gameObject.name}", gameObject
 0200                return;
 201            }
 202
 1203            SetupPoolableObject(gameObject, addActive);
 1204        }
 205
 206        public void RemoveFromPool(PoolableObject poolable)
 207        {
 2208            if (poolable.node != null)
 209            {
 2210                if (poolable.node.List != null)
 0211                    poolable.node.List.Remove(poolable);
 212
 2213                poolable.node = null;
 214            }
 215
 2216            PoolManager.i.poolables.Remove(poolable.gameObject);
 2217            PoolManager.i.poolableValues.Remove(poolable);
 218#if UNITY_EDITOR
 2219            RefreshName();
 220#endif
 2221        }
 222
 223        public void Cleanup()
 224        {
 1796225            ReleaseAll();
 226
 2602227            while (unusedObjects.Count > 0)
 228            {
 806229                PoolManager.i.poolables.Remove(unusedObjects.First.Value.gameObject);
 806230                PoolManager.i.poolableValues.Remove(unusedObjects.First.Value);
 806231                unusedObjects.RemoveFirst();
 232            }
 233
 1796234            while (usedObjects.Count > 0)
 235            {
 0236                PoolManager.i.poolables.Remove(usedObjects.First.Value.gameObject);
 0237                PoolManager.i.poolableValues.Remove(usedObjects.First.Value);
 0238                usedObjects.RemoveFirst();
 239            }
 240
 1796241            unusedObjects.Clear();
 1796242            usedObjects.Clear();
 243
 1796244            Object.Destroy(this.original);
 245
 1796246            if (PoolManager.USE_POOL_CONTAINERS)
 1796247                Object.Destroy(this.container);
 248
 1796249            OnCleanup?.Invoke(this);
 109250        }
 251
 252        public void EnablePoolableObject(PoolableObject poolable)
 253        {
 853254            GameObject go = poolable.gameObject;
 255
 853256            if (go == null)
 0257                return;
 258
 853259            if (!go.activeSelf)
 852260                go.SetActive(true);
 261
 853262            go.transform.ResetLocalTRS();
 263
 853264            lastGetTime = Time.unscaledTime;
 853265        }
 266
 267        public void DisablePoolableObject(PoolableObject poolable)
 268        {
 269#if UNITY_STANDALONE || UNITY_EDITOR
 1658270            if (DataStore.i.common.isApplicationQuitting.Get())
 0271                return;
 272#endif
 1658273            GameObject go = poolable.gameObject;
 274
 1658275            if (go == null)
 56276                return;
 277
 1602278            if (go.activeSelf)
 1600279                go.SetActive(false);
 280
 1602281            if (PoolManager.USE_POOL_CONTAINERS)
 282            {
 1602283                if (container != null)
 284                {
 1602285                    go.transform.SetParent(container.transform);
 286                }
 1602287            }
 288            else
 289            {
 0290                go.transform.SetParent(null);
 291            }
 0292        }
 293
 294#if UNITY_EDITOR
 295        private void RefreshName()
 296        {
 2513297            if (this.container != null)
 2513298                this.container.name = $"in: {unusedObjectsCount} out: {usedObjectsCount} id: {id} persistent: {persisten
 2513299        }
 300#endif
 301        public static bool FindPoolInGameObject(GameObject gameObject, out Pool pool)
 302        {
 1303            pool = null;
 304
 1305            if (PoolManager.i.poolables.TryGetValue(gameObject, out PoolableObject poolable))
 306            {
 0307                pool = poolable.pool;
 0308                return true;
 309            }
 310
 1311            return false;
 312        }
 313
 12314        public bool IsValid() { return original != null; }
 315    }
 316};