< Summary

Class:AvatarModifierArea
Assembly:AvatarShape
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarModifiers/AvatarModifierArea.cs
Covered lines:87
Uncovered lines:13
Coverable lines:100
Total lines:253
Line coverage:87% (87 of 100)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
GetDataFromJSON(...)0%110100%
AvatarModifierArea()0%110100%
ApplyChanges(...)0%110100%
Awake()0%110100%
OnDestroy()0%3.013090.91%
Update()0%13.213089.47%
AreSetEquals(...)0%5.25080%
DetectAllAvatarsInArea()0%5.25080%
RemoveAllModifiers()0%110100%
RemoveAllModifiers(...)0%770100%
ApplyCurrentModel()0%660100%
GetClassId()0%2100%
GetExcludedColliders(...)0%990100%
OtherPlayersOnOnAdded(...)0%110100%
OwnPlayerOnOnChange(...)0%2100%
OnOtherPlayersRemoved(...)0%6200%
RefreshExclusionList(...)0%8.817066.67%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarModifiers/AvatarModifierArea.cs

#LineLine coverage
 1using System;
 2using System.Collections;
 3using System.Collections.Generic;
 4using System.Linq;
 5using DCL;
 6using DCL.Components;
 7using DCL.Helpers;
 8using DCL.Models;
 9using UnityEngine;
 10
 11public class AvatarModifierArea : BaseComponent
 12{
 13    [Serializable]
 14    public class Model : BaseModel
 15    {
 16        // TODO: Change to TriggerArea and handle deserialization with subclasses
 17        public BoxTriggerArea area;
 18        public string[] modifiers;
 19        public string[] excludeIds;
 20
 21        public override BaseModel GetDataFromJSON(string json)
 22        {
 1623            return Utils.SafeFromJson<Model>(json);
 24        }
 25    }
 26
 727    private Model cachedModel = new Model();
 28
 729    private HashSet<GameObject> avatarsInArea = new HashSet<GameObject>();
 30    private event Action<GameObject> OnAvatarEnter;
 31    private event Action<GameObject> OnAvatarExit;
 32    internal readonly Dictionary<string, AvatarModifier> modifiers;
 33
 34    private HashSet<Collider> excludedColliders;
 35
 736    public AvatarModifierArea()
 37    {
 38        // Configure all available modifiers
 739        this.modifiers = new Dictionary<string, AvatarModifier>()
 40        {
 41            { "HIDE_AVATARS", new HideAvatarsModifier() },
 42            { "DISABLE_PASSPORTS", new DisablePassportModifier() }
 43        };
 744        model = new Model();
 745    }
 46
 47    public override IEnumerator ApplyChanges(BaseModel newModel)
 48    {
 49
 50        // Clean up
 1651        RemoveAllModifiers();
 1652        OnAvatarEnter = null;
 1653        OnAvatarExit = null;
 54
 1655        ApplyCurrentModel();
 56
 1657        return null;
 58    }
 59
 60    private void Awake()
 61    {
 662        DataStore.i.player.otherPlayers.OnRemoved += OnOtherPlayersRemoved;
 663    }
 64
 65    private void OnDestroy()
 66    {
 667        var toRemove = new HashSet<GameObject>();
 668        if (avatarsInArea != null)
 669            toRemove.UnionWith(avatarsInArea);
 70
 671        var currentInArea = DetectAllAvatarsInArea();
 672        if (currentInArea != null)
 073            toRemove.UnionWith(currentInArea);
 74
 675        RemoveAllModifiers(toRemove);
 76
 677        DataStore.i.player.ownPlayer.OnChange -= OwnPlayerOnOnChange;
 678        DataStore.i.player.otherPlayers.OnAdded -= OtherPlayersOnOnAdded;
 679        DataStore.i.player.otherPlayers.OnRemoved -= OnOtherPlayersRemoved;
 680    }
 81
 82    private void Update()
 83    {
 4884        if (cachedModel?.area == null)
 85        {
 086            return;
 87        }
 88
 89        // Find avatars currently on the area
 4890        HashSet<GameObject> newAvatarsInArea = DetectAllAvatarsInArea();
 4891        if (AreSetEquals(avatarsInArea, newAvatarsInArea))
 792            return;
 93
 4194        if (avatarsInArea == null)
 095            avatarsInArea = new HashSet<GameObject>();
 96
 4197        if (newAvatarsInArea == null)
 3498            newAvatarsInArea = new HashSet<GameObject>();
 99
 100        // Call event for avatars that just entered the area
 100101        foreach (GameObject avatarThatEntered in newAvatarsInArea.Except(avatarsInArea))
 102        {
 9103            OnAvatarEnter?.Invoke(avatarThatEntered);
 104        }
 105
 106        // Call events for avatars that just exited the area
 90107        foreach (GameObject avatarThatExited in avatarsInArea.Except(newAvatarsInArea))
 108        {
 4109            OnAvatarExit?.Invoke(avatarThatExited);
 110        }
 111
 41112        avatarsInArea = newAvatarsInArea;
 41113    }
 114
 115    private bool AreSetEquals(HashSet<GameObject> set1, HashSet<GameObject> set2)
 116    {
 48117        if (set1 == null && set2 == null)
 0118            return true;
 119
 48120        if (set1 == null || set2 == null)
 34121            return false;
 122
 14123        return set1.SetEquals(set2);
 124    }
 125
 126    private HashSet<GameObject> DetectAllAvatarsInArea()
 127    {
 70128        if (entity?.gameObject == null)
 129        {
 0130            return null;
 131        }
 132
 70133        Vector3 center = entity.gameObject.transform.position;
 70134        Quaternion rotation = entity.gameObject.transform.rotation;
 70135        return cachedModel.area?.DetectAvatars(center, rotation, excludedColliders);
 136    }
 137
 138    private void RemoveAllModifiers()
 139    {
 16140        RemoveAllModifiers(DetectAllAvatarsInArea());
 16141    }
 142
 143    private void RemoveAllModifiers(HashSet<GameObject> avatars)
 144    {
 22145        if (cachedModel?.area == null)
 146        {
 6147            return;
 148        }
 149
 16150        if (avatars != null)
 151        {
 48152            foreach (GameObject avatar in avatars)
 153            {
 14154                OnAvatarExit?.Invoke(avatar);
 155            }
 156        }
 16157    }
 158
 159    private void ApplyCurrentModel()
 160    {
 16161        DataStore.i.player.ownPlayer.OnChange -= OwnPlayerOnOnChange;
 16162        DataStore.i.player.otherPlayers.OnAdded -= OtherPlayersOnOnAdded;
 163
 16164        cachedModel = (Model)this.model;
 16165        if (cachedModel.modifiers != null)
 166        {
 167            // Add all listeners
 52168            foreach (string modifierKey in cachedModel.modifiers)
 169            {
 10170                if (!modifiers.TryGetValue(modifierKey, out AvatarModifier modifier))
 171                    continue;
 172
 10173                OnAvatarEnter += modifier.ApplyModifier;
 10174                OnAvatarExit += modifier.RemoveModifier;
 175            }
 176
 177            // Set excluded colliders
 16178            excludedColliders = GetExcludedColliders(cachedModel);
 179
 16180            if (cachedModel.excludeIds != null && cachedModel.excludeIds.Length > 0)
 181            {
 3182                DataStore.i.player.ownPlayer.OnChange += OwnPlayerOnOnChange;
 3183                DataStore.i.player.otherPlayers.OnAdded += OtherPlayersOnOnAdded;
 184            }
 185        }
 16186    }
 187
 188    public override int GetClassId()
 189    {
 0190        return (int)CLASS_ID_COMPONENT.AVATAR_MODIFIER_AREA;
 191    }
 192
 193    private static HashSet<Collider> GetExcludedColliders(in Model componentModel)
 194    {
 16195        string[] excludeIds = componentModel?.excludeIds;
 16196        if (excludeIds == null || excludeIds.Length == 0)
 197        {
 13198            return null;
 199        }
 200
 3201        var ownPlayer = DataStore.i.player.ownPlayer.Get();
 3202        var otherPlayers = DataStore.i.player.otherPlayers;
 203
 3204        HashSet<Collider> result = new HashSet<Collider>();
 14205        for (int i = 0; i < excludeIds.Length; i++)
 206        {
 4207            if (ownPlayer != null && excludeIds[i] == ownPlayer.id)
 208            {
 1209                result.Add(ownPlayer.collider);
 1210            }
 3211            else if (otherPlayers.TryGetValue(excludeIds[i], out Player player))
 212            {
 2213                result.Add(player.collider);
 214            }
 215        }
 3216        return result;
 217    }
 218
 219    private void OtherPlayersOnOnAdded(string id, Player player)
 220    {
 1221        RefreshExclusionList(player);
 1222    }
 223
 224    private void OwnPlayerOnOnChange(Player current, Player previous)
 225    {
 0226        RefreshExclusionList(current);
 0227    }
 228
 229    private void OnOtherPlayersRemoved(string id, Player player)
 230    {
 0231        excludedColliders?.Remove(player.collider);
 0232    }
 233
 234    private void RefreshExclusionList(Player player)
 235    {
 1236        string[] excludeIds = cachedModel?.excludeIds;
 1237        if (excludeIds == null || excludeIds.Length == 0)
 238        {
 0239            return;
 240        }
 241
 1242        if (!excludeIds.Contains(player.id))
 243        {
 0244            return;
 245        }
 246
 1247        if (excludedColliders == null)
 248        {
 0249            excludedColliders = new HashSet<Collider>();
 250        }
 1251        excludedColliders.Add(player.collider);
 1252    }
 253}