< Summary

Class:DCL.Pool
Assembly:PoolManager
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/PoolManager/Pool.cs
Covered lines:108
Uncovered lines:22
Coverable lines:130
Total lines:331
Line coverage:83% (108 of 130)
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%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
 532241        private readonly LinkedList<PoolableObject> unusedObjects = new LinkedList<PoolableObject>();
 532242        private readonly LinkedList<PoolableObject> usedObjects = new LinkedList<PoolableObject>();
 43
 44        private readonly int maxPrewarmCount;
 45
 46        private bool isInitialized;
 47
 160848        public float lastGetTime { get; private set; }
 49
 495250        public int objectsCount => unusedObjectsCount + usedObjectsCount;
 51
 1013052        public int unusedObjectsCount => unusedObjects.Count;
 53
 1560754        public int usedObjectsCount => usedObjects.Count;
 55
 532256        public Pool(string name, int maxPrewarmCount)
 57        {
 532258            if (PoolManager.USE_POOL_CONTAINERS)
 59            {
 532260                container = new GameObject("Pool - " + name);
 532261                container.transform.position = EnvironmentSettings.MORDOR;
 62            }
 63
 532264            this.maxPrewarmCount = maxPrewarmCount;
 532265        }
 66
 67        public void ForcePrewarm()
 68        {
 495169            if (maxPrewarmCount <= objectsCount)
 495170                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
 160584            if (PoolManager.i.initializing && !isInitialized)
 85            {
 46686                isInitialized = true;
 87
 93288                for (int i = unusedObjectsCount; i < Mathf.Min(usedObjectsCount * PREWARM_ACTIVE_MULTIPLIER, maxPrewarmC
 089                    Instantiate();
 90
 46691                Instantiate();
 92            }
 218293            else if (unusedObjects.Count == 0) { Instantiate(); }
 94
 160595            PoolableObject poolable = Extract();
 96
 160597            EnablePoolableObject(poolable);
 160598            poolable.OnPoolGet();
 99
 1605100            return poolable;
 101        }
 102
 103        private PoolableObject Extract()
 104        {
 1605105            PoolableObject po = null;
 1605106            po = unusedObjects.First.Value;
 1605107            unusedObjects.RemoveFirst();
 1605108            po.node = usedObjects.AddFirst(po);
 109
 110#if UNITY_EDITOR
 1605111            RefreshName();
 112#endif
 1605113            return po;
 114        }
 115
 116        public async UniTask PrewarmAsync(int prewarmCount, CancellationToken cancellationToken)
 117        {
 4118            cancellationToken.ThrowIfCancellationRequested();
 119
 4120            if (unusedObjects.Count >= prewarmCount)
 4121                return;
 122
 0123            for (int i = 0; i < prewarmCount; i++)
 124            {
 0125                Instantiate();
 0126                await UniTask.NextFrame(cancellationToken);
 127            }
 4128        }
 129
 130        public PoolableObject Instantiate()
 131        {
 1509132            var gameObject = InstantiateAsOriginal();
 133
 1509134            return SetupPoolableObject(gameObject);
 135        }
 136
 137        public GameObject InstantiateAsOriginal()
 138        {
 1531139            Assert.IsTrue(original != null, $"Original should never be null here ({id})");
 140
 1531141            GameObject gameObject = null;
 142
 1531143            if (instantiator != null)
 121144                gameObject = instantiator.Instantiate(original);
 145            else
 1410146                gameObject = GameObject.Instantiate(original);
 147
 1531148            gameObject.SetActive(true);
 149
 1531150            return gameObject;
 151        }
 152
 153        private PoolableObject SetupPoolableObject(GameObject gameObject, bool active = false)
 154        {
 1512155            if (PoolManager.i.poolables.ContainsKey(gameObject))
 0156                return PoolManager.i.GetPoolable(gameObject);
 157
 1512158            PoolableObject poolable = new PoolableObject(this, gameObject);
 1512159            PoolManager.i.poolables.Add(gameObject, poolable);
 1512160            PoolManager.i.poolableValues.Add(poolable);
 161
 1512162            if (!active)
 163            {
 1509164                DisablePoolableObject(poolable);
 1509165                poolable.node = unusedObjects.AddFirst(poolable);
 166            }
 167            else
 168            {
 3169                EnablePoolableObject(poolable);
 3170                poolable.node = usedObjects.AddFirst(poolable);
 171            }
 172
 173#if UNITY_EDITOR
 1512174            RefreshName();
 175#endif
 1512176            return poolable;
 177        }
 178
 179        public void Release(PoolableObject poolable)
 180        {
 1805181            if (poolable == null || !PoolManager.i.HasPoolable(poolable))
 217182                return;
 183
 1588184            DisablePoolableObject(poolable);
 185
 1588186            poolable.node.List.Remove(poolable.node);
 1588187            poolable.node = unusedObjects.AddFirst(poolable);
 188
 189#if UNITY_EDITOR
 1588190            RefreshName();
 191#endif
 1588192        }
 193
 194        public void ReleaseAll()
 195        {
 8354196            while (usedObjects.Count > 0) { usedObjects.First.Value.Release(); }
 5580197        }
 198
 199        /// <summary>
 200        /// This will add a gameObject that is not on any pool to this pool.
 201        /// </summary>
 202        /// <param name="gameObject"></param>
 203        public void AddToPool(GameObject gameObject, bool addActive = true)
 204        {
 3205            if (instantiator != null && !instantiator.IsValid(gameObject))
 206            {
 0207                Debug.LogError($"ERROR: Trying to add invalid gameObject to pool! -- {gameObject.name}", gameObject);
 208
 0209                return;
 210            }
 211
 3212            PoolableObject obj = PoolManager.i.GetPoolable(gameObject);
 213
 3214            if (obj != null)
 215            {
 0216                Debug.LogError($"ERROR: gameObject is already being tracked by a pool! -- {gameObject.name}", gameObject
 217
 0218                return;
 219            }
 220
 3221            SetupPoolableObject(gameObject, addActive);
 3222        }
 223
 224        public void RemoveFromPool(PoolableObject poolable)
 225        {
 5226            if (poolable.node != null)
 227            {
 5228                if (poolable.node.List != null)
 0229                    poolable.node.List.Remove(poolable);
 230
 5231                poolable.node = null;
 232            }
 233
 5234            PoolManager.i.poolables.Remove(poolable.gameObject);
 5235            PoolManager.i.poolableValues.Remove(poolable);
 236#if UNITY_EDITOR
 5237            RefreshName();
 238#endif
 5239        }
 240
 241        public void Cleanup()
 242        {
 5304243            ReleaseAll();
 244
 6787245            while (unusedObjects.Count > 0)
 246            {
 1483247                PoolManager.i.poolables.Remove(unusedObjects.First.Value.gameObject);
 1483248                PoolManager.i.poolableValues.Remove(unusedObjects.First.Value);
 1483249                unusedObjects.RemoveFirst();
 250            }
 251
 5304252            while (usedObjects.Count > 0)
 253            {
 0254                PoolManager.i.poolables.Remove(usedObjects.First.Value.gameObject);
 0255                PoolManager.i.poolableValues.Remove(usedObjects.First.Value);
 0256                usedObjects.RemoveFirst();
 257            }
 258
 5304259            unusedObjects.Clear();
 5304260            usedObjects.Clear();
 261
 5304262            Utils.SafeDestroy(this.original);
 263
 5304264            Utils.SafeDestroy(this.container);;
 265
 5304266            OnCleanup?.Invoke(this);
 114267        }
 268
 269        public void EnablePoolableObject(PoolableObject poolable)
 270        {
 1608271            GameObject go = poolable.gameObject;
 272
 1608273            if (go == null)
 0274                return;
 275
 1608276            if (!go.activeSelf)
 1605277                go.SetActive(true);
 278
 1608279            go.transform.ResetLocalTRS();
 280
 1608281            lastGetTime = Time.unscaledTime;
 1608282        }
 283
 284        public void DisablePoolableObject(PoolableObject poolable)
 285        {
 286#if UNITY_STANDALONE || UNITY_EDITOR
 3097287            if (DataStore.i.common.isApplicationQuitting.Get())
 0288                return;
 289#endif
 3097290            GameObject go = poolable.gameObject;
 291
 3097292            if (go == null)
 29293                return;
 294
 3068295            if (go.activeSelf)
 3064296                go.SetActive(false);
 297
 3068298            if (PoolManager.USE_POOL_CONTAINERS)
 299            {
 6136300                if (container != null) { go.transform.SetParent(container.transform); }
 301            }
 0302            else { go.transform.SetParent(null); }
 0303        }
 304
 305#if UNITY_EDITOR
 306        private void RefreshName()
 307        {
 4710308            if (this.container != null)
 4710309                this.container.name = $"in: {unusedObjectsCount} out: {usedObjectsCount} id: {id} persistent: {persisten
 4710310        }
 311#endif
 312        public static bool FindPoolInGameObject(GameObject gameObject, out Pool pool)
 313        {
 3314            pool = null;
 315
 3316            if (PoolManager.i.poolables.TryGetValue(gameObject, out PoolableObject poolable))
 317            {
 0318                pool = poolable.pool;
 319
 0320                return true;
 321            }
 322
 3323            return false;
 324        }
 325
 326        public bool IsValid()
 327        {
 15328            return original != null;
 329        }
 330    }
 331};