< Summary

Class:WearableItem
Assembly:AvatarAssets
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Models/AvatarAssets/WearableItem.cs
Covered lines:75
Uncovered lines:11
Coverable lines:86
Total lines:324
Line coverage:87.2% (75 of 86)
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%220100%
SupportsBodyShape(...)0%6.076087.5%
GetReplacesList(...)0%550100%
GetHidesList(...)0%770100%
SanitizeHidesLists()0%440100%
DoesHide(...)0%110100%
IsCollectible()0%2.152066.67%
IsSkin()0%110100%
IsSmart()0%9.089090%
GetName(...)0%440100%
GetIssuedCountFromRarity(...)0%770100%
ComposeThumbnailUrl()0%110100%
ComposeHiddenCategories(...)0%4.024090%
IsInL2()0%3.333066.67%
IsEmote()0%2100%
ToString()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;
 6using UnityEngine;
 7
 8[Serializable]
 9public class WearableItem
 10{
 11    private const string THIRD_PARTY_COLLECTIONS_PATH = "collections-thirdparty";
 12
 13    [Serializable]
 14    public class MappingPair
 15    {
 16        public string key;
 17        public string hash;
 18    }
 19
 20    [Serializable]
 21    public class Representation
 22    {
 23        public string[] bodyShapes;
 24        public string mainFile;
 25        public MappingPair[] contents;
 26        public string[] overrideHides;
 27        public string[] overrideReplaces;
 28    }
 29
 30    [Serializable]
 31    public class Data
 32    {
 33        public Representation[] representations;
 34        public string category;
 35        public string[] tags;
 36        public string[] replaces;
 37        public string[] hides;
 38        public bool loop;
 39    }
 40
 41    public Data data;
 42    public EmoteDataV0 emoteDataV0;
 43    public string id;
 44
 45    public string baseUrl;
 46    public string baseUrlBundles;
 47
 48    public i18n[] i18n;
 49    public string thumbnail;
 50
 51    private string thirdPartyCollectionId;
 52    public string ThirdPartyCollectionId
 53    {
 54        get
 55        {
 1383956            if (!string.IsNullOrEmpty(thirdPartyCollectionId)) return thirdPartyCollectionId;
 2767857            if (!id.Contains(THIRD_PARTY_COLLECTIONS_PATH)) return "";
 058            var paths = id.Split(':');
 059            var thirdPartyIndex = Array.IndexOf(paths, THIRD_PARTY_COLLECTIONS_PATH);
 060            thirdPartyCollectionId = string.Join(":", paths, 0, thirdPartyIndex + 2);
 061            return thirdPartyCollectionId;
 62        }
 63    }
 64
 1383065    public bool IsFromThirdPartyCollection => !string.IsNullOrEmpty(ThirdPartyCollectionId);
 66
 67    public Sprite thumbnailSprite;
 68
 69    //This fields are temporary, once Kernel is finished we must move them to wherever they are placed
 70    public string rarity;
 71    public string description;
 72    public int issuedId;
 73
 365674    private readonly Dictionary<string, string> cachedI18n = new Dictionary<string, string>();
 365675    private readonly Dictionary<string, ContentProvider> cachedContentProviers =
 76        new Dictionary<string, ContentProvider>();
 77
 365678    private readonly string[] skinImplicitCategories =
 79    {
 80        WearableLiterals.Categories.EYES,
 81        WearableLiterals.Categories.MOUTH,
 82        WearableLiterals.Categories.EYEBROWS,
 83        WearableLiterals.Categories.HAIR,
 84        WearableLiterals.Categories.UPPER_BODY,
 85        WearableLiterals.Categories.LOWER_BODY,
 86        WearableLiterals.Categories.FEET,
 87        WearableLiterals.Misc.HEAD,
 88        WearableLiterals.Categories.FACIAL_HAIR
 89    };
 90
 91    public bool TryGetRepresentation(string bodyshapeId, out Representation representation)
 92    {
 1493        representation = GetRepresentation(bodyshapeId);
 1494        return representation != null;
 95    }
 96
 97    public Representation GetRepresentation(string bodyShapeType)
 98    {
 430399        if (data?.representations == null)
 3100            return null;
 101
 8724102        for (int i = 0; i < data.representations.Length; i++)
 103        {
 4360104            if (data.representations[i].bodyShapes.Contains(bodyShapeType))
 105            {
 4298106                return data.representations[i];
 107            }
 108        }
 109
 2110        return null;
 111    }
 112
 113    public ContentProvider GetContentProvider(string bodyShapeType)
 114    {
 26115        var representation = GetRepresentation(bodyShapeType);
 116
 26117        if (representation == null)
 0118            return null;
 119
 26120        if (!cachedContentProviers.ContainsKey(bodyShapeType))
 121        {
 23122            var contentProvider = CreateContentProvider(baseUrl, representation.contents);
 23123            contentProvider.BakeHashes();
 23124            cachedContentProviers.Add(bodyShapeType, contentProvider);
 125        }
 126
 26127        return cachedContentProviers[bodyShapeType];
 128    }
 129
 130    protected virtual ContentProvider CreateContentProvider(string baseUrl, MappingPair[] contents)
 131    {
 1132        return new ContentProvider
 133        {
 134            baseUrl = baseUrl,
 1135            contents = contents.Select(mapping => new ContentServerUtils.MappingPair()
 136                                   { file = mapping.key, hash = mapping.hash })
 137                               .ToList()
 138        };
 139    }
 140
 141    public bool SupportsBodyShape(string bodyShapeType)
 142    {
 1112143        if (data?.representations == null)
 0144            return false;
 145
 2280146        for (int i = 0; i < data.representations.Length; i++)
 147        {
 1133148            if (data.representations[i].bodyShapes.Contains(bodyShapeType))
 149            {
 1105150                return true;
 151            }
 152        }
 153
 7154        return false;
 155    }
 156
 157    public string[] GetReplacesList(string bodyShapeType)
 158    {
 4190159        var representation = GetRepresentation(bodyShapeType);
 160
 4190161        if (representation?.overrideReplaces == null || representation.overrideReplaces.Length == 0)
 4188162            return data.replaces;
 163
 2164        return representation.overrideReplaces;
 165    }
 166
 167    public string[] GetHidesList(string bodyShapeType)
 168    {
 44169        var representation = GetRepresentation(bodyShapeType);
 170
 171        string[] hides;
 172
 44173        if (representation?.overrideHides == null || representation.overrideHides.Length == 0)
 42174            hides = data.hides;
 175        else
 2176            hides = representation.overrideHides;
 177
 44178        if (IsSkin())
 179        {
 11180            hides = hides == null
 181                ? skinImplicitCategories
 182                : hides.Concat(skinImplicitCategories).Distinct().ToArray();
 183        }
 184
 44185        return hides;
 186    }
 187
 188    public void SanitizeHidesLists()
 189    {
 190        //remove bodyshape from hides list
 3097191        if (data.hides != null)
 3097192            data.hides = data.hides.Except(new [] { WearableLiterals.Categories.BODY_SHAPE }).ToArray();
 14280193        for (int i = 0; i < data.representations.Length; i++)
 194        {
 4043195            Representation representation = data.representations[i];
 4043196            if (representation.overrideHides != null)
 4043197                representation.overrideHides = representation.overrideHides.Except(new [] { WearableLiterals.Categories.
 198
 199        }
 3097200    }
 201
 54202    public bool DoesHide(string category, string bodyShape) => GetHidesList(bodyShape).Any(s => s == category);
 203
 204    public bool IsCollectible()
 205    {
 16983206        if (id == null)
 0207            return false;
 208
 16983209        return !id.StartsWith("urn:decentraland:off-chain:base-avatars:");
 210    }
 211
 5524212    public bool IsSkin() => data.category == WearableLiterals.Categories.SKIN;
 213
 214    public bool IsSmart()
 215    {
 6456216        if (data?.representations == null) return false;
 217
 27562218        for (var i = 0; i < data.representations.Length; i++)
 219        {
 7328220            var representation = data.representations[i];
 23645221            var containsGameJs = representation.contents?.Any(pair => pair.key.EndsWith("game.js")) ?? false;
 7331222            if (containsGameJs) return true;
 223        }
 224
 6453225        return false;
 226    }
 227
 228    public string GetName(string langCode = "en")
 229    {
 7374230        if (!cachedI18n.ContainsKey(langCode))
 231        {
 2760232            cachedI18n.Add(langCode, i18n.FirstOrDefault(x => x.code == langCode)?.text);
 233        }
 234
 7374235        return cachedI18n[langCode];
 236    }
 237
 238    public int GetIssuedCountFromRarity(string rarity)
 239    {
 240        switch (rarity)
 241        {
 242            case WearableLiterals.ItemRarity.RARE:
 6243                return 5000;
 244            case WearableLiterals.ItemRarity.EPIC:
 76245                return 1000;
 246            case WearableLiterals.ItemRarity.LEGENDARY:
 12247                return 100;
 248            case WearableLiterals.ItemRarity.MYTHIC:
 3249                return 10;
 250            case WearableLiterals.ItemRarity.UNIQUE:
 3251                return 1;
 252        }
 253
 6348254        return int.MaxValue;
 255    }
 256
 1075257    public string ComposeThumbnailUrl() { return baseUrl + thumbnail; }
 258
 259    public static HashSet<string> ComposeHiddenCategories(string bodyShapeId, List<WearableItem> wearables)
 260    {
 2261        HashSet<string> result = new HashSet<string>();
 262        //Last wearable added has priority over the rest
 22263        for (int index = 0; index < wearables.Count; index++)
 264        {
 9265            WearableItem wearableItem = wearables[index];
 9266            if (result.Contains(wearableItem.data.category)) //Skip hidden elements to avoid two elements hiding each ot
 267                continue;
 268
 9269            string[] wearableHidesList = wearableItem.GetHidesList(bodyShapeId);
 9270            if (wearableHidesList != null)
 271            {
 0272                result.UnionWith(wearableHidesList);
 273            }
 274        }
 275
 2276        return result;
 277    }
 278
 279    //Workaround to know the net of a wearable.
 280    //Once wearables are allowed to be moved from Ethereum to Polygon this method wont be reliable anymore
 281    //To retrieve this properly first we need the catalyst to send the net of each wearable, not just the ID
 282    public bool IsInL2()
 283    {
 7371284        if (id.StartsWith("urn:decentraland:matic") || id.StartsWith("urn:decentraland:mumbai"))
 0285            return true;
 7371286        return false;
 287    }
 288
 0289    public bool IsEmote() { return emoteDataV0 != null; }
 290
 0291    public override string ToString() { return id; }
 292}
 293
 294[Serializable]
 295public class EmoteItem : WearableItem{
 296}
 297
 298[Serializable]
 299public class WearablesRequestResponse
 300{
 301    public WearableItem[] wearables;
 302    public string context;
 303}
 304
 305[Serializable]
 306public class WearablesRequestFailed
 307{
 308    public string error;
 309    public string context;
 310}
 311
 312[Serializable]
 313public class WearableContent
 314{
 315    public string file;
 316    public string hash;
 317}
 318
 319[Serializable]
 320public class i18n
 321{
 322    public string code;
 323    public string text;
 324}