< Summary

Class:DCL.Pool
Assembly:PoolManager
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/PoolManager/Pool.cs
Covered lines:109
Uncovered lines:22
Coverable lines:131
Total lines:334
Line coverage:83.2% (109 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.095084.62%
Get[T]()0%110100%
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%4.134080%
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
 15        GameObject Instantiate(GameObject gameObject);
 16    }
 17
 18    public class Pool : ICleanable
 19    {
 20        public delegate void OnReleaseAllDlg(Pool pool);
 21
 22        public const int PREWARM_ACTIVE_MULTIPLIER = 2;
 23        public object id;
 24        public GameObject original;
 25        public GameObject container;
 26
 27        public bool persistent = false;
 28
 29        /// <summary>
 30        /// If this is set to true, all Unity components in the poolable gameObject implementing ILifecycleHandler
 31        /// will be registered and called when necessary.
 32        ///
 33        /// The interface call responsibility lies in the PoolableObject class.
 34        /// </summary>
 35        public bool useLifecycleHandlers = false;
 36
 37        public System.Action<Pool> OnCleanup;
 38
 39        public IPooledObjectInstantiator instantiator;
 40
 520441        private readonly LinkedList<PoolableObject> unusedObjects = new LinkedList<PoolableObject>();
 520442        private readonly LinkedList<PoolableObject> usedObjects = new LinkedList<PoolableObject>();
 43
 44        private readonly int maxPrewarmCount;
 45
 46        private bool isInitialized;
 47
 157148        public float lastGetTime { get; private set; }
 49
 483450        public int objectsCount => unusedObjectsCount + usedObjectsCount;
 51
 989552        public int unusedObjectsCount => unusedObjects.Count;
 53
 1525454        public int usedObjectsCount => usedObjects.Count;
 55
 520456        public Pool(string name, int maxPrewarmCount)
 57        {
 520458            if (PoolManager.USE_POOL_CONTAINERS)
 59            {
 520460                container = new GameObject("Pool - " + name);
 520461                container.transform.position = EnvironmentSettings.MORDOR;
 62            }
 63
 520464            this.maxPrewarmCount = maxPrewarmCount;
 520465        }
 66
 67        public void ForcePrewarm()
 68        {
 483369            if (maxPrewarmCount <= objectsCount)
 483370                return;
 71
 072            int objectsToInstantiate = Mathf.Max(0, maxPrewarmCount - objectsCount);
 73
 074            for (int i = 0; i < objectsToInstantiate; i++) { Instantiate(); }
 075        }
 76
 77        /// <summary>
 78        /// This will return an instance of the poolable object
 79        /// </summary>
 80        /// <returns></returns>
 81        public PoolableObject Get()
 82        {
 83            // These extra instantiations during initialization are to populate pools that will be used a lot later
 156884            if (PoolManager.i.initializing && !isInitialized)
 85            {
 46186                isInitialized = true;
 87
 92288                for (int i = unusedObjectsCount; i < Mathf.Min(usedObjectsCount * PREWARM_ACTIVE_MULTIPLIER, maxPrewarmC
 089                    Instantiate();
 90
 46191                Instantiate();
 92            }
 211793            else if (unusedObjects.Count == 0) { Instantiate(); }
 94
 156895            PoolableObject poolable = Extract();
 96
 156897            EnablePoolableObject(poolable);
 156898            poolable.OnPoolGet();
 99
 1568100            return poolable;
 101        }
 102
 103        public T Get<T>() where T: MonoBehaviour =>
 62104            this.Get().gameObject.GetComponent<T>();
 105
 106        private PoolableObject Extract()
 107        {
 1568108            PoolableObject po = null;
 1568109            po = unusedObjects.First.Value;
 1568110            unusedObjects.RemoveFirst();
 1568111            po.node = usedObjects.AddFirst(po);
 112
 113#if UNITY_EDITOR
 1568114            RefreshName();
 115#endif
 1568116            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        {
 1471135            var gameObject = InstantiateAsOriginal();
 136
 1471137            return SetupPoolableObject(gameObject);
 138        }
 139
 140        public GameObject InstantiateAsOriginal()
 141        {
 1493142            Assert.IsTrue(original != null, $"Original should never be null here ({id})");
 143
 1493144            GameObject gameObject = null;
 145
 1493146            if (instantiator != null)
 121147                gameObject = instantiator.Instantiate(original);
 148            else
 1372149                gameObject = GameObject.Instantiate(original);
 150
 1493151            gameObject.SetActive(true);
 152
 1493153            return gameObject;
 154        }
 155
 156        private PoolableObject SetupPoolableObject(GameObject gameObject, bool active = false)
 157        {
 1474158            if (PoolManager.i.poolables.ContainsKey(gameObject))
 0159                return PoolManager.i.GetPoolable(gameObject);
 160
 1474161            PoolableObject poolable = new PoolableObject(this, gameObject);
 1474162            PoolManager.i.poolables.Add(gameObject, poolable);
 1474163            PoolManager.i.poolableValues.Add(poolable);
 164
 1474165            if (!active)
 166            {
 1471167                DisablePoolableObject(poolable);
 1471168                poolable.node = unusedObjects.AddFirst(poolable);
 169            }
 170            else
 171            {
 3172                EnablePoolableObject(poolable);
 3173                poolable.node = usedObjects.AddFirst(poolable);
 174            }
 175
 176#if UNITY_EDITOR
 1474177            RefreshName();
 178#endif
 1474179            return poolable;
 180        }
 181
 182        public void Release(PoolableObject poolable)
 183        {
 1735184            if (poolable == null || !PoolManager.i.HasPoolable(poolable))
 184185                return;
 186
 1551187            DisablePoolableObject(poolable);
 188
 1551189            poolable.node.List.Remove(poolable.node);
 1551190            poolable.node = unusedObjects.AddFirst(poolable);
 191
 192#if UNITY_EDITOR
 1551193            RefreshName();
 194#endif
 1551195        }
 196
 197        public void ReleaseAll()
 198        {
 8175199            while (usedObjects.Count > 0) { usedObjects.First.Value.Release(); }
 5463200        }
 201
 202        /// <summary>
 203        /// This will add a gameObject that is not on any pool to this pool.
 204        /// </summary>
 205        /// <param name="gameObject"></param>
 206        public void AddToPool(GameObject gameObject, bool addActive = true)
 207        {
 3208            if (instantiator != null && !instantiator.IsValid(gameObject))
 209            {
 0210                Debug.LogError($"ERROR: Trying to add invalid gameObject to pool! -- {gameObject.name}", gameObject);
 211
 0212                return;
 213            }
 214
 3215            PoolableObject obj = PoolManager.i.GetPoolable(gameObject);
 216
 3217            if (obj != null)
 218            {
 0219                Debug.LogError($"ERROR: gameObject is already being tracked by a pool! -- {gameObject.name}", gameObject
 220
 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        {
 5186246            ReleaseAll();
 247
 6631248            while (unusedObjects.Count > 0)
 249            {
 1445250                PoolManager.i.poolables.Remove(unusedObjects.First.Value.gameObject);
 1445251                PoolManager.i.poolableValues.Remove(unusedObjects.First.Value);
 1445252                unusedObjects.RemoveFirst();
 253            }
 254
 5186255            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
 5186262            unusedObjects.Clear();
 5186263            usedObjects.Clear();
 264
 5186265            Utils.SafeDestroy(this.original);
 266
 5186267            Utils.SafeDestroy(this.container);;
 268
 5186269            OnCleanup?.Invoke(this);
 114270        }
 271
 272        public void EnablePoolableObject(PoolableObject poolable)
 273        {
 1571274            GameObject go = poolable.gameObject;
 275
 1571276            if (go == null)
 0277                return;
 278
 1571279            if (!go.activeSelf)
 1568280                go.SetActive(true);
 281
 1571282            go.transform.ResetLocalTRS();
 283
 1571284            lastGetTime = Time.unscaledTime;
 1571285        }
 286
 287        public void DisablePoolableObject(PoolableObject poolable)
 288        {
 289#if UNITY_STANDALONE || UNITY_EDITOR
 3022290            if (DataStore.i.common.isApplicationQuitting.Get())
 0291                return;
 292#endif
 3022293            GameObject go = poolable.gameObject;
 294
 3022295            if (go == null)
 29296                return;
 297
 2993298            if (go.activeSelf)
 2987299                go.SetActive(false);
 300
 2993301            if (PoolManager.USE_POOL_CONTAINERS)
 302            {
 5986303                if (container != null) { go.transform.SetParent(container.transform); }
 304            }
 0305            else { go.transform.SetParent(null); }
 0306        }
 307
 308#if UNITY_EDITOR
 309        private void RefreshName()
 310        {
 4598311            if (this.container != null)
 4598312                this.container.name = $"in: {unusedObjectsCount} out: {usedObjectsCount} id: {id} persistent: {persisten
 4598313        }
 314#endif
 315        public static bool FindPoolInGameObject(GameObject gameObject, out Pool pool)
 316        {
 3317            pool = null;
 318
 3319            if (PoolManager.i.poolables.TryGetValue(gameObject, out PoolableObject poolable))
 320            {
 0321                pool = poolable.pool;
 322
 0323                return true;
 324            }
 325
 3326            return false;
 327        }
 328
 329        public bool IsValid()
 330        {
 15331            return original != null;
 332        }
 333    }
 334};