< 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
 164938        private readonly LinkedList<PoolableObject> unusedObjects = new LinkedList<PoolableObject>();
 164939        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
 164952        public Pool(string name, int maxPrewarmCount)
 53        {
 164954            if (PoolManager.USE_POOL_CONTAINERS)
 164955                container = new GameObject("Pool - " + name);
 56
 164957            this.maxPrewarmCount = maxPrewarmCount;
 164958        }
 59
 60        public void ForcePrewarm()
 61        {
 118462            if (maxPrewarmCount <= objectsCount)
 118463                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
 187879            if (PoolManager.i.initializing && !isInitialized)
 80            {
 56181                isInitialized = true;
 56182                int count = usedObjectsCount;
 83
 112284                for (int i = unusedObjectsCount; i < Mathf.Min(count * PREWARM_ACTIVE_MULTIPLIER, maxPrewarmCount); i++)
 85                {
 086                    Instantiate();
 87                }
 88
 56189                Instantiate();
 56190            }
 131791            else if (unusedObjects.Count == 0)
 92            {
 124293                Instantiate();
 94            }
 95
 187896            PoolableObject poolable = Extract();
 97
 187898            EnablePoolableObject(poolable);
 187899            poolable.OnPoolGet();
 1878100            return poolable;
 101        }
 102
 103        private PoolableObject Extract()
 104        {
 1878105            PoolableObject po = null;
 1878106            po = unusedObjects.First.Value;
 1878107            unusedObjects.RemoveFirst();
 1878108            po.node = usedObjects.AddFirst(po);
 109
 110#if UNITY_EDITOR
 1878111            RefreshName();
 112#endif
 1878113            return po;
 114        }
 115
 116        public PoolableObject Instantiate()
 117        {
 1803118            var gameObject = InstantiateAsOriginal();
 1803119            return SetupPoolableObject(gameObject);
 120        }
 121
 122        public GameObject InstantiateAsOriginal()
 123        {
 1825124            Assert.IsTrue(original != null, $"Original should never be null here ({id})");
 125
 1825126            GameObject gameObject = null;
 127
 1825128            if (instantiator != null)
 141129                gameObject = instantiator.Instantiate(original);
 130            else
 1684131                gameObject = GameObject.Instantiate(original);
 132
 1825133            gameObject.SetActive(true);
 134
 1825135            return gameObject;
 136        }
 137
 138        private PoolableObject SetupPoolableObject(GameObject gameObject, bool active = false)
 139        {
 1806140            if (PoolManager.i.poolables.ContainsKey(gameObject))
 0141                return PoolManager.i.GetPoolable(gameObject);
 142
 1806143            PoolableObject poolable = new PoolableObject(this, gameObject);
 1806144            PoolManager.i.poolables.Add(gameObject, poolable);
 1806145            PoolManager.i.poolableValues.Add(poolable);
 146
 1806147            if (!active)
 148            {
 1803149                DisablePoolableObject(poolable);
 1803150                poolable.node = unusedObjects.AddFirst(poolable);
 1803151            }
 152            else
 153            {
 3154                EnablePoolableObject(poolable);
 3155                poolable.node = usedObjects.AddFirst(poolable);
 156            }
 157
 158#if UNITY_EDITOR
 1806159            RefreshName();
 160#endif
 1806161            return poolable;
 162        }
 163
 164        public void Release(PoolableObject poolable)
 165        {
 2356166            if (poolable == null || !PoolManager.i.HasPoolable(poolable))
 500167                return;
 168
 1856169            DisablePoolableObject(poolable);
 170
 1856171            poolable.node.List.Remove(poolable.node);
 1856172            poolable.node = unusedObjects.AddFirst(poolable);
 173
 174#if UNITY_EDITOR
 1856175            RefreshName();
 176#endif
 1856177        }
 178
 179        public void ReleaseAll()
 180        {
 3542181            while (usedObjects.Count > 0)
 182            {
 1646183                usedObjects.First.Value.Release();
 184            }
 1896185        }
 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        {
 1628229            ReleaseAll();
 230
 3401231            while (unusedObjects.Count > 0)
 232            {
 1773233                PoolManager.i.poolables.Remove(unusedObjects.First.Value.gameObject);
 1773234                PoolManager.i.poolableValues.Remove(unusedObjects.First.Value);
 1773235                unusedObjects.RemoveFirst();
 236            }
 237
 1628238            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
 1628245            unusedObjects.Clear();
 1628246            usedObjects.Clear();
 247
 1628248            Object.Destroy(this.original);
 249
 1628250            if (PoolManager.USE_POOL_CONTAINERS)
 1628251                Object.Destroy(this.container);
 252
 1628253            OnCleanup?.Invoke(this);
 128254        }
 255
 256        public void EnablePoolableObject(PoolableObject poolable)
 257        {
 1881258            GameObject go = poolable.gameObject;
 259
 1881260            if (go == null)
 0261                return;
 262
 1881263            if (!go.activeSelf)
 1878264                go.SetActive(true);
 265
 1881266            go.transform.ResetLocalTRS();
 267
 1881268            lastGetTime = Time.unscaledTime;
 1881269        }
 270
 271        public void DisablePoolableObject(PoolableObject poolable)
 272        {
 273#if UNITY_STANDALONE || UNITY_EDITOR
 3659274            if (DataStore.i.common.isApplicationQuitting.Get())
 0275                return;
 276#endif
 3659277            GameObject go = poolable.gameObject;
 278
 3659279            if (go == null)
 27280                return;
 281
 3632282            if (go.activeSelf)
 3630283                go.SetActive(false);
 284
 3632285            if (PoolManager.USE_POOL_CONTAINERS)
 286            {
 3632287                if (container != null)
 288                {
 3632289                    go.transform.SetParent(container.transform);
 290                }
 3632291            }
 292            else
 293            {
 0294                go.transform.SetParent(null);
 295            }
 0296        }
 297
 298#if UNITY_EDITOR
 299        private void RefreshName()
 300        {
 5545301            if (this.container != null)
 5545302                this.container.name = $"in: {unusedObjectsCount} out: {usedObjectsCount} id: {id} persistent: {persisten
 5545303        }
 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};