< Summary

Class:DCL.Pool
Assembly:PoolManager
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/PoolManager/Pool.cs
Covered lines:111
Uncovered lines:27
Coverable lines:138
Total lines:337
Line coverage:80.4% (111 of 138)
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.075085.71%
Extract()0%110100%
PrewarmAsync()0%11.445036.36%
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.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
 163940        private readonly LinkedList<PoolableObject> unusedObjects = new LinkedList<PoolableObject>();
 163941        private readonly LinkedList<PoolableObject> usedObjects = new LinkedList<PoolableObject>();
 42
 43        private readonly int maxPrewarmCount;
 44
 45        private bool isInitialized;
 46
 047        public float lastGetTime { get; private set; }
 48
 049        public int objectsCount => unusedObjectsCount + usedObjectsCount;
 50
 051        public int unusedObjectsCount => unusedObjects.Count;
 52
 053        public int usedObjectsCount => usedObjects.Count;
 54
 163955        public Pool(string name, int maxPrewarmCount)
 56        {
 163957            if (PoolManager.USE_POOL_CONTAINERS)
 58            {
 163959                container = new GameObject("Pool - " + name);
 163960                container.transform.position = EnvironmentSettings.MORDOR;
 61            }
 62
 163963            this.maxPrewarmCount = maxPrewarmCount;
 163964        }
 65
 66        public void ForcePrewarm()
 67        {
 117368            if (maxPrewarmCount <= objectsCount)
 117369                return;
 70
 071            int objectsToInstantiate = Mathf.Max(0, maxPrewarmCount - objectsCount);
 072            for (int i = 0; i < objectsToInstantiate; i++)
 73            {
 074                Instantiate();
 75            }
 076        }
 77
 78        /// <summary>
 79        /// This will return an instance of the poolable object
 80        /// </summary>
 81        /// <returns></returns>
 82        public PoolableObject Get()
 83        {
 84            // These extra instantiations during initialization are to populate pools that will be used a lot later
 192285            if (PoolManager.i.initializing && !isInitialized)
 86            {
 56287                isInitialized = true;
 88
 112489                for (int i = unusedObjectsCount; i < Mathf.Min(usedObjectsCount * PREWARM_ACTIVE_MULTIPLIER, maxPrewarmC
 090                    Instantiate();
 91
 56292                Instantiate();
 56293            }
 136094            else if (unusedObjects.Count == 0)
 95            {
 126096                Instantiate();
 97            }
 98
 192299            PoolableObject poolable = Extract();
 100
 1922101            EnablePoolableObject(poolable);
 1922102            poolable.OnPoolGet();
 1922103            return poolable;
 104        }
 105
 106        private PoolableObject Extract()
 107        {
 1922108            PoolableObject po = null;
 1922109            po = unusedObjects.First.Value;
 1922110            unusedObjects.RemoveFirst();
 1922111            po.node = usedObjects.AddFirst(po);
 112
 113#if UNITY_EDITOR
 1922114            RefreshName();
 115#endif
 1922116            return po;
 117        }
 118
 119        public async UniTask PrewarmAsync(int prewarmCount, CancellationToken cancellationToken)
 120        {
 4121            cancellationToken.ThrowIfCancellationRequested();
 122
 4123            if (unusedObjects.Count >= prewarmCount)
 4124                return;
 125
 0126            for (int i = 0; i < prewarmCount; i++)
 127            {
 0128                Instantiate();
 0129                await UniTask.NextFrame(cancellationToken);
 130            }
 4131        }
 132
 133        public PoolableObject Instantiate()
 134        {
 1822135            var gameObject = InstantiateAsOriginal();
 1822136            return SetupPoolableObject(gameObject);
 137        }
 138
 139        public GameObject InstantiateAsOriginal()
 140        {
 1844141            Assert.IsTrue(original != null, $"Original should never be null here ({id})");
 142
 1844143            GameObject gameObject = null;
 144
 1844145            if (instantiator != null)
 141146                gameObject = instantiator.Instantiate(original);
 147            else
 1703148                gameObject = GameObject.Instantiate(original);
 149
 1844150            gameObject.SetActive(true);
 151
 1844152            return gameObject;
 153        }
 154
 155        private PoolableObject SetupPoolableObject(GameObject gameObject, bool active = false)
 156        {
 1825157            if (PoolManager.i.poolables.ContainsKey(gameObject))
 0158                return PoolManager.i.GetPoolable(gameObject);
 159
 1825160            PoolableObject poolable = new PoolableObject(this, gameObject);
 1825161            PoolManager.i.poolables.Add(gameObject, poolable);
 1825162            PoolManager.i.poolableValues.Add(poolable);
 163
 1825164            if (!active)
 165            {
 1822166                DisablePoolableObject(poolable);
 1822167                poolable.node = unusedObjects.AddFirst(poolable);
 1822168            }
 169            else
 170            {
 3171                EnablePoolableObject(poolable);
 3172                poolable.node = usedObjects.AddFirst(poolable);
 173            }
 174
 175#if UNITY_EDITOR
 1825176            RefreshName();
 177#endif
 1825178            return poolable;
 179        }
 180
 181        public void Release(PoolableObject poolable)
 182        {
 2413183            if (poolable == null || !PoolManager.i.HasPoolable(poolable))
 508184                return;
 185
 1905186            DisablePoolableObject(poolable);
 187
 1905188            poolable.node.List.Remove(poolable.node);
 1905189            poolable.node = unusedObjects.AddFirst(poolable);
 190
 191#if UNITY_EDITOR
 1905192            RefreshName();
 193#endif
 1905194        }
 195
 196        public void ReleaseAll()
 197        {
 3594198            while (usedObjects.Count > 0)
 199            {
 1696200                usedObjects.First.Value.Release();
 201            }
 1898202        }
 203
 204        /// <summary>
 205        /// This will add a gameObject that is not on any pool to this pool.
 206        /// </summary>
 207        /// <param name="gameObject"></param>
 208        public void AddToPool(GameObject gameObject, bool addActive = true)
 209        {
 3210            if (instantiator != null && !instantiator.IsValid(gameObject))
 211            {
 0212                Debug.LogError($"ERROR: Trying to add invalid gameObject to pool! -- {gameObject.name}", gameObject);
 0213                return;
 214            }
 215
 3216            PoolableObject obj = PoolManager.i.GetPoolable(gameObject);
 217
 3218            if (obj != null)
 219            {
 0220                Debug.LogError($"ERROR: gameObject is already being tracked by a pool! -- {gameObject.name}", gameObject
 0221                return;
 222            }
 223
 3224            SetupPoolableObject(gameObject, addActive);
 3225        }
 226
 227        public void RemoveFromPool(PoolableObject poolable)
 228        {
 5229            if (poolable.node != null)
 230            {
 5231                if (poolable.node.List != null)
 0232                    poolable.node.List.Remove(poolable);
 233
 5234                poolable.node = null;
 235            }
 236
 5237            PoolManager.i.poolables.Remove(poolable.gameObject);
 5238            PoolManager.i.poolableValues.Remove(poolable);
 239#if UNITY_EDITOR
 5240            RefreshName();
 241#endif
 5242        }
 243
 244        public void Cleanup()
 245        {
 1621246            ReleaseAll();
 247
 3417248            while (unusedObjects.Count > 0)
 249            {
 1796250                PoolManager.i.poolables.Remove(unusedObjects.First.Value.gameObject);
 1796251                PoolManager.i.poolableValues.Remove(unusedObjects.First.Value);
 1796252                unusedObjects.RemoveFirst();
 253            }
 254
 1621255            while (usedObjects.Count > 0)
 256            {
 0257                PoolManager.i.poolables.Remove(usedObjects.First.Value.gameObject);
 0258                PoolManager.i.poolableValues.Remove(usedObjects.First.Value);
 0259                usedObjects.RemoveFirst();
 260            }
 261
 1621262            unusedObjects.Clear();
 1621263            usedObjects.Clear();
 264
 1621265            Object.Destroy(this.original);
 266
 1621267            if (PoolManager.USE_POOL_CONTAINERS)
 1621268                Object.Destroy(this.container);
 269
 1621270            OnCleanup?.Invoke(this);
 128271        }
 272
 273        public void EnablePoolableObject(PoolableObject poolable)
 274        {
 1925275            GameObject go = poolable.gameObject;
 276
 1925277            if (go == null)
 0278                return;
 279
 1925280            if (!go.activeSelf)
 1922281                go.SetActive(true);
 282
 1925283            go.transform.ResetLocalTRS();
 284
 1925285            lastGetTime = Time.unscaledTime;
 1925286        }
 287
 288        public void DisablePoolableObject(PoolableObject poolable)
 289        {
 290#if UNITY_STANDALONE || UNITY_EDITOR
 3727291            if (DataStore.i.common.isApplicationQuitting.Get())
 0292                return;
 293#endif
 3727294            GameObject go = poolable.gameObject;
 295
 3727296            if (go == null)
 29297                return;
 298
 3698299            if (go.activeSelf)
 3695300                go.SetActive(false);
 301
 3698302            if (PoolManager.USE_POOL_CONTAINERS)
 303            {
 3698304                if (container != null)
 305                {
 3698306                    go.transform.SetParent(container.transform);
 307                }
 3698308            }
 309            else
 310            {
 0311                go.transform.SetParent(null);
 312            }
 0313        }
 314
 315#if UNITY_EDITOR
 316        private void RefreshName()
 317        {
 5657318            if (this.container != null)
 5657319                this.container.name = $"in: {unusedObjectsCount} out: {usedObjectsCount} id: {id} persistent: {persisten
 5657320        }
 321#endif
 322        public static bool FindPoolInGameObject(GameObject gameObject, out Pool pool)
 323        {
 3324            pool = null;
 325
 3326            if (PoolManager.i.poolables.TryGetValue(gameObject, out PoolableObject poolable))
 327            {
 0328                pool = poolable.pool;
 0329                return true;
 330            }
 331
 3332            return false;
 333        }
 334
 15335        public bool IsValid() { return original != null; }
 336    }
 337};