< Summary

Class:AvatarSystem.AvatarCurator
Assembly:AvatarSystem
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/AvatarCurator.cs
Covered lines:40
Uncovered lines:10
Coverable lines:50
Total lines:141
Line coverage:80% (40 of 50)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
AvatarCurator(...)0%110100%
Curate()0%31.6524076.32%
GetFallbackForMissingNeededCategories()0%12.5410070.59%
Dispose()0%110100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/AvatarCurator.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using System.Threading;
 5using Cysharp.Threading.Tasks;
 6using UnityEngine;
 7using UnityEngine.Assertions;
 8
 9namespace AvatarSystem
 10{
 11    public class AvatarCurator : IAvatarCurator
 12    {
 13        private readonly IWearableItemResolver wearableItemResolver;
 14
 130815        public AvatarCurator(IWearableItemResolver wearableItemResolver)
 16        {
 130817            Assert.IsNotNull(wearableItemResolver);
 130818            this.wearableItemResolver = wearableItemResolver;
 130819        }
 20
 21        /// <summary>
 22        /// Curate a flattened into IDs set of wearables.
 23        /// Bear in mind that the bodyshape must be part of the list of wearables
 24        /// </summary>
 25        /// <param name="settings"></param>
 26        /// <param name="wearablesId"></param>
 27        /// <param name="ct"></param>
 28        /// <returns></returns>
 29        /// <exception cref="Exception"></exception>
 30        public async UniTask<(WearableItem bodyshape, WearableItem eyes, WearableItem eyebrows, WearableItem mouth, List
 31        {
 8032            ct.ThrowIfCancellationRequested();
 33
 34            try
 35            {
 8136                WearableItem[] wearableItems =  await wearableItemResolver.Resolve(wearablesId, ct);
 7837                HashSet<string> hiddenCategories = WearableItem.ComposeHiddenCategories(settings.bodyshapeId, wearableIt
 38
 7839                Dictionary<string, WearableItem> wearablesByCategory = new Dictionary<string, WearableItem>();
 129840                for (int i = 0; i < wearableItems.Length; i++)
 41                {
 57142                    WearableItem wearableItem = wearableItems[i];
 43
 44                    // Ignore hidden categories
 57145                    if (hiddenCategories.Contains(wearableItem.data.category))
 46                        continue;
 47
 48                    // Avoid having two items with the same category.
 57149                    if (wearableItem == null || wearablesByCategory.ContainsKey(wearableItem.data.category) )
 50                        continue;
 51
 52                    // Filter wearables without representation for the bodyshape
 57153                    if (!wearableItem.TryGetRepresentation(settings.bodyshapeId, out var representation))
 54                        continue;
 55
 57156                    wearablesByCategory.Add(wearableItem.data.category, wearableItem);
 57                }
 58
 7859                if (!wearablesByCategory.ContainsKey(WearableLiterals.Categories.BODY_SHAPE))
 060                    throw new Exception("Set of wearables doesn't contain a bodyshape (or couldn't be resolved)");
 61
 7862                WearableItem[] fallbackWearables = await GetFallbackForMissingNeededCategories(settings.bodyshapeId, wea
 63
 16664                for (int i = 0; i < fallbackWearables.Length; i++)
 65                {
 566                    WearableItem wearableItem = fallbackWearables[i];
 567                    if (wearableItem == null)
 068                        throw new Exception($"Fallback wearable is null");
 569                    if (!wearableItem.TryGetRepresentation(settings.bodyshapeId, out var representation))
 070                        throw new Exception($"Fallback wearable {wearableItem} doesn't contain a representation for {set
 571                    if (wearablesByCategory.ContainsKey(wearableItem.data.category))
 072                        throw new Exception($"A wearable in category {wearableItem.data.category} already exists trying 
 573                    wearablesByCategory.Add(wearableItem.data.category, wearableItem);
 74                }
 75
 76                // Wearables that are not bodyshape or facialFeatures
 7877                List<WearableItem> wearables = wearablesByCategory.Where(
 78                                                                      x =>
 57679                                                                          x.Key != WearableLiterals.Categories.BODY_SHAP
 80                                                                          x.Key != WearableLiterals.Categories.EYES &&
 81                                                                          x.Key != WearableLiterals.Categories.EYEBROWS 
 82                                                                          x.Key != WearableLiterals.Categories.MOUTH)
 26483                                                                  .Select(x => x.Value)
 84                                                                  .ToList();
 85
 7886                return (
 87                    wearablesByCategory[WearableLiterals.Categories.BODY_SHAPE],
 88                    wearablesByCategory.ContainsKey(WearableLiterals.Categories.EYES) ? wearablesByCategory[WearableLite
 89                    wearablesByCategory.ContainsKey(WearableLiterals.Categories.EYEBROWS) ? wearablesByCategory[Wearable
 90                    wearablesByCategory.ContainsKey(WearableLiterals.Categories.MOUTH) ? wearablesByCategory[WearableLit
 91                    wearables
 92                );
 93            }
 194            catch (OperationCanceledException)
 95            {
 96                //No Disposing required
 197                throw;
 98            }
 099            catch
 100            {
 0101                Debug.Log("Failed curating avatar wearables");
 0102                throw;
 103            }
 78104        }
 105
 106        private async UniTask<WearableItem[]> GetFallbackForMissingNeededCategories(string bodyshapeId, Dictionary<strin
 107        {
 78108            ct.ThrowIfCancellationRequested();
 109
 110            try
 111            {
 78112                List<UniTask<WearableItem>> neededWearablesTasks = new List<UniTask<WearableItem>>();
 936113                foreach (string neededCategory in WearableLiterals.Categories.REQUIRED_CATEGORIES)
 114                {
 115                    // If a needed category is hidden we dont need to fallback, we skipped it on purpose
 390116                    if (hiddenCategories.Contains(neededCategory))
 117                        continue;
 118
 119                    // The needed category is present
 390120                    if (wearablesByCategory.ContainsKey(neededCategory))
 121                        continue;
 122
 5123                    string fallbackWearableId = WearableLiterals.DefaultWearables.GetDefaultWearable(bodyshapeId, needed
 124
 5125                    if (fallbackWearableId == null)
 0126                        throw new Exception($"Couldn't find a fallback wearable for bodyshape: {bodyshapeId} and categor
 127
 5128                    neededWearablesTasks.Add(wearableItemResolver.Resolve(fallbackWearableId, ct));
 129                }
 78130                return await UniTask.WhenAll(neededWearablesTasks).AttachExternalCancellation(ct);
 131            }
 0132            catch (OperationCanceledException)
 133            {
 134                //No disposing required
 0135                throw;
 136            }
 78137        }
 138
 2820139        public void Dispose() { wearableItemResolver.Dispose(); }
 140    }
 141}