< Summary

Class:UserProfile
Assembly:UserProfile
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/UserProfile/UserProfile.cs
Covered lines:76
Uncovered lines:32
Coverable lines:108
Total lines:223
Line coverage:70.3% (76 of 108)
Covered branches:0
Total branches:0
Covered methods:25
Total methods:39
Method coverage:64.1% (25 of 39)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
UserProfile()0%110100%
ModelFallback()0%2100%
AvatarFallback()0%110100%
UpdateData(...)0%12.4612085.29%
GetItemAmount(...)0%3.333066.67%
OverrideAvatar(...)0%220100%
SetAvatarExpression(...)0%770100%
SetInventory(...)0%440100%
AddToInventory(...)0%6200%
RemoveFromInventory(...)0%2100%
ContainsInInventory(...)0%2100%
GetInventoryItemsIds()0%2100%
GetOwnUserProfile()0%220100%
CloneModel()0%2100%
IsBlocked(...)0%220100%
Block(...)0%3.583060%
Unblock(...)0%12300%
HasEquipped(...)0%2100%
OnEnable()0%110100%
CleanUp()0%6200%

File(s)

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

#LineLine coverage
 1using DCL;
 2using DCL.Helpers;
 3using DCL.UserProfiles;
 4using Decentraland.Renderer.KernelServices;
 5using System;
 6using System.Collections.Generic;
 7using System.Linq;
 8using UnityEditor;
 9using UnityEngine;
 10using Environment = DCL.Environment;
 11
 12[CreateAssetMenu(fileName = "UserProfile", menuName = "UserProfile")]
 13public class UserProfile : ScriptableObject //TODO Move to base variable
 14{
 15    public enum EmoteSource
 16    {
 17        EmotesWheel,
 18        Shortcut,
 19        Command,
 20        Backpack,
 21        EmoteLoop,
 22        EmoteCancel,
 23    }
 24
 25    private const string FALLBACK_NAME = "fallback";
 26
 27    public event Action<UserProfile> OnUpdate;
 28    public event Action<string, long, EmoteSource> OnAvatarEmoteSet;
 29
 101630    public string userId => model.userId;
 24031    public string ethAddress => model.ethAddress;
 30432    public string userName => model.name;
 6433    public string description => model.description;
 034    public string email => model.email;
 035    public string bodySnapshotURL => model.ComposeCorrectUrl(model.snapshots.body);
 13036    public string face256SnapshotURL => model.ComposeCorrectUrl(model.snapshots.face256);
 037    public string baseUrl => model.baseUrl;
 038    public UserProfileModel.ParcelsWithAccess[] parcelsWithAccess => model.parcelsWithAccess;
 16539    public List<string> blocked => model.blocked ?? new List<string>();
 140    public List<string> muted => model.muted ?? new List<string>();
 4641    public bool hasConnectedWeb3 => model.hasConnectedWeb3;
 8542    public bool hasClaimedName => model.hasClaimedName;
 17043    public bool isGuest => !model.hasConnectedWeb3;
 17444    public AvatarModel avatar => model.avatar;
 045    public int tutorialStep => model.tutorialStep;
 7346    public List<UserProfileModel.Link> Links => model.links;
 6247    public AdditionalInfo AdditionalInfo => model.AdditionalInfo;
 48
 75949    internal Dictionary<string, int> inventory = new ();
 50
 75951    public ILazyTextureObserver snapshotObserver = new LazyTextureObserver();
 75952    public ILazyTextureObserver bodySnapshotObserver = new LazyTextureObserver();
 53
 54    internal static UserProfile ownUserProfile;
 55
 56    // Empty initialization to avoid null-checks
 75957    internal UserProfileModel model = new () { avatar = new AvatarModel() };
 58
 59    private UserProfileModel ModelFallback() =>
 060        UserProfileModel.FallbackModel(FALLBACK_NAME, this.GetInstanceID());
 61
 62    private AvatarModel AvatarFallback() =>
 58763        AvatarModel.FallbackModel(FALLBACK_NAME, this.GetInstanceID());
 64
 75965    private int emoteLamportTimestamp = 1;
 166    private ClientEmotesKernelService emotes => Environment.i.serviceLocator.Get<IRPC>().Emotes();
 67
 68    public void UpdateData(UserProfileModel newModel)
 69    {
 72070        if (newModel == null)
 71        {
 072            if (!Application.isBatchMode)
 073                Debug.LogError("Model is null when updating UserProfile! Using fallback or previous model instead.");
 74
 75            // Check if there is a previous model to fallback to. Because default model has everything empty or null.
 076            newModel = string.IsNullOrEmpty(model.userId) ? ModelFallback() : model;
 77        }
 78
 72079        if (newModel.avatar == null)
 80        {
 66281            model.avatar = new AvatarModel();
 82
 66283            if (!Application.isBatchMode)
 084                Debug.LogError("Avatar is null when updating UserProfile! Using fallback or previous avatar instead.");
 85
 86            // Check if there is a previous avatar to fallback to.
 66287            newModel.avatar = string.IsNullOrEmpty(model.userId) ? AvatarFallback() : model.avatar;
 88        }
 89
 72090        bool faceSnapshotDirty = model.snapshots.face256 != newModel.snapshots.face256;
 72091        bool bodySnapshotDirty = model.snapshots.body != newModel.snapshots.body;
 92
 72093        model.userId = newModel.userId;
 72094        model.ethAddress = newModel.ethAddress;
 72095        model.parcelsWithAccess = newModel.parcelsWithAccess;
 72096        model.tutorialStep = newModel.tutorialStep;
 72097        model.hasClaimedName = newModel.hasClaimedName;
 72098        model.name = newModel.name;
 72099        model.email = newModel.email;
 720100        model.description = newModel.description;
 720101        model.baseUrl = newModel.baseUrl;
 720102        model.avatar.CopyFrom(newModel.avatar);
 720103        model.snapshots = newModel.snapshots;
 720104        model.hasConnectedWeb3 = newModel.hasConnectedWeb3;
 720105        model.blocked = newModel.blocked;
 720106        model.muted = newModel.muted;
 720107        model.version = newModel.version;
 720108        model.links = newModel.links;
 720109        model.AdditionalInfo.CopyFrom(newModel.AdditionalInfo);
 110
 720111        if (faceSnapshotDirty)
 52112            snapshotObserver.RefreshWithUri(face256SnapshotURL);
 113
 720114        if (bodySnapshotDirty)
 0115            bodySnapshotObserver.RefreshWithUri(bodySnapshotURL);
 116
 720117        OnUpdate?.Invoke(this);
 25118    }
 119
 120    public int GetItemAmount(string itemId)
 121    {
 2122        if (inventory == null || !inventory.ContainsKey(itemId))
 0123            return 0;
 124
 2125        return inventory[itemId];
 126    }
 127
 128    public void OverrideAvatar(AvatarModel newModel, Texture2D newFaceSnapshot)
 129    {
 6130        model.avatar.CopyFrom(newModel);
 6131        this.snapshotObserver.RefreshWithTexture(newFaceSnapshot);
 132
 6133        OnUpdate?.Invoke(this);
 6134    }
 135
 136    public void SetAvatarExpression(string id, EmoteSource source, bool rpcOnly = false)
 137    {
 1138        int timestamp = emoteLamportTimestamp++;
 1139        avatar.expressionTriggerId = id;
 1140        avatar.expressionTriggerTimestamp = timestamp;
 141
 142        // TODO: fix message `Timestamp` should NOT be `float`, we should use `int lamportTimestamp` or `long timeStamp`
 1143        emotes?.TriggerExpression(new TriggerExpressionRequest()
 144        {
 145            Id = id,
 146            Timestamp = rpcOnly ? -1 : timestamp
 147        });
 148
 1149        if (!rpcOnly)
 150        {
 1151            OnUpdate?.Invoke(this);
 1152            OnAvatarEmoteSet?.Invoke(id, timestamp, source);
 153        }
 1154    }
 155
 156    public void SetInventory(IEnumerable<string> inventoryIds)
 157    {
 173158        inventory.Clear();
 3240159        inventory = inventoryIds.GroupBy(x => x).ToDictionary(x => x.Key, x => x.Count());
 173160    }
 161
 162    public void AddToInventory(string wearableId)
 163    {
 0164        if (inventory.ContainsKey(wearableId))
 0165            inventory[wearableId]++;
 166        else
 0167            inventory.Add(wearableId, 1);
 0168    }
 169
 0170    public void RemoveFromInventory(string wearableId) { inventory.Remove(wearableId); }
 171
 0172    public bool ContainsInInventory(string wearableId) => inventory.ContainsKey(wearableId);
 173
 174    public string[] GetInventoryItemsIds() =>
 0175        inventory.Keys.ToArray();
 176
 177    // TODO: Remove this call. The own user profile should be accessed via IUserProfileBridge.GetOwn()
 178    public static UserProfile GetOwnUserProfile()
 179    {
 3332180        if (ownUserProfile == null)
 18181            ownUserProfile = Resources.Load<UserProfile>("ScriptableObjects/OwnUserProfile");
 182
 3332183        return ownUserProfile;
 184    }
 185
 0186    public UserProfileModel CloneModel() => model.Clone();
 187
 188    public bool IsBlocked(string userId) =>
 65189        blocked != null && blocked.Contains(userId);
 190
 191    public void Block(string userId)
 192    {
 19193        if (IsBlocked(userId))
 0194            return;
 19195        blocked.Add(userId);
 19196        OnUpdate?.Invoke(this);
 0197    }
 198
 199    public void Unblock(string userId)
 200    {
 0201        if (!IsBlocked(userId))
 0202            return;
 0203        blocked.Remove(userId);
 0204        OnUpdate?.Invoke(this);
 0205    }
 206
 0207    public bool HasEquipped(string wearableId) => avatar.wearables.Contains(wearableId);
 208
 209#if UNITY_EDITOR
 210    private void OnEnable()
 211    {
 759212        Application.quitting -= CleanUp;
 759213        Application.quitting += CleanUp;
 759214    }
 215
 216    private void CleanUp()
 217    {
 0218        Application.quitting -= CleanUp;
 0219        if (AssetDatabase.Contains(this))
 0220            Resources.UnloadAsset(this);
 0221    }
 222#endif
 223}