< Summary

Class:DCL.Emotes.EmoteAnimationsTracker
Assembly:EmoteAnimationsPlugin
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/DCLPlugins/EmoteAnimations/EmoteAnimationsTracker.cs
Covered lines:49
Uncovered lines:12
Coverable lines:61
Total lines:139
Line coverage:80.3% (49 of 61)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
EmoteAnimationsTracker(...)0%110100%
InitializeEmbeddedEmotes()0%440100%
OnRefCountUpdated(...)0%220100%
InitializeEmotes(...)0%330100%
LoadEmote()0%10.427058.82%
UnloadEmote(...)0%3.043083.33%
Dispose()0%6200%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/DCLPlugins/EmoteAnimations/EmoteAnimationsTracker.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using System.Runtime.ExceptionServices;
 5using System.Threading;
 6using AvatarSystem;
 7using Cysharp.Threading.Tasks;
 8using DCL.Configuration;
 9using UnityEngine;
 10using Object = UnityEngine.Object;
 11
 12namespace DCL.Emotes
 13{
 14    public class EmoteAnimationsTracker : IDisposable
 15    {
 16        internal readonly DataStore_Emotes dataStore;
 17        internal readonly EmoteAnimationLoaderFactory emoteAnimationLoaderFactory;
 18        internal readonly IWearableItemResolver wearableItemResolver;
 19
 420        internal Dictionary<(string bodyshapeId, string emoteId), IEmoteAnimationLoader> loaders = new Dictionary<(strin
 21
 422        private CancellationTokenSource cts = new CancellationTokenSource();
 23
 24        internal GameObject animationsModelsContainer;
 25
 426        public EmoteAnimationsTracker(DataStore_Emotes dataStore, EmoteAnimationLoaderFactory emoteAnimationLoaderFactor
 27        {
 428            animationsModelsContainer = new GameObject("_EmoteAnimationsHolder");
 429            animationsModelsContainer.transform.position = EnvironmentSettings.MORDOR;
 430            this.dataStore = dataStore;
 431            this.emoteAnimationLoaderFactory = emoteAnimationLoaderFactory;
 432            this.wearableItemResolver = wearableItemResolver;
 433            this.dataStore.animations.Clear();
 34
 435            InitializeEmbeddedEmotes();
 436            InitializeEmotes(this.dataStore.emotesOnUse.GetAllRefCounts());
 37
 438            this.dataStore.emotesOnUse.OnRefCountUpdated += OnRefCountUpdated;
 439        }
 40
 41        private void InitializeEmbeddedEmotes()
 42        {
 43            //To avoid circular references in assemblies we hardcode this here instead of using WearableLiterals
 44            //Embedded Emotes are only temporary until they can be retrieved from the content server
 45            const string FEMALE = "urn:decentraland:off-chain:base-avatars:BaseFemale";
 46            const string MALE = "urn:decentraland:off-chain:base-avatars:BaseMale";
 47
 448            EmbeddedEmotesSO embeddedEmotes = Resources.Load<EmbeddedEmotesSO>("EmbeddedEmotes");
 49
 16050            foreach (EmbeddedEmote embeddedEmote in embeddedEmotes.emotes)
 51            {
 7652                if (embeddedEmote.maleAnimation != null)
 53                {
 54                    //We match the animation id with its name due to performance reasons
 55                    //Unity's Animation uses the name to play the clips.
 7656                    embeddedEmote.maleAnimation.name = embeddedEmote.id;
 7657                    dataStore.emotesOnUse.SetRefCount((MALE,  embeddedEmote.id), 5000);
 7658                    dataStore.animations.Add((MALE, embeddedEmote.id), embeddedEmote.maleAnimation);
 7659                    loaders.Add((MALE, embeddedEmote.id), emoteAnimationLoaderFactory.Get());
 60                }
 61
 7662                if (embeddedEmote.femaleAnimation != null)
 63                {
 64                    //We match the animation id with its name due to performance reasons
 65                    //Unity's Animation uses the name to play the clips.
 7666                    embeddedEmote.femaleAnimation.name = embeddedEmote.id;
 7667                    dataStore.emotesOnUse.SetRefCount((FEMALE,  embeddedEmote.id), 5000);
 7668                    dataStore.animations.Add((FEMALE, embeddedEmote.id), embeddedEmote.femaleAnimation);
 7669                    loaders.Add((FEMALE, embeddedEmote.id), emoteAnimationLoaderFactory.Get());
 70                }
 71            }
 472            CatalogController.i.EmbedWearables(embeddedEmotes.emotes);
 473        }
 74
 75        private void OnRefCountUpdated((string bodyshapeId, string emoteId) value, int refCount)
 76        {
 377            if (refCount > 0)
 278                LoadEmote(value.bodyshapeId, value.emoteId, cts.Token);
 79            else
 180                UnloadEmote(value.bodyshapeId, value.emoteId);
 181        }
 82
 83        private void InitializeEmotes(IEnumerable<KeyValuePair<(string bodyshapeId, string emoteId), int>> refCounts)
 84        {
 31285            foreach (KeyValuePair<(string bodyshapeId, string emoteId), int> keyValuePair in refCounts)
 86            {
 15287                LoadEmote(keyValuePair.Key.bodyshapeId, keyValuePair.Key.emoteId, cts.Token);
 88            }
 489        }
 90
 91        private async UniTaskVoid LoadEmote(string bodyShapeId, string emoteId, CancellationToken ct)
 92        {
 15493            ct.ThrowIfCancellationRequested();
 94
 15495            if (loaders.ContainsKey((bodyShapeId, emoteId)))
 15396                return;
 97
 98            try
 99            {
 1100                WearableItem emote = await wearableItemResolver.Resolve(emoteId, ct);
 101
 1102                IEmoteAnimationLoader animationLoader = emoteAnimationLoaderFactory.Get();
 1103                loaders.Add((bodyShapeId, emoteId), animationLoader);
 1104                await animationLoader.LoadEmote(animationsModelsContainer, emote, bodyShapeId, ct);
 105
 1106                dataStore.animations.Add((bodyShapeId, emoteId), animationLoader.animation);
 1107            }
 108            catch (Exception e)
 109            {
 0110                loaders.Remove((bodyShapeId, emoteId));
 0111                ExceptionDispatchInfo.Capture(e).Throw();
 0112                throw;
 113            }
 154114        }
 115
 116        private void UnloadEmote(string bodyShapeId, string emoteId)
 117        {
 1118            if (!loaders.TryGetValue((bodyShapeId, emoteId), out IEmoteAnimationLoader loader))
 0119                return;
 120
 1121            dataStore.animations.Remove((bodyShapeId, emoteId));
 1122            loaders.Remove((bodyShapeId, emoteId));
 1123            loader?.Dispose();
 1124        }
 125
 126        public void Dispose()
 127        {
 0128            dataStore.emotesOnUse.OnRefCountUpdated -= OnRefCountUpdated;
 0129            (string bodyshapeId, string emoteId)[] keys = loaders.Keys.ToArray();
 0130            foreach ((string bodyshapeId, string emoteId) in keys)
 131            {
 0132                UnloadEmote(bodyshapeId, emoteId);
 133            }
 0134            loaders.Clear();
 0135            cts.Cancel();
 0136            Object.Destroy(animationsModelsContainer);
 0137        }
 138    }
 139}