< Summary

Class:DCL.Pool
Assembly:PoolManager
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/PoolManager/Pool.cs
Covered lines:112
Uncovered lines:23
Coverable lines:135
Total lines:338
Line coverage:82.9% (112 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.83025%
Get()0%5.095084.62%
Extract()0%110100%
PrewarmAsync()0%11.445036.36%
Instantiate()0%110100%
InstantiateAsOriginal()0%220100%
SetupPoolableObject(...)0%3.013091.67%
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.566075%
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.Generic;
 2using System.Threading;
 3using Cysharp.Threading.Tasks;
 4using DCL.Configuration;
 5using UnityEngine;
 6using DCL.Helpers;
 7using UnityEngine.Assertions;
 8
 9namespace DCL
 10{
 11    public interface IPooledObjectInstantiator
 12    {
 13        bool IsValid(GameObject original);
 14        GameObject Instantiate(GameObject gameObject);
 15    }
 16
 17    public class Pool : ICleanable
 18    {
 19        public delegate void OnReleaseAllDlg(Pool pool);
 20
 21        public const int PREWARM_ACTIVE_MULTIPLIER = 2;
 22        public object id;
 23        public GameObject original;
 24        public GameObject container;
 25
 26        public bool persistent = false;
 27
 28        /// <summary>
 29        /// If this is set to true, all Unity components in the poolable gameObject implementing ILifecycleHandler
 30        /// will be registered and called when necessary.
 31        ///
 32        /// The interface call responsibility lies in the PoolableObject class.
 33        /// </summary>
 34        public bool useLifecycleHandlers = false;
 35
 36        public System.Action<Pool> OnCleanup;
 37
 38        public IPooledObjectInstantiator instantiator;
 39
 586140        private readonly LinkedList<PoolableObject> unusedObjects = new LinkedList<PoolableObject>();
 586141        private readonly LinkedList<PoolableObject> usedObjects = new LinkedList<PoolableObject>();
 42
 43        private readonly int maxPrewarmCount;
 44
 45        private bool isInitialized;
 46
 162547        public float lastGetTime { get; private set; }
 48
 547849        public int objectsCount => unusedObjectsCount + usedObjectsCount;
 50
 1072651        public int unusedObjectsCount => unusedObjects.Count;
 52
 1674153        public int usedObjectsCount => usedObjects.Count;
 54
 55
 586156        public Pool(string name, int maxPrewarmCount)
 57        {
 586158            if (PoolManager.USE_POOL_CONTAINERS)
 59            {
 586160                container = new GameObject("Pool - " + name);
 586161                container.transform.position = EnvironmentSettings.MORDOR;
 62            }
 63
 586164            this.maxPrewarmCount = maxPrewarmCount;
 586165        }
 66
 67        public void ForcePrewarm()
 68        {
 547769            if (maxPrewarmCount <= objectsCount)
 547770                return;
 71
 072            int objectsToInstantiate = Mathf.Max(0, maxPrewarmCount - objectsCount);
 073            for (int i = 0; i < objectsToInstantiate; i++)
 74            {
 075                Instantiate();
 76            }
 077        }
 78
 79        /// <summary>
 80        /// This will return an instance of the poolable object
 81        /// </summary>
 82        /// <returns></returns>
 83        public PoolableObject Get()
 84        {
 85            // These extra instantiations during initialization are to populate pools that will be used a lot later
 162286            if (PoolManager.i.initializing && !isInitialized)
 87            {
 47988                isInitialized = true;
 89
 95890                for (int i = unusedObjectsCount; i < Mathf.Min(usedObjectsCount * PREWARM_ACTIVE_MULTIPLIER, maxPrewarmC
 091                    Instantiate();
 92
 47993                Instantiate();
 94            }
 114395            else if (unusedObjects.Count == 0)
 96            {
 104697                Instantiate();
 98            }
 99
 1622100            PoolableObject poolable = Extract();
 101
 1622102            EnablePoolableObject(poolable);
 1622103            poolable.OnPoolGet();
 1622104            return poolable;
 105        }
 106
 107        private PoolableObject Extract()
 108        {
 1622109            PoolableObject po = null;
 1622110            po = unusedObjects.First.Value;
 1622111            unusedObjects.RemoveFirst();
 1622112            po.node = usedObjects.AddFirst(po);
 113
 114#if UNITY_EDITOR
 1622115            RefreshName();
 116#endif
 1622117            return po;
 118        }
 119
 120        public async UniTask PrewarmAsync(int prewarmCount, CancellationToken cancellationToken)
 121        {
 4122            cancellationToken.ThrowIfCancellationRequested();
 123
 4124            if (unusedObjects.Count >= prewarmCount)
 4125                return;
 126
 0127            for (int i = 0; i < prewarmCount; i++)
 128            {
 0129                Instantiate();
 0130                await UniTask.NextFrame(cancellationToken);
 131            }
 4132        }
 133
 134        public PoolableObject Instantiate()
 135        {
 1525136            var gameObject = InstantiateAsOriginal();
 1525137            return SetupPoolableObject(gameObject);
 138        }
 139
 140        public GameObject InstantiateAsOriginal()
 141        {
 1547142            Assert.IsTrue(original != null, $"Original should never be null here ({id})");
 143
 1547144            GameObject gameObject = null;
 145
 1547146            if (instantiator != null)
 131147                gameObject = instantiator.Instantiate(original);
 148            else
 1416149                gameObject = GameObject.Instantiate(original);
 150
 1547151            gameObject.SetActive(true);
 152
 1547153            return gameObject;
 154        }
 155
 156        private PoolableObject SetupPoolableObject(GameObject gameObject, bool active = false)
 157        {
 1528158            if (PoolManager.i.poolables.ContainsKey(gameObject))
 0159                return PoolManager.i.GetPoolable(gameObject);
 160
 1528161            PoolableObject poolable = new PoolableObject(this, gameObject);
 1528162            PoolManager.i.poolables.Add(gameObject, poolable);
 1528163            PoolManager.i.poolableValues.Add(poolable);
 164
 1528165            if (!active)
 166            {
 1525167                DisablePoolableObject(poolable);
 1525168                poolable.node = unusedObjects.AddFirst(poolable);
 169            }
 170            else
 171            {
 3172                EnablePoolableObject(poolable);
 3173                poolable.node = usedObjects.AddFirst(poolable);
 174            }
 175
 176#if UNITY_EDITOR
 1528177            RefreshName();
 178#endif
 1528179            return poolable;
 180        }
 181
 182        public void Release(PoolableObject poolable)
 183        {
 1828184            if (poolable == null || !PoolManager.i.HasPoolable(poolable))
 223185                return;
 186
 1605187            DisablePoolableObject(poolable);
 188
 1605189            poolable.node.List.Remove(poolable.node);
 1605190            poolable.node = unusedObjects.AddFirst(poolable);
 191
 192#if UNITY_EDITOR
 1605193            RefreshName();
 194#endif
 1605195        }
 196
 197        public void ReleaseAll()
 198        {
 7520199            while (usedObjects.Count > 0)
 200            {
 1400201                usedObjects.First.Value.Release();
 202            }
 6120203        }
 204
 205        /// <summary>
 206        /// This will add a gameObject that is not on any pool to this pool.
 207        /// </summary>
 208        /// <param name="gameObject"></param>
 209        public void AddToPool(GameObject gameObject, bool addActive = true)
 210        {
 3211            if (instantiator != null && !instantiator.IsValid(gameObject))
 212            {
 0213                Debug.LogError($"ERROR: Trying to add invalid gameObject to pool! -- {gameObject.name}", gameObject);
 0214                return;
 215            }
 216
 3217            PoolableObject obj = PoolManager.i.GetPoolable(gameObject);
 218
 3219            if (obj != null)
 220            {
 0221                Debug.LogError($"ERROR: gameObject is already being tracked by a pool! -- {gameObject.name}", gameObject
 0222                return;
 223            }
 224
 3225            SetupPoolableObject(gameObject, addActive);
 3226        }
 227
 228        public void RemoveFromPool(PoolableObject poolable)
 229        {
 5230            if (poolable.node != null)
 231            {
 5232                if (poolable.node.List != null)
 0233                    poolable.node.List.Remove(poolable);
 234
 5235                poolable.node = null;
 236            }
 237
 5238            PoolManager.i.poolables.Remove(poolable.gameObject);
 5239            PoolManager.i.poolableValues.Remove(poolable);
 240#if UNITY_EDITOR
 5241            RefreshName();
 242#endif
 5243        }
 244
 245        public void Cleanup()
 246        {
 5843247            ReleaseAll();
 248
 7342249            while (unusedObjects.Count > 0)
 250            {
 1499251                PoolManager.i.poolables.Remove(unusedObjects.First.Value.gameObject);
 1499252                PoolManager.i.poolableValues.Remove(unusedObjects.First.Value);
 1499253                unusedObjects.RemoveFirst();
 254            }
 255
 5843256            while (usedObjects.Count > 0)
 257            {
 0258                PoolManager.i.poolables.Remove(usedObjects.First.Value.gameObject);
 0259                PoolManager.i.poolableValues.Remove(usedObjects.First.Value);
 0260                usedObjects.RemoveFirst();
 261            }
 262
 5843263            unusedObjects.Clear();
 5843264            usedObjects.Clear();
 265
 5843266            Object.Destroy(this.original);
 267
 5843268            if (PoolManager.USE_POOL_CONTAINERS)
 5843269                Object.Destroy(this.container);
 270
 5843271            OnCleanup?.Invoke(this);
 118272        }
 273
 274        public void EnablePoolableObject(PoolableObject poolable)
 275        {
 1625276            GameObject go = poolable.gameObject;
 277
 1625278            if (go == null)
 0279                return;
 280
 1625281            if (!go.activeSelf)
 1622282                go.SetActive(true);
 283
 1625284            go.transform.ResetLocalTRS();
 285
 1625286            lastGetTime = Time.unscaledTime;
 1625287        }
 288
 289        public void DisablePoolableObject(PoolableObject poolable)
 290        {
 291#if UNITY_STANDALONE || UNITY_EDITOR
 3130292            if (DataStore.i.common.isApplicationQuitting.Get())
 0293                return;
 294#endif
 3130295            GameObject go = poolable.gameObject;
 296
 3130297            if (go == null)
 29298                return;
 299
 3101300            if (go.activeSelf)
 3097301                go.SetActive(false);
 302
 3101303            if (PoolManager.USE_POOL_CONTAINERS)
 304            {
 3101305                if (container != null)
 306                {
 3101307                    go.transform.SetParent(container.transform);
 308                }
 309            }
 310            else
 311            {
 0312                go.transform.SetParent(null);
 313            }
 0314        }
 315
 316#if UNITY_EDITOR
 317        private void RefreshName()
 318        {
 4760319            if (this.container != null)
 4760320                this.container.name = $"in: {unusedObjectsCount} out: {usedObjectsCount} id: {id} persistent: {persisten
 4760321        }
 322#endif
 323        public static bool FindPoolInGameObject(GameObject gameObject, out Pool pool)
 324        {
 3325            pool = null;
 326
 3327            if (PoolManager.i.poolables.TryGetValue(gameObject, out PoolableObject poolable))
 328            {
 0329                pool = poolable.pool;
 0330                return true;
 331            }
 332
 3333            return false;
 334        }
 335
 15336        public bool IsValid() { return original != null; }
 337    }
 338};