< Summary

Class:AvatarSystem.AvatarEmotesController
Assembly:AvatarSystem
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/AvatarEmotesController.cs
Covered lines:16
Uncovered lines:53
Coverable lines:69
Total lines:149
Line coverage:23.1% (16 of 69)
Covered branches:0
Total branches:0
Covered methods:3
Total methods:14
Method coverage:21.4% (3 of 14)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
AvatarEmotesController(...)0%110100%
TryGetEquippedEmote(...)0%2100%
AddVisibilityConstraint(...)0%6200%
RemoveVisibilityConstraint(...)0%2100%
Prepare(...)0%2100%
LoadEmotes(...)0%12300%
LoadEmote(...)0%6200%
AsyncEmoteLoad()0%42600%
PlayEmote(...)0%8.056061.54%
CanPlayEmote()0%110100%
StopEmote(...)0%2100%
EquipEmote(...)0%20400%
UnEquipEmote(...)0%6200%
Dispose()0%6200%

File(s)

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

#LineLine coverage
 1using Cysharp.Threading.Tasks;
 2using DCL.Emotes;
 3using DCL.Tasks;
 4using System;
 5using System.Collections.Generic;
 6using System.Threading;
 7using UnityEngine;
 8
 9namespace AvatarSystem
 10{
 11    public class AvatarEmotesController : IAvatarEmotesController
 12    {
 13        private const string IN_HIDE_AREA = "IN_HIDE_AREA";
 14
 15        public event Action<string, IEmoteReference> OnEmoteEquipped;
 16        public event Action<string> OnEmoteUnequipped;
 17
 51818        private string bodyShapeId = "";
 19        private readonly IAnimator animator;
 20        private readonly IEmotesService emotesService;
 51821        private readonly Dictionary<EmoteBodyId, IEmoteReference> equippedEmotes = new ();
 51822        private readonly CancellationTokenSource cts = new ();
 23        private readonly HashSet<string> visibilityConstraints;
 24
 51825        public AvatarEmotesController(IAnimator animator, IEmotesService emotesService)
 26        {
 51827            this.animator = animator;
 51828            this.emotesService = emotesService;
 51829            visibilityConstraints = new HashSet<string>();
 51830        }
 31
 32        public bool TryGetEquippedEmote(string bodyShape, string emoteId, out IEmoteReference emoteReference) =>
 033            equippedEmotes.TryGetValue(new EmoteBodyId(bodyShape, emoteId), out emoteReference);
 34
 35        public void AddVisibilityConstraint(string key)
 36        {
 037            visibilityConstraints.Add(key);
 38
 039            if (!CanPlayEmote())
 040                StopEmote(true);
 041        }
 42
 43        public void RemoveVisibilityConstraint(string key)
 44        {
 045            visibilityConstraints.Remove(key);
 046        }
 47
 48        public void Prepare(string bodyShapeId, GameObject container)
 49        {
 050            this.bodyShapeId = bodyShapeId;
 051            animator.Prepare(bodyShapeId, container);
 052        }
 53
 54        // ReSharper disable once PossibleMultipleEnumeration (its intended)
 55        public void LoadEmotes(string bodyShapeId, IEnumerable<WearableItem> newEmotes)
 56        {
 057            foreach (WearableItem emote in newEmotes)
 058                LoadEmote(bodyShapeId, emote);
 059        }
 60
 61        private void LoadEmote(string bodyShapeId, WearableItem emote)
 62        {
 063            var emoteKey = new EmoteBodyId(bodyShapeId, emote.id);
 064            if (equippedEmotes.ContainsKey(emoteKey)) return;
 065            equippedEmotes.Add(emoteKey, null);
 066            AsyncEmoteLoad(bodyShapeId, emote.id).Forget();
 067        }
 68
 69        private async UniTask AsyncEmoteLoad(string bodyShapeId, string emoteId)
 70        {
 071            var emoteKey = new EmoteBodyId(bodyShapeId, emoteId);
 72
 73            try
 74            {
 075                IEmoteReference emoteReference = await emotesService.RequestEmote(emoteKey, cts.Token);
 076                if (emoteReference == null) return;
 077                animator.EquipEmote(emoteId, emoteReference.GetData());
 078                equippedEmotes[emoteKey] = emoteReference;
 079                OnEmoteEquipped?.Invoke(emoteId, emoteReference);
 080            }
 081            catch (OperationCanceledException) { }
 082            catch (Exception e) { Debug.LogException(e); }
 083        }
 84
 85        public void PlayEmote(string emoteId, long timestamps, bool spatial = true, bool occlude = true, bool forcePlay 
 86        {
 187            bool isPlayingEmote = !string.IsNullOrEmpty(animator.GetCurrentEmoteId());
 188            bool emoteIsValid = !string.IsNullOrEmpty(emoteId);
 89
 190            if (isPlayingEmote && !emoteIsValid)
 091                animator.StopEmote(false);
 92
 193            if (!emoteIsValid) return;
 194            if (!CanPlayEmote()) return;
 95
 196            var emoteKey = new EmoteBodyId(bodyShapeId, emoteId);
 297            if (!equippedEmotes.ContainsKey(emoteKey)) return;
 98
 099            animator.PlayEmote(emoteId, timestamps, spatial, occlude, forcePlay);
 0100        }
 101
 102        private bool CanPlayEmote() =>
 1103            !visibilityConstraints.Contains(IN_HIDE_AREA);
 104
 105        public void StopEmote(bool immediate)
 106        {
 0107            animator.StopEmote(immediate);
 0108        }
 109
 110        public void EquipEmote(string emoteId, IEmoteReference emoteReference)
 111        {
 0112            if (emoteReference == null) return;
 0113            var emoteKey = new EmoteBodyId(bodyShapeId, emoteId);
 114
 0115            if (equippedEmotes.ContainsKey(emoteKey))
 116            {
 117                // we avoid dangling references in case an emote was loaded twice
 0118                emoteReference.Dispose();
 0119                return;
 120            }
 121
 0122            equippedEmotes.Add(emoteKey, emoteReference);
 0123            animator.EquipEmote(emoteId, emoteReference.GetData());
 0124            OnEmoteEquipped?.Invoke(emoteId, emoteReference);
 0125        }
 126
 127        public void UnEquipEmote(string emoteId)
 128        {
 0129            var emoteKey = new EmoteBodyId(bodyShapeId, emoteId);
 130
 0131            if (equippedEmotes.ContainsKey(emoteKey))
 132            {
 0133                animator.UnequipEmote(emoteId);
 0134                equippedEmotes[emoteKey].Dispose();
 0135                equippedEmotes.Remove(emoteKey);
 136            }
 0137        }
 138
 139        public void Dispose()
 140        {
 0141            cts.SafeCancelAndDispose();
 142
 0143            foreach (var kvp in equippedEmotes)
 0144                kvp.Value.Dispose();
 145
 0146            equippedEmotes.Clear();
 0147        }
 148    }
 149}