< 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:68
Uncovered lines:23
Coverable lines:91
Total lines:207
Line coverage:74.7% (68 of 91)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
AvatarModifierAreaComponentHandler(...)0%110100%
OnComponentCreated(...)0%2100%
OnComponentRemoved(...)0%3.013091.67%
OnComponentModelUpdated(...)0%110100%
Update()0%40.949026.67%
AreSetEquals(...)0%10.45040%
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
 038        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)
 046                toRemove.UnionWith(currentInArea);
 47
 48            // Remove the modifiers on all avatars
 549            RemoveAllModifiers(toRemove);
 550            if(avatarsInArea != null)
 451                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.LateUpdate, Update);
 559        }
 60
 61        public void OnComponentModelUpdated(IParcelScene scene, IDCLEntity entity, PBAvatarModifierArea model)
 62        {
 63            // Clean up
 264            RemoveAllModifiers();
 265            OnAvatarEnter = null;
 266            OnAvatarExit = null;
 67
 268            this.entity = entity;
 269            ApplyCurrentModel(model);
 270        }
 71
 72        private void Update()
 73        {
 274            if (model == null)
 075                return;
 76
 77            // Find avatars currently on the area
 278            HashSet<GameObject> newAvatarsInArea = DetectAllAvatarsInArea();
 279            if (AreSetEquals(avatarsInArea, newAvatarsInArea))
 280                return;
 81
 82            // Call event for avatars that just entered the area
 083            foreach (GameObject avatarThatEntered in newAvatarsInArea.Except(avatarsInArea))
 84            {
 085                OnAvatarEnter?.Invoke(avatarThatEntered);
 86            }
 87
 88            // Call events for avatars that just exited the area
 089            foreach (GameObject avatarThatExited in avatarsInArea.Except(newAvatarsInArea))
 90            {
 091                OnAvatarExit?.Invoke(avatarThatExited);
 92            }
 93
 094            avatarsInArea = newAvatarsInArea;
 095        }
 96
 97        private bool AreSetEquals(HashSet<GameObject> set1, HashSet<GameObject> set2)
 98        {
 299            if (set1 == null && set2 == null)
 2100                return true;
 101
 0102            if (set1 == null || set2 == null)
 0103                return false;
 104
 0105            return set1.SetEquals(set2);
 106        }
 107
 108        private HashSet<GameObject> DetectAllAvatarsInArea()
 109        {
 9110            if (entity?.gameObject == null)
 4111                return null;
 112
 5113            UnityEngine.Vector3 center = entity.gameObject.transform.position;
 5114            Quaternion rotation = entity.gameObject.transform.rotation;
 5115            return ECSAvatarUtils.DetectAvatars(boxArea, center, rotation, excludedColliders);
 116        }
 117
 118        private void RemoveAllModifiers()
 119        {
 2120            RemoveAllModifiers(DetectAllAvatarsInArea());
 2121            avatarsInArea = null;
 2122        }
 123
 124        private void RemoveAllModifiers(HashSet<GameObject> avatars)
 125        {
 7126            if (avatars == null)
 3127                return;
 128
 10129            foreach (GameObject avatar in avatars)
 130            {
 1131                OnAvatarExit?.Invoke(avatar);
 132            }
 4133        }
 134
 135        private void ApplyCurrentModel(PBAvatarModifierArea model)
 136        {
 2137            dataStore.ownPlayer.OnChange -= OwnPlayerOnOnChange;
 2138            dataStore.otherPlayers.OnAdded -= OtherPlayersOnOnAdded;
 139
 2140            if (model.Modifiers.Count > 0)
 141            {
 142                // We set the unity engine Vector3 here, so we don't allocate a Vector3 each time we use it
 2143                boxArea = ProtoConvertUtils.PBVectorToUnityVector(model.Area);
 144
 145                // Add all listeners
 8146                foreach (AvatarModifier modifierKey in model.Modifiers)
 147                {
 2148                    var modifier = factory.GetOrCreateAvatarModifier(modifierKey);
 149
 2150                    OnAvatarEnter += modifier.ApplyModifier;
 2151                    OnAvatarExit += modifier.RemoveModifier;
 152                }
 153
 154                // Set excluded colliders
 2155                excludedColliders = GetExcludedColliders(model);
 156
 2157                if (model.ExcludeIds.Count > 0)
 158                {
 2159                    dataStore.ownPlayer.OnChange += OwnPlayerOnOnChange;
 2160                    dataStore.otherPlayers.OnAdded += OtherPlayersOnOnAdded;
 161                }
 162
 2163                this.model = model;
 164
 165                // Force update due to after model update modifiers are removed and re-added
 166                // leaving a frame with the avatar without the proper modifications
 2167                Update();
 168            }
 2169        }
 170
 171        internal HashSet<Collider> GetExcludedColliders(PBAvatarModifierArea model)
 172        {
 3173            if (model.ExcludeIds.Count == 0)
 0174                return null;
 175
 3176            var ownPlayer = dataStore.ownPlayer.Get();
 3177            var otherPlayers = dataStore.otherPlayers;
 178
 3179            HashSet<Collider> result = new HashSet<Collider>();
 14180            for (int i = 0; i < model.ExcludeIds.Count; i++)
 181            {
 4182                if (ownPlayer != null && model.ExcludeIds[i] == ownPlayer.id)
 0183                    result.Add(ownPlayer.collider);
 4184                else if (otherPlayers.TryGetValue(model.ExcludeIds[i], out Player player))
 1185                    result.Add(player.collider);
 186            }
 3187            return result;
 188        }
 189
 0190        private void OtherPlayersOnOnAdded(string id, Player player) { RefreshExclusionList(player); }
 191
 0192        private void OwnPlayerOnOnChange(Player current, Player previous) { RefreshExclusionList(current); }
 193
 0194        private void OnOtherPlayersRemoved(string id, Player player) { excludedColliders?.Remove(player.collider); }
 195
 196        private void RefreshExclusionList(Player player)
 197        {
 0198            if (model.ExcludeIds.Count == 0 || !model.ExcludeIds.Contains(player.id))
 0199                return;
 200
 0201            if (excludedColliders == null)
 0202                excludedColliders = new HashSet<Collider>();
 203
 0204            excludedColliders.Add(player.collider);
 0205        }
 206    }
 207}