< Summary

Class:WearableItem
Assembly:AvatarAssets
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Models/AvatarAssets/WearableItem.cs
Covered lines:61
Uncovered lines:8
Coverable lines:69
Total lines:276
Line coverage:88.4% (61 of 69)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
WearableItem()0%110100%
TryGetRepresentation(...)0%110100%
GetRepresentation(...)0%660100%
GetContentProvider(...)0%3.023087.5%
CreateContentProvider(...)0%6200%
SupportsBodyShape(...)0%6.076087.5%
GetReplacesList(...)0%550100%
GetHidesList(...)0%770100%
DoesHide(...)0%110100%
IsCollectible()0%2100%
IsSkin()0%110100%
IsSmart()0%9.089090%
GetName(...)0%440100%
GetIssuedCountFromRarity(...)0%7.237083.33%
ComposeThumbnailUrl()0%110100%
ComposeHiddenCategories(...)0%440100%
IsInL2()0%3.333066.67%
IsEmote()0%2100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Models/AvatarAssets/WearableItem.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using DCL;
 5using DCL.Emotes;
 6
 7[Serializable]
 8public class WearableItem
 9{
 10    [Serializable]
 11    public class MappingPair
 12    {
 13        public string key;
 14        public string hash;
 15    }
 16
 17    [Serializable]
 18    public class Representation
 19    {
 20        public string[] bodyShapes;
 21        public string mainFile;
 22        public MappingPair[] contents;
 23        public string[] overrideHides;
 24        public string[] overrideReplaces;
 25    }
 26
 27    [Serializable]
 28    public class Data
 29    {
 30        public Representation[] representations;
 31        public string category;
 32        public string[] tags;
 33        public string[] replaces;
 34        public string[] hides;
 35    }
 36
 37    public Data data;
 38    public EmoteDataV0 emoteDataV0 = null;
 39    public string id;
 40
 41    public string baseUrl;
 42    public string baseUrlBundles;
 43
 44    public i18n[] i18n;
 45    public string thumbnail;
 46
 47    //This fields are temporary, once Kernel is finished we must move them to wherever they are placed
 48    public string rarity;
 49    public string description;
 50    public int issuedId;
 51
 325552    private readonly Dictionary<string, string> cachedI18n = new Dictionary<string, string>();
 325553    private readonly Dictionary<string, ContentProvider> cachedContentProviers =
 54        new Dictionary<string, ContentProvider>();
 55
 325556    private readonly string[] skinImplicitCategories =
 57    {
 58        WearableLiterals.Categories.EYES,
 59        WearableLiterals.Categories.MOUTH,
 60        WearableLiterals.Categories.EYEBROWS,
 61        WearableLiterals.Categories.HAIR,
 62        WearableLiterals.Categories.UPPER_BODY,
 63        WearableLiterals.Categories.LOWER_BODY,
 64        WearableLiterals.Categories.FEET,
 65        WearableLiterals.Misc.HEAD,
 66        WearableLiterals.Categories.FACIAL_HAIR
 67    };
 68
 69    public bool TryGetRepresentation(string bodyshapeId, out Representation representation)
 70    {
 57671        representation = GetRepresentation(bodyshapeId);
 57672        return representation != null;
 73    }
 74
 75    public Representation GetRepresentation(string bodyShapeType)
 76    {
 508677        if (data?.representations == null)
 278            return null;
 79
 1036280        for (int i = 0; i < data.representations.Length; i++)
 81        {
 517982            if (data.representations[i].bodyShapes.Contains(bodyShapeType))
 83            {
 508284                return data.representations[i];
 85            }
 86        }
 87
 288        return null;
 89    }
 90
 91    public ContentProvider GetContentProvider(string bodyShapeType)
 92    {
 10193        var representation = GetRepresentation(bodyShapeType);
 94
 10195        if (representation == null)
 096            return null;
 97
 10198        if (!cachedContentProviers.ContainsKey(bodyShapeType))
 99        {
 72100            var contentProvider = CreateContentProvider(baseUrl, representation.contents);
 72101            contentProvider.BakeHashes();
 72102            cachedContentProviers.Add(bodyShapeType, contentProvider);
 103        }
 104
 101105        return cachedContentProviers[bodyShapeType];
 106    }
 107
 108    protected virtual ContentProvider CreateContentProvider(string baseUrl, MappingPair[] contents)
 109    {
 0110        return new ContentProvider
 111        {
 112            baseUrl = baseUrl,
 0113            contents = contents.Select(mapping => new ContentServerUtils.MappingPair()
 114                                   { file = mapping.key, hash = mapping.hash })
 115                               .ToList()
 116        };
 117    }
 118
 119    public bool SupportsBodyShape(string bodyShapeType)
 120    {
 3740121        if (data?.representations == null)
 0122            return false;
 123
 10096124        for (int i = 0; i < data.representations.Length; i++)
 125        {
 4153126            if (data.representations[i].bodyShapes.Contains(bodyShapeType))
 127            {
 2845128                return true;
 129            }
 130        }
 131
 895132        return false;
 133    }
 134
 135    public string[] GetReplacesList(string bodyShapeType)
 136    {
 3711137        var representation = GetRepresentation(bodyShapeType);
 138
 3711139        if (representation?.overrideReplaces == null || representation.overrideReplaces.Length == 0)
 3709140            return data.replaces;
 141
 2142        return representation.overrideReplaces;
 143    }
 144
 145    public string[] GetHidesList(string bodyShapeType)
 146    {
 595147        var representation = GetRepresentation(bodyShapeType);
 148
 149        string[] hides;
 150
 595151        if (representation?.overrideHides == null || representation.overrideHides.Length == 0)
 594152            hides = data.hides;
 153        else
 1154            hides = representation.overrideHides;
 155
 595156        if (IsSkin())
 157        {
 11158            hides = hides == null
 159                ? skinImplicitCategories
 160                : hides.Concat(skinImplicitCategories).Distinct().ToArray();
 161        }
 162
 595163        return hides;
 164    }
 165
 54166    public bool DoesHide(string category, string bodyShape) => GetHidesList(bodyShape).Any(s => s == category);
 167
 0168    public bool IsCollectible() { return !string.IsNullOrEmpty(rarity); }
 169
 675170    public bool IsSkin() => data.category == WearableLiterals.Categories.SKIN;
 171
 172    public bool IsSmart()
 173    {
 36174        if (data?.representations == null) return false;
 175
 140176        for (var i = 0; i < data.representations.Length; i++)
 177        {
 36178            var representation = data.representations[i];
 98179            var containsGameJs = representation.contents?.Any(pair => pair.key.EndsWith("game.js")) ?? false;
 38180            if (containsGameJs) return true;
 181        }
 182
 34183        return false;
 184    }
 185
 186    public string GetName(string langCode = "en")
 187    {
 37188        if (!cachedI18n.ContainsKey(langCode))
 189        {
 36190            cachedI18n.Add(langCode, i18n.FirstOrDefault(x => x.code == langCode)?.text);
 191        }
 192
 37193        return cachedI18n[langCode];
 194    }
 195
 196    public int GetIssuedCountFromRarity(string rarity)
 197    {
 198        switch (rarity)
 199        {
 200            case WearableLiterals.ItemRarity.RARE:
 4201                return 5000;
 202            case WearableLiterals.ItemRarity.EPIC:
 27203                return 1000;
 204            case WearableLiterals.ItemRarity.LEGENDARY:
 2205                return 100;
 206            case WearableLiterals.ItemRarity.MYTHIC:
 2207                return 10;
 208            case WearableLiterals.ItemRarity.UNIQUE:
 2209                return 1;
 210        }
 211
 0212        return int.MaxValue;
 213    }
 214
 198215    public string ComposeThumbnailUrl() { return baseUrl + thumbnail; }
 216
 217    public static HashSet<string> ComposeHiddenCategories(string bodyShapeId, List<WearableItem> wearables)
 218    {
 78219        HashSet<string> result = new HashSet<string>();
 220        //Last wearable added has priority over the rest
 1298221        for (int index = 0; index < wearables.Count; index++)
 222        {
 571223            WearableItem wearableItem = wearables[index];
 571224            if (result.Contains(wearableItem.data.category)) //Skip hidden elements to avoid two elements hiding each ot
 225                continue;
 226
 571227            string[] wearableHidesList = wearableItem.GetHidesList(bodyShapeId);
 571228            if (wearableHidesList != null)
 229            {
 562230                result.UnionWith(wearableHidesList);
 231            }
 232        }
 233
 78234        return result;
 235    }
 236
 237    //Workaround to know the net of a wearable.
 238    //Once wearables are allowed to be moved from Ethereum to Polygon this method wont be reliable anymore
 239    //To retrieve this properly first we need the catalyst to send the net of each wearable, not just the ID
 240    public bool IsInL2()
 241    {
 36242        if (id.StartsWith("urn:decentraland:matic") || id.StartsWith("urn:decentraland:mumbai"))
 0243            return true;
 36244        return false;
 245    }
 246
 0247    public bool IsEmote() { return emoteDataV0 != null; }
 248}
 249
 250[Serializable]
 251public class WearablesRequestResponse
 252{
 253    public WearableItem[] wearables;
 254    public string context;
 255}
 256
 257[Serializable]
 258public class WearablesRequestFailed
 259{
 260    public string error;
 261    public string context;
 262}
 263
 264[Serializable]
 265public class WearableContent
 266{
 267    public string file;
 268    public string hash;
 269}
 270
 271[Serializable]
 272public class i18n
 273{
 274    public string code;
 275    public string text;
 276}