< Summary

Class:DCL.ECSComponents.AvatarModifierAreaComponentHandler
Assembly:DCL.ECSComponents.AvatarModifierArea
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/DCLPlugins/ECS7/ECSComponents/AvatarModifierArea/Handler/AvatarModifierAreaComponentHandler.cs
Covered lines:72
Uncovered lines:21
Coverable lines:93
Total lines:210
Line coverage:77.4% (72 of 93)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
AvatarModifierAreaComponentHandler(...)0%110100%
OnComponentCreated(...)0%110100%
OnComponentRemoved(...)0%330100%
OnComponentModelUpdated(...)0%2.012087.5%
Update()0%40.949026.67%
AreSetEquals(...)0%6.65060%
DetectAllAvatarsInArea()0%440100%
RemoveAllModifiers()0%110100%
RemoveAllModifiers(...)0%440100%
ApplyCurrentModel(...)0%550100%
GetExcludedColliders(...)0%6.136084.62%
OtherPlayersOnOnAdded(...)0%2100%
OwnPlayerOnOnChange(...)0%2100%
OnOtherPlayersRemoved(...)0%6200%
RefreshExclusionList(...)0%20400%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/DCLPlugins/ECS7/ECSComponents/AvatarModifierArea/Handler/AvatarModifierAreaComponentHandler.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using DCL.Controllers;
 5using DCL.ECSComponents.Utils;
 6using DCL.ECSRuntime;
 7using DCL.Models;
 8using UnityEngine;
 9
 10namespace DCL.ECSComponents
 11{
 12    public class AvatarModifierAreaComponentHandler : IECSComponentHandler<PBAvatarModifierArea>
 13    {
 14        private event Action<GameObject> OnAvatarEnter;
 15        private event Action<GameObject> OnAvatarExit;
 16
 417        internal HashSet<GameObject> avatarsInArea = new HashSet<GameObject>();
 18        internal HashSet<Collider> excludedColliders;
 19
 20        internal PBAvatarModifierArea model;
 21        private IDCLEntity entity;
 22        private UnityEngine.Vector3 boxArea;
 23
 24        private readonly AvatarModifierFactory factory;
 25        private readonly IUpdateEventHandler updateEventHandler;
 26        private readonly DataStore_Player dataStore;
 27
 428        public AvatarModifierAreaComponentHandler(IUpdateEventHandler updateEventHandler,DataStore_Player dataStore, Ava
 29        {
 430            this.factory = factory;
 431            this.dataStore = dataStore;
 432            this.updateEventHandler = updateEventHandler;
 33
 434            updateEventHandler.AddListener(IUpdateEventHandler.EventType.Update, Update);
 435            dataStore.otherPlayers.OnRemoved += OnOtherPlayersRemoved;
 436        }
 37
 438        public void OnComponentCreated(IParcelScene scene, IDCLEntity entity) { }
 39
 40        public void OnComponentRemoved(IParcelScene scene, IDCLEntity entity)
 41        {
 42            // We detect current affected avatars
 543            var toRemove = avatarsInArea;
 544            var currentInArea = DetectAllAvatarsInArea();
 545            if (currentInArea != null)
 346                toRemove.UnionWith(currentInArea);
 47
 48            // Remove the modifiers on all avatars
 549            RemoveAllModifiers(toRemove);
 550            if(avatarsInArea != null)
 551                avatarsInArea.Clear();
 52
 53            // We unsubscribe from events
 554            dataStore.ownPlayer.OnChange -= OwnPlayerOnOnChange;
 555            dataStore.otherPlayers.OnAdded -= OtherPlayersOnOnAdded;
 556            dataStore.otherPlayers.OnRemoved -= OnOtherPlayersRemoved;
 57
 558            updateEventHandler.RemoveListener(IUpdateEventHandler.EventType.Update, Update);
 559        }
 60
 61        public void OnComponentModelUpdated(IParcelScene scene, IDCLEntity entity, PBAvatarModifierArea model)
 62        {
 263            if (model.Equals(this.model))
 064                return;
 65
 66            // Clean up
 267            RemoveAllModifiers();
 268            OnAvatarEnter = null;
 269            OnAvatarExit = null;
 70
 271            this.entity = entity;
 272            ApplyCurrentModel(model);
 273        }
 74
 75        private void Update()
 76        {
 277            if (model == null)
 078                return;
 79
 80            // Find avatars currently on the area
 281            HashSet<GameObject> newAvatarsInArea = DetectAllAvatarsInArea();
 282            if (AreSetEquals(avatarsInArea, newAvatarsInArea))
 283                return;
 84
 85            // Call event for avatars that just entered the area
 086            foreach (GameObject avatarThatEntered in newAvatarsInArea.Except(avatarsInArea))
 87            {
 088                OnAvatarEnter?.Invoke(avatarThatEntered);
 89            }
 90
 91            // Call events for avatars that just exited the area
 092            foreach (GameObject avatarThatExited in avatarsInArea.Except(newAvatarsInArea))
 93            {
 094                OnAvatarExit?.Invoke(avatarThatExited);
 95            }
 96
 097            avatarsInArea = newAvatarsInArea;
 098        }
 99
 100        private bool AreSetEquals(HashSet<GameObject> set1, HashSet<GameObject> set2)
 101        {
 2102            if (set1 == null && set2 == null)
 0103                return true;
 104
 2105            if (set1 == null || set2 == null)
 0106                return false;
 107
 2108            return set1.SetEquals(set2);
 109        }
 110
 111        private HashSet<GameObject> DetectAllAvatarsInArea()
 112        {
 9113            if (entity?.gameObject == null)
 4114                return null;
 115
 5116            UnityEngine.Vector3 center = entity.gameObject.transform.position;
 5117            Quaternion rotation = entity.gameObject.transform.rotation;
 5118            return ECSAvatarUtils.DetectAvatars(boxArea, center, rotation, excludedColliders);
 119        }
 120
 121        private void RemoveAllModifiers()
 122        {
 2123            RemoveAllModifiers(DetectAllAvatarsInArea());
 2124            avatarsInArea.Clear();
 2125        }
 126
 127        private void RemoveAllModifiers(HashSet<GameObject> avatars)
 128        {
 7129            if (avatars == null)
 2130                return;
 131
 12132            foreach (GameObject avatar in avatars)
 133            {
 1134                OnAvatarExit?.Invoke(avatar);
 135            }
 5136        }
 137
 138        private void ApplyCurrentModel(PBAvatarModifierArea model)
 139        {
 2140            dataStore.ownPlayer.OnChange -= OwnPlayerOnOnChange;
 2141            dataStore.otherPlayers.OnAdded -= OtherPlayersOnOnAdded;
 142
 2143            if (model.Modifiers.Count > 0)
 144            {
 145                // We set the unity engine Vector3 here, so we don't allocate a Vector3 each time we use it
 2146                boxArea = ProtoConvertUtils.PBVectorToUnityVector(model.Area);
 147
 148                // Add all listeners
 8149                foreach (AvatarModifierType modifierKey in model.Modifiers)
 150                {
 2151                    var modifier = factory.GetOrCreateAvatarModifier(modifierKey);
 152
 2153                    OnAvatarEnter += modifier.ApplyModifier;
 2154                    OnAvatarExit += modifier.RemoveModifier;
 155                }
 156
 157                // Set excluded colliders
 2158                excludedColliders = GetExcludedColliders(model);
 159
 2160                if (model.ExcludeIds.Count > 0)
 161                {
 2162                    dataStore.ownPlayer.OnChange += OwnPlayerOnOnChange;
 2163                    dataStore.otherPlayers.OnAdded += OtherPlayersOnOnAdded;
 164                }
 165
 2166                this.model = model;
 167
 168                // Force update due to after model update modifiers are removed and re-added
 169                // leaving a frame with the avatar without the proper modifications
 2170                Update();
 171            }
 2172        }
 173
 174        internal HashSet<Collider> GetExcludedColliders(PBAvatarModifierArea model)
 175        {
 3176            if (model.ExcludeIds.Count == 0)
 0177                return null;
 178
 3179            var ownPlayer = dataStore.ownPlayer.Get();
 3180            var otherPlayers = dataStore.otherPlayers;
 181
 3182            HashSet<Collider> result = new HashSet<Collider>();
 14183            for (int i = 0; i < model.ExcludeIds.Count; i++)
 184            {
 4185                if (ownPlayer != null && model.ExcludeIds[i] == ownPlayer.id)
 0186                    result.Add(ownPlayer.collider);
 4187                else if (otherPlayers.TryGetValue(model.ExcludeIds[i], out Player player))
 1188                    result.Add(player.collider);
 189            }
 3190            return result;
 191        }
 192
 0193        private void OtherPlayersOnOnAdded(string id, Player player) { RefreshExclusionList(player); }
 194
 0195        private void OwnPlayerOnOnChange(Player current, Player previous) { RefreshExclusionList(current); }
 196
 0197        private void OnOtherPlayersRemoved(string id, Player player) { excludedColliders?.Remove(player.collider); }
 198
 199        private void RefreshExclusionList(Player player)
 200        {
 0201            if (model.ExcludeIds.Count == 0 || !model.ExcludeIds.Contains(player.id))
 0202                return;
 203
 0204            if (excludedColliders == null)
 0205                excludedColliders = new HashSet<Collider>();
 206
 0207            excludedColliders.Add(player.collider);
 0208        }
 209    }
 210}