< Summary

Class:WearableItem
Assembly:AvatarAssets
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Models/AvatarAssets/WearableItem.cs
Covered lines:79
Uncovered lines:12
Coverable lines:91
Total lines:329
Line coverage:86.8% (79 of 91)
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%660100%
ComposeThumbnailUrl()0%110100%
ComposeHiddenCategories(...)0%4.024090%
IsInL2()0%3.333066.67%
IsEmote()0%110100%
ShowInBackpack()0%110100%
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        {
 1190756            if (!string.IsNullOrEmpty(thirdPartyCollectionId))
 057                return thirdPartyCollectionId;
 1190758            if (!id.Contains(THIRD_PARTY_COLLECTIONS_PATH))
 1190759                return "";
 060            var paths = id.Split(':');
 061            var thirdPartyIndex = Array.IndexOf(paths, THIRD_PARTY_COLLECTIONS_PATH);
 062            thirdPartyCollectionId = string.Join(":", paths, 0, thirdPartyIndex + 2);
 063            return thirdPartyCollectionId;
 64        }
 65    }
 66
 1189867    public bool IsFromThirdPartyCollection => !string.IsNullOrEmpty(ThirdPartyCollectionId);
 68
 69    public Sprite thumbnailSprite;
 70
 71    //This fields are temporary, once Kernel is finished we must move them to wherever they are placed
 72    public string rarity;
 73    public string description;
 74    public int issuedId;
 75
 440576    private readonly Dictionary<string, string> cachedI18n = new Dictionary<string, string>();
 440577    private readonly Dictionary<string, ContentProvider> cachedContentProviers =
 78        new Dictionary<string, ContentProvider>();
 79
 440580    private readonly string[] skinImplicitCategories =
 81    {
 82        WearableLiterals.Categories.EYES,
 83        WearableLiterals.Categories.MOUTH,
 84        WearableLiterals.Categories.EYEBROWS,
 85        WearableLiterals.Categories.HAIR,
 86        WearableLiterals.Categories.UPPER_BODY,
 87        WearableLiterals.Categories.LOWER_BODY,
 88        WearableLiterals.Categories.FEET,
 89        WearableLiterals.Misc.HEAD,
 90        WearableLiterals.Categories.FACIAL_HAIR
 91    };
 92
 93    public bool TryGetRepresentation(string bodyshapeId, out Representation representation)
 94    {
 1495        representation = GetRepresentation(bodyshapeId);
 1496        return representation != null;
 97    }
 98
 99    public Representation GetRepresentation(string bodyShapeType)
 100    {
 3862101        if (data?.representations == null)
 3102            return null;
 103
 7842104        for (int i = 0; i < data.representations.Length; i++)
 105        {
 3919106            if (data.representations[i].bodyShapes.Contains(bodyShapeType))
 107            {
 3857108                return data.representations[i];
 109            }
 110        }
 111
 2112        return null;
 113    }
 114
 115    public ContentProvider GetContentProvider(string bodyShapeType)
 116    {
 26117        var representation = GetRepresentation(bodyShapeType);
 118
 26119        if (representation == null)
 0120            return null;
 121
 26122        if (!cachedContentProviers.ContainsKey(bodyShapeType))
 123        {
 23124            var contentProvider = CreateContentProvider(baseUrl, representation.contents);
 23125            contentProvider.BakeHashes();
 23126            cachedContentProviers.Add(bodyShapeType, contentProvider);
 127        }
 128
 26129        return cachedContentProviers[bodyShapeType];
 130    }
 131
 132    protected virtual ContentProvider CreateContentProvider(string baseUrl, MappingPair[] contents)
 133    {
 1134        return new ContentProvider
 135        {
 136            baseUrl = baseUrl,
 1137            contents = contents.Select(mapping => new ContentServerUtils.MappingPair()
 138                                   { file = mapping.key, hash = mapping.hash })
 139                               .ToList()
 140        };
 141    }
 142
 143    public bool SupportsBodyShape(string bodyShapeType)
 144    {
 986145        if (data?.representations == null)
 0146            return false;
 147
 2028148        for (int i = 0; i < data.representations.Length; i++)
 149        {
 1007150            if (data.representations[i].bodyShapes.Contains(bodyShapeType))
 151            {
 979152                return true;
 153            }
 154        }
 155
 7156        return false;
 157    }
 158
 159    public string[] GetReplacesList(string bodyShapeType)
 160    {
 3749161        var representation = GetRepresentation(bodyShapeType);
 162
 3749163        if (representation?.overrideReplaces == null || representation.overrideReplaces.Length == 0)
 3747164            return data.replaces;
 165
 2166        return representation.overrideReplaces;
 167    }
 168
 169    public string[] GetHidesList(string bodyShapeType)
 170    {
 44171        var representation = GetRepresentation(bodyShapeType);
 172
 173        string[] hides;
 174
 44175        if (representation?.overrideHides == null || representation.overrideHides.Length == 0)
 42176            hides = data.hides;
 177        else
 2178            hides = representation.overrideHides;
 179
 44180        if (IsSkin())
 181        {
 11182            hides = hides == null
 183                ? skinImplicitCategories
 184                : hides.Concat(skinImplicitCategories).Distinct().ToArray();
 185        }
 186
 44187        return hides;
 188    }
 189
 190    public void SanitizeHidesLists()
 191    {
 192        //remove bodyshape from hides list
 3421193        if (data.hides != null)
 3421194            data.hides = data.hides.Except(new [] { WearableLiterals.Categories.BODY_SHAPE }).ToArray();
 15774195        for (int i = 0; i < data.representations.Length; i++)
 196        {
 4466197            Representation representation = data.representations[i];
 4466198            if (representation.overrideHides != null)
 4466199                representation.overrideHides = representation.overrideHides.Except(new [] { WearableLiterals.Categories.
 200
 201        }
 3421202    }
 203
 54204    public bool DoesHide(string category, string bodyShape) => GetHidesList(bodyShape).Any(s => s == category);
 205
 206    public bool IsCollectible()
 207    {
 12846208        if (id == null)
 0209            return false;
 210
 12846211        return !id.StartsWith("urn:decentraland:off-chain:base-avatars:");
 212    }
 213
 4768214    public bool IsSkin() => data.category == WearableLiterals.Categories.SKIN;
 215
 216    public bool IsSmart()
 217    {
 3663218        if (data?.representations == null)
 0219            return false;
 220
 15664221        for (var i = 0; i < data.representations.Length; i++)
 222        {
 4171223            var representation = data.representations[i];
 13276224            var containsGameJs = representation.contents?.Any(pair => pair.key.EndsWith("game.js")) ?? false;
 4171225            if (containsGameJs)
 2226                return true;
 227        }
 228
 3661229        return false;
 230    }
 231
 232    public string GetName(string langCode = "en")
 233    {
 4581234        if (!cachedI18n.ContainsKey(langCode))
 235        {
 2760236            cachedI18n.Add(langCode, i18n.FirstOrDefault(x => x.code == langCode)?.text);
 237        }
 238
 4581239        return cachedI18n[langCode];
 240    }
 241
 242    public int GetIssuedCountFromRarity(string rarity)
 243    {
 244        switch (rarity)
 245        {
 246            case WearableLiterals.ItemRarity.RARE:
 4247                return 5000;
 248            case WearableLiterals.ItemRarity.EPIC:
 31249                return 1000;
 250            case WearableLiterals.ItemRarity.LEGENDARY:
 4251                return 100;
 252            case WearableLiterals.ItemRarity.MYTHIC:
 2253                return 10;
 254            case WearableLiterals.ItemRarity.UNIQUE:
 2255                return 1;
 256        }
 257
 3612258        return int.MaxValue;
 259    }
 260
 4663261    public string ComposeThumbnailUrl() { return baseUrl + thumbnail; }
 262
 263    public static HashSet<string> ComposeHiddenCategories(string bodyShapeId, List<WearableItem> wearables)
 264    {
 2265        HashSet<string> result = new HashSet<string>();
 266        //Last wearable added has priority over the rest
 22267        for (int index = 0; index < wearables.Count; index++)
 268        {
 9269            WearableItem wearableItem = wearables[index];
 9270            if (result.Contains(wearableItem.data.category)) //Skip hidden elements to avoid two elements hiding each ot
 271                continue;
 272
 9273            string[] wearableHidesList = wearableItem.GetHidesList(bodyShapeId);
 9274            if (wearableHidesList != null)
 275            {
 0276                result.UnionWith(wearableHidesList);
 277            }
 278        }
 279
 2280        return result;
 281    }
 282
 283    //Workaround to know the net of a wearable.
 284    //Once wearables are allowed to be moved from Ethereum to Polygon this method wont be reliable anymore
 285    //To retrieve this properly first we need the catalyst to send the net of each wearable, not just the ID
 286    public bool IsInL2()
 287    {
 4578288        if (id.StartsWith("urn:decentraland:matic") || id.StartsWith("urn:decentraland:mumbai"))
 0289            return true;
 4578290        return false;
 291    }
 292
 8942293    public bool IsEmote() { return emoteDataV0 != null; }
 294
 2295    public virtual bool ShowInBackpack() { return true; }
 296
 0297    public override string ToString() { return id; }
 298}
 299
 300[Serializable]
 301public class EmoteItem : WearableItem { }
 302
 303[Serializable]
 304public class WearablesRequestResponse
 305{
 306    public WearableItem[] wearables;
 307    public string context;
 308}
 309
 310[Serializable]
 311public class WearablesRequestFailed
 312{
 313    public string error;
 314    public string context;
 315}
 316
 317[Serializable]
 318public class WearableContent
 319{
 320    public string file;
 321    public string hash;
 322}
 323
 324[Serializable]
 325public class i18n
 326{
 327    public string code;
 328    public string text;
 329}