< 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:33
Coverable lines:136
Total lines:337
Line coverage:75.7% (103 of 136)
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%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
 121738        private readonly LinkedList<PoolableObject> unusedObjects = new LinkedList<PoolableObject>();
 121739        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
 121752        public Pool(string name, int maxPrewarmCount)
 53        {
 54#if UNITY_EDITOR
 121755            Application.quitting += OnIsQuitting;
 56#endif
 121757            if (PoolManager.USE_POOL_CONTAINERS)
 121758                container = new GameObject("Pool - " + name);
 59
 121760            this.maxPrewarmCount = maxPrewarmCount;
 121761        }
 62
 63        public void ForcePrewarm()
 64        {
 77465            if (maxPrewarmCount <= objectsCount)
 77466                return;
 67
 068            for (int i = 0; i < Mathf.Max(0, maxPrewarmCount - objectsCount); i++)
 69            {
 070                Instantiate();
 71            }
 072        }
 73
 74        public PoolableObject Get()
 75        {
 76            // These extra instantiations during initialization are to populate pools that will be used a lot later
 79377            if (PoolManager.i.initializing && !isInitialized)
 78            {
 079                isInitialized = true;
 080                int count = usedObjectsCount;
 81
 082                for (int i = unusedObjectsCount; i < Mathf.Min(count * PREWARM_ACTIVE_MULTIPLIER, maxPrewarmCount); i++)
 83                {
 084                    Instantiate();
 85                }
 86
 087                Instantiate();
 088            }
 79389            else if (unusedObjects.Count == 0)
 90            {
 75591                Instantiate();
 92            }
 93
 79394            PoolableObject poolable = Extract();
 95
 79396            EnablePoolableObject(poolable);
 79397            poolable.OnPoolGet();
 79398            return poolable;
 99        }
 100
 101        private PoolableObject Extract()
 102        {
 793103            PoolableObject po = null;
 793104            po = unusedObjects.First.Value;
 793105            unusedObjects.RemoveFirst();
 793106            po.node = usedObjects.AddFirst(po);
 107
 108#if UNITY_EDITOR
 793109            RefreshName();
 110#endif
 793111            return po;
 112        }
 113
 114        public PoolableObject Instantiate()
 115        {
 755116            var gameObject = InstantiateAsOriginal();
 755117            return SetupPoolableObject(gameObject);
 118        }
 119
 120        public GameObject InstantiateAsOriginal()
 121        {
 777122            Assert.IsTrue(original != null, $"Original should never be null here ({id})");
 123
 777124            GameObject gameObject = null;
 125
 777126            if (instantiator != null)
 121127                gameObject = instantiator.Instantiate(original);
 128            else
 656129                gameObject = GameObject.Instantiate(original);
 130
 777131            gameObject.SetActive(true);
 132
 777133            return gameObject;
 134        }
 135
 136        private PoolableObject SetupPoolableObject(GameObject gameObject, bool active = false)
 137        {
 756138            if (PoolManager.i.poolables.ContainsKey(gameObject))
 0139                return PoolManager.i.GetPoolable(gameObject);
 140
 756141            PoolableObject poolable = new PoolableObject(this, gameObject);
 756142            PoolManager.i.poolables.Add(gameObject, poolable);
 756143            PoolManager.i.poolableValues.Add(poolable);
 144
 756145            if (!active)
 146            {
 755147                DisablePoolableObject(poolable);
 755148                poolable.node = unusedObjects.AddFirst(poolable);
 755149            }
 150            else
 151            {
 1152                EnablePoolableObject(poolable);
 1153                poolable.node = usedObjects.AddFirst(poolable);
 154            }
 155
 156#if UNITY_EDITOR
 756157            RefreshName();
 158#endif
 756159            return poolable;
 160        }
 161
 162        public void Release(PoolableObject poolable)
 163        {
 164#if UNITY_EDITOR
 794165            if (isQuitting)
 0166                return;
 167#endif
 168
 794169            if (poolable == null || !PoolManager.i.HasPoolable(poolable))
 0170                return;
 171
 794172            DisablePoolableObject(poolable);
 173
 794174            poolable.node.List.Remove(poolable.node);
 794175            poolable.node = unusedObjects.AddFirst(poolable);
 176
 177#if UNITY_EDITOR
 794178            RefreshName();
 179#endif
 794180        }
 181
 182        public void ReleaseAll()
 183        {
 1292184            while (usedObjects.Count > 0)
 185            {
 74186                usedObjects.First.Value.Release();
 187            }
 1218188        }
 189
 190        /// <summary>
 191        /// This will add a gameObject that is not on any pool to this pool.
 192        /// </summary>
 193        /// <param name="gameObject"></param>
 194        public void AddToPool(GameObject gameObject, bool addActive = true)
 195        {
 1196            if (instantiator != null && !instantiator.IsValid(gameObject))
 197            {
 0198                Debug.LogError($"ERROR: Trying to add invalid gameObject to pool! -- {gameObject.name}", gameObject);
 0199                return;
 200            }
 201
 1202            PoolableObject obj = PoolManager.i.GetPoolable(gameObject);
 203
 1204            if (obj != null)
 205            {
 0206                Debug.LogError($"ERROR: gameObject is already being tracked by a pool! -- {gameObject.name}", gameObject
 0207                return;
 208            }
 209
 1210            SetupPoolableObject(gameObject, addActive);
 1211        }
 212
 213        public void RemoveFromPool(PoolableObject poolable)
 214        {
 2215            if (poolable.node != null)
 216            {
 2217                if (poolable.node.List != null)
 0218                    poolable.node.List.Remove(poolable);
 219
 2220                poolable.node = null;
 221            }
 222
 2223            PoolManager.i.poolables.Remove(poolable.gameObject);
 2224            PoolManager.i.poolableValues.Remove(poolable);
 225#if UNITY_EDITOR
 2226            RefreshName();
 227#endif
 2228        }
 229
 230        public void Cleanup()
 231        {
 1217232            ReleaseAll();
 233
 1973234            while (unusedObjects.Count > 0)
 235            {
 756236                PoolManager.i.poolables.Remove(unusedObjects.First.Value.gameObject);
 756237                PoolManager.i.poolableValues.Remove(unusedObjects.First.Value);
 756238                unusedObjects.RemoveFirst();
 239            }
 240
 1217241            while (usedObjects.Count > 0)
 242            {
 0243                PoolManager.i.poolables.Remove(usedObjects.First.Value.gameObject);
 0244                PoolManager.i.poolableValues.Remove(usedObjects.First.Value);
 0245                usedObjects.RemoveFirst();
 246            }
 247
 1217248            unusedObjects.Clear();
 1217249            usedObjects.Clear();
 250
 1217251            Object.Destroy(this.original);
 252
 1217253            if (PoolManager.USE_POOL_CONTAINERS)
 1217254                Object.Destroy(this.container);
 255
 1217256            OnCleanup?.Invoke(this);
 111257        }
 258
 259        public void EnablePoolableObject(PoolableObject poolable)
 260        {
 794261            GameObject go = poolable.gameObject;
 262
 794263            if (go == null)
 0264                return;
 265
 794266            if (!go.activeSelf)
 793267                go.SetActive(true);
 268
 794269            go.transform.ResetLocalTRS();
 270
 794271            lastGetTime = Time.unscaledTime;
 794272        }
 273
 274        public void DisablePoolableObject(PoolableObject poolable)
 275        {
 276#if UNITY_EDITOR
 1549277            if (isQuitting)
 0278                return;
 279#endif
 1549280            GameObject go = poolable.gameObject;
 281
 1549282            if (go == null)
 33283                return;
 284
 1516285            if (go.activeSelf)
 1027286                go.SetActive(false);
 287
 1516288            if (PoolManager.USE_POOL_CONTAINERS)
 289            {
 1516290                if (container != null)
 291                {
 1516292                    go.transform.SetParent(container.transform);
 293                }
 1516294            }
 295            else
 296            {
 0297                go.transform.SetParent(null);
 298            }
 0299        }
 300
 301#if UNITY_EDITOR
 302        private void RefreshName()
 303        {
 2345304            if (this.container != null)
 2337305                this.container.name = $"in: {unusedObjectsCount} out: {usedObjectsCount} id: {id} persistent: {persisten
 2345306        }
 307#endif
 308        public static bool FindPoolInGameObject(GameObject gameObject, out Pool pool)
 309        {
 1310            pool = null;
 311
 1312            if (PoolManager.i.poolables.TryGetValue(gameObject, out PoolableObject poolable))
 313            {
 0314                pool = poolable.pool;
 0315                return true;
 316            }
 317
 1318            return false;
 319        }
 320
 11321        public bool IsValid() { return original != null; }
 322
 323#if UNITY_EDITOR
 324        // In production it will always be false
 325        private bool isQuitting = false;
 326
 327        // We need to check if application is quitting in editor
 328        // to prevent the pool from releasing objects that are
 329        // being destroyed
 330        void OnIsQuitting()
 331        {
 0332            Application.quitting -= OnIsQuitting;
 0333            isQuitting = true;
 0334        }
 335#endif
 336    }
 337};