< 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:151
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.Runtime.ExceptionServices;
 5using System.Threading;
 6using Cysharp.Threading.Tasks;
 7using UnityEngine;
 8using UnityEngine.Assertions;
 9
 10namespace AvatarSystem
 11{
 12    public class AvatarCurator : IAvatarCurator
 13    {
 14        private readonly IWearableItemResolver wearableItemResolver;
 15
 130816        public AvatarCurator(IWearableItemResolver wearableItemResolver)
 17        {
 130818            Assert.IsNotNull(wearableItemResolver);
 130819            this.wearableItemResolver = wearableItemResolver;
 130820        }
 21
 22        /// <summary>
 23        /// Curate a flattened into IDs set of wearables.
 24        /// Bear in mind that the bodyshape must be part of the list of wearables
 25        /// </summary>
 26        /// <param name="settings"></param>
 27        /// <param name="wearablesId"></param>
 28        /// <param name="ct"></param>
 29        /// <returns></returns>
 30        /// <exception cref="Exception"></exception>
 31        public async UniTask<(
 32            WearableItem bodyshape,
 33            WearableItem eyes,
 34            WearableItem eyebrows,
 35            WearableItem mouth,
 36            List<WearableItem> wearables,
 37            List<WearableItem> emotes
 38            )> Curate(AvatarSettings settings, IEnumerable<string> wearablesId, CancellationToken ct = default)
 39        {
 8040            ct.ThrowIfCancellationRequested();
 41
 42            try
 43            {
 8144                (List<WearableItem> wearableItems, List<WearableItem> emotes) =  await wearableItemResolver.ResolveAndSp
 7845                HashSet<string> hiddenCategories = WearableItem.ComposeHiddenCategories(settings.bodyshapeId, wearableIt
 46
 7847                Dictionary<string, WearableItem> wearablesByCategory = new Dictionary<string, WearableItem>();
 129848                for (int i = 0; i < wearableItems.Count; i++)
 49                {
 57150                    WearableItem wearableItem = wearableItems[i];
 51
 52                    // Ignore hidden categories
 57153                    if (hiddenCategories.Contains(wearableItem.data.category))
 54                        continue;
 55
 56                    // Avoid having two items with the same category.
 57157                    if (wearableItem == null || wearablesByCategory.ContainsKey(wearableItem.data.category) )
 58                        continue;
 59
 60                    // Filter wearables without representation for the bodyshape
 57161                    if (!wearableItem.TryGetRepresentation(settings.bodyshapeId, out var representation))
 62                        continue;
 63
 57164                    wearablesByCategory.Add(wearableItem.data.category, wearableItem);
 65                }
 66
 7867                if (!wearablesByCategory.ContainsKey(WearableLiterals.Categories.BODY_SHAPE))
 068                    throw new Exception("Set of wearables doesn't contain a bodyshape (or couldn't be resolved)");
 69
 7870                WearableItem[] fallbackWearables = await GetFallbackForMissingNeededCategories(settings.bodyshapeId, wea
 71
 16672                for (int i = 0; i < fallbackWearables.Length; i++)
 73                {
 574                    WearableItem wearableItem = fallbackWearables[i];
 575                    if (wearableItem == null)
 076                        throw new Exception($"Fallback wearable is null");
 577                    if (!wearableItem.TryGetRepresentation(settings.bodyshapeId, out var representation))
 078                        throw new Exception($"Fallback wearable {wearableItem} doesn't contain a representation for {set
 579                    if (wearablesByCategory.ContainsKey(wearableItem.data.category))
 080                        throw new Exception($"A wearable in category {wearableItem.data.category} already exists trying 
 581                    wearablesByCategory.Add(wearableItem.data.category, wearableItem);
 82                }
 83
 84                // Wearables that are not bodyshape or facialFeatures
 7885                List<WearableItem> wearables = wearablesByCategory.Where(
 86                                                                      x =>
 57687                                                                          x.Key != WearableLiterals.Categories.BODY_SHAP
 88                                                                          x.Key != WearableLiterals.Categories.EYES &&
 89                                                                          x.Key != WearableLiterals.Categories.EYEBROWS 
 90                                                                          x.Key != WearableLiterals.Categories.MOUTH)
 26491                                                                  .Select(x => x.Value)
 92                                                                  .ToList();
 93
 7894                return (
 95                    wearablesByCategory[WearableLiterals.Categories.BODY_SHAPE],
 96                    wearablesByCategory.ContainsKey(WearableLiterals.Categories.EYES) ? wearablesByCategory[WearableLite
 97                    wearablesByCategory.ContainsKey(WearableLiterals.Categories.EYEBROWS) ? wearablesByCategory[Wearable
 98                    wearablesByCategory.ContainsKey(WearableLiterals.Categories.MOUTH) ? wearablesByCategory[WearableLit
 99                    wearables,
 100                    emotes.ToList()
 101                );
 102            }
 1103            catch (OperationCanceledException)
 104            {
 105                //No Disposing required
 1106                throw;
 107            }
 108            catch (Exception e)
 109            {
 0110                Debug.Log("Failed curating avatar wearables");
 0111                ExceptionDispatchInfo.Capture(e).Throw();
 0112                throw;
 113            }
 78114        }
 115
 116        private async UniTask<WearableItem[]> GetFallbackForMissingNeededCategories(string bodyshapeId, Dictionary<strin
 117        {
 78118            ct.ThrowIfCancellationRequested();
 119
 120            try
 121            {
 78122                List<UniTask<WearableItem>> neededWearablesTasks = new List<UniTask<WearableItem>>();
 936123                foreach (string neededCategory in WearableLiterals.Categories.REQUIRED_CATEGORIES)
 124                {
 125                    // If a needed category is hidden we dont need to fallback, we skipped it on purpose
 390126                    if (hiddenCategories.Contains(neededCategory))
 127                        continue;
 128
 129                    // The needed category is present
 390130                    if (wearablesByCategory.ContainsKey(neededCategory))
 131                        continue;
 132
 5133                    string fallbackWearableId = WearableLiterals.DefaultWearables.GetDefaultWearable(bodyshapeId, needed
 134
 5135                    if (fallbackWearableId == null)
 0136                        throw new Exception($"Couldn't find a fallback wearable for bodyshape: {bodyshapeId} and categor
 137
 5138                    neededWearablesTasks.Add(wearableItemResolver.Resolve(fallbackWearableId, ct));
 139                }
 78140                return await UniTask.WhenAll(neededWearablesTasks).AttachExternalCancellation(ct);
 141            }
 0142            catch (OperationCanceledException)
 143            {
 144                //No disposing required
 0145                throw;
 146            }
 78147        }
 148
 2820149        public void Dispose() { wearableItemResolver.Dispose(); }
 150    }
 151}