< Summary

Class:DCL.AssetBundlesLoader
Assembly:AssetPromiseKeeper
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/AssetManager/AssetBundles/AB/AssetBundlesLoader.cs
Covered lines:58
Uncovered lines:19
Coverable lines:77
Total lines:201
Line coverage:75.3% (58 of 77)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
AssetBundleInfo(...)0%110100%
AssetBundlesLoader()0%110100%
Start()0%220100%
Stop()0%220100%
MarkAssetBundleForLoad(...)0%2.092071.43%
LoadAssetBundlesAsync()0%48.9617052%
LoadAssetBundleAsync()0%13.0913092%
IsLoadBudgetTimeReached(...)0%5.673033.33%
WaitForSkippedFrames(...)0%2100%
CheckForReprioritizeAwaitingAssets()0%12.415033.33%
GetDistanceFromPlayer(...)0%330100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/AssetManager/AssetBundles/AB/AssetBundlesLoader.cs

#LineLine coverage
 1using Cysharp.Threading.Tasks;
 2using System;
 3using System.Collections.Generic;
 4using System.Linq;
 5using DCL.Shaders;
 6using System.Threading;
 7using UnityEngine;
 8
 9namespace DCL
 10{
 11    public class AssetBundlesLoader
 12    {
 13        private const float MAX_LOAD_BUDGET_TIME = 0.05f;
 14        private const int SKIPPED_FRAMES_AFTER_BUDGET_TIME_IS_REACHED_FOR_NEARBY_ASSETS = 1;
 15        private const int SKIPPED_FRAMES_AFTER_BUDGET_TIME_IS_REACHED_FOR_DISTANT_ASSETS = 5;
 16        private const float MAX_SQR_DISTANCE_FOR_QUICK_LOADING = 6000f;
 17        private const float TIME_BETWEEN_REPRIORITIZATIONS = 1f;
 18
 19        private struct AssetBundleInfo
 20        {
 21            public Asset_AB asset;
 22            public Transform containerTransform;
 23            public Action onSuccess;
 24            public Action<Exception> onFail;
 25
 26            public AssetBundleInfo(Asset_AB asset, Transform containerTransform, Action onSuccess, Action<Exception> onF
 27            {
 2228                this.asset = asset;
 2229                this.containerTransform = containerTransform;
 2230                this.onSuccess = onSuccess;
 2231                this.onFail = onFail;
 2232            }
 33        }
 34
 135        private Queue<AssetBundleInfo> highPriorityLoadQueue = new Queue<AssetBundleInfo>();
 136        private Queue<AssetBundleInfo> lowPriorityLoadQueue = new Queue<AssetBundleInfo>();
 37
 138        private Dictionary<string, int> loadOrderByExtension = new Dictionary<string, int>()
 39        {
 40            { "png", 0 },
 41            { "jpg", 1 },
 42            { "peg", 2 },
 43            { "bmp", 3 },
 44            { "psd", 4 },
 45            { "iff", 5 },
 46            { "mat", 6 },
 47            { "nim", 7 },
 48            { "ltf", 8 },
 49            { "glb", 9 }
 50        };
 51
 152        private List<UnityEngine.Object> loadedAssetsByName = new List<UnityEngine.Object>();
 53        private float currentLoadBudgetTime = 0;
 54        private AssetBundleInfo assetBundleInfoToLoad;
 55        private float lastQueuesReprioritizationTime = 0;
 56
 57        private CancellationTokenSource cancellationTokenSource;
 58
 3859        private bool limitTimeBudget => CommonScriptableObjects.rendererState.Get();
 60
 61        public void Start()
 62        {
 4363            if (cancellationTokenSource != null)
 3764                return;
 65
 666            cancellationTokenSource = new CancellationTokenSource();
 667            LoadAssetBundlesAsync(cancellationTokenSource.Token).SuppressCancellationThrow().Forget();
 668        }
 69
 70        public void Stop()
 71        {
 3572            if (cancellationTokenSource == null)
 2973                return;
 74
 675            cancellationTokenSource.Cancel();
 676            cancellationTokenSource.Dispose();
 677            cancellationTokenSource = null;
 78
 679            highPriorityLoadQueue.Clear();
 680            lowPriorityLoadQueue.Clear();
 681        }
 82
 83        public void MarkAssetBundleForLoad(Asset_AB asset, Transform containerTransform, Action onSuccess, Action<Except
 84        {
 2285            CheckForReprioritizeAwaitingAssets();
 86
 2287            AssetBundleInfo assetBundleToLoad = new AssetBundleInfo(asset, containerTransform, onSuccess, onFail);
 88
 2289            float distanceFromPlayer = GetDistanceFromPlayer(containerTransform);
 90
 2291            if (distanceFromPlayer <= MAX_SQR_DISTANCE_FOR_QUICK_LOADING)
 2292                highPriorityLoadQueue.Enqueue(assetBundleToLoad);
 93            else
 094                lowPriorityLoadQueue.Enqueue(assetBundleToLoad);
 095        }
 96
 97        private async UniTask LoadAssetBundlesAsync(CancellationToken cancellationToken)
 98        {
 234899            while (!cancellationToken.IsCancellationRequested)
 100            {
 2364101                while (highPriorityLoadQueue.Count > 0)
 102                {
 22103                    float time = Time.realtimeSinceStartup;
 104
 22105                    assetBundleInfoToLoad = highPriorityLoadQueue.Dequeue();
 66106                    await LoadAssetBundleAsync(assetBundleInfoToLoad, cancellationToken);
 107
 22108                    if (IsLoadBudgetTimeReached(time))
 109                    {
 0110                        await WaitForSkippedFrames(SKIPPED_FRAMES_AFTER_BUDGET_TIME_IS_REACHED_FOR_NEARBY_ASSETS);
 111                    }
 112                }
 113
 2342114                while (lowPriorityLoadQueue.Count > 0 && highPriorityLoadQueue.Count == 0)
 115                {
 0116                    float time = Time.realtimeSinceStartup;
 117
 0118                    assetBundleInfoToLoad = lowPriorityLoadQueue.Dequeue();
 0119                    await LoadAssetBundleAsync(assetBundleInfoToLoad, cancellationToken);
 120
 0121                    if (IsLoadBudgetTimeReached(time))
 122                    {
 0123                        await WaitForSkippedFrames(SKIPPED_FRAMES_AFTER_BUDGET_TIME_IS_REACHED_FOR_DISTANT_ASSETS);
 124                    }
 125                }
 126
 7026127                await UniTask.Yield();
 128            }
 6129        }
 130
 131        private async UniTask LoadAssetBundleAsync(AssetBundleInfo assetBundleInfo, CancellationToken ct)
 132        {
 22133            if (!assetBundleInfo.asset.IsValid())
 134            {
 0135                assetBundleInfo.onFail?.Invoke(new Exception("Asset bundle is null"));
 0136                return;
 137            }
 138
 22139            AssetBundleRequest abRequest = assetBundleInfo.asset.LoadAllAssetsAsync();
 66140            await abRequest.WithCancellation(ct);
 141
 22142            loadedAssetsByName = abRequest.allAssets.ToList();
 143
 188144            foreach (var loadedAsset in loadedAssetsByName)
 145            {
 72146                string ext = "any";
 147
 79148                if (loadedAsset is Texture) { ext = "png"; }
 65149                else if (loadedAsset is Material material)
 150                {
 13151                    ShaderUtils.UpgradeMaterial_2020_To_2021(material);
 13152                    ext = "mat";
 153                }
 60154                else if (loadedAsset is Animation || loadedAsset is AnimationClip) { ext = "nim"; }
 57155                else if (loadedAsset is GameObject) { ext = "glb"; }
 156
 72157                assetBundleInfo.asset.AddAssetByExtension(ext, loadedAsset);
 158            }
 159
 22160            loadedAssetsByName.Clear();
 22161            assetBundleInfo.onSuccess?.Invoke();
 22162        }
 163
 164        private bool IsLoadBudgetTimeReached(float startTime)
 165        {
 22166            if (limitTimeBudget)
 167            {
 0168                currentLoadBudgetTime += Time.realtimeSinceStartup - startTime;
 169
 0170                if (currentLoadBudgetTime > MAX_LOAD_BUDGET_TIME)
 171                {
 0172                    currentLoadBudgetTime = 0f;
 0173                    return true;
 174                }
 175            }
 176
 22177            return false;
 178        }
 179
 180        private UniTask WaitForSkippedFrames(int skippedFramesBetweenLoadings) =>
 0181            UniTask.DelayFrame(skippedFramesBetweenLoadings);
 182
 183        private void CheckForReprioritizeAwaitingAssets()
 184        {
 22185            if (lowPriorityLoadQueue.Count == 0 ||
 186                (Time.realtimeSinceStartup - lastQueuesReprioritizationTime) < TIME_BETWEEN_REPRIORITIZATIONS)
 22187                return;
 188
 0189            while (lowPriorityLoadQueue.Count > 0 && GetDistanceFromPlayer(lowPriorityLoadQueue.Peek().containerTransfor
 190            {
 0191                highPriorityLoadQueue.Enqueue(lowPriorityLoadQueue.Dequeue());
 0192                lastQueuesReprioritizationTime = Time.realtimeSinceStartup;
 193            }
 0194        }
 195
 196        private float GetDistanceFromPlayer(Transform containerTransform)
 197        {
 22198            return (containerTransform != null && limitTimeBudget) ? Vector3.SqrMagnitude(containerTransform.position - 
 199        }
 200    }
 201}