< Summary

Class:DCL.AvatarsLODController
Assembly:AvatarShape
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarLOD/AvatarsLODController.cs
Covered lines:82
Uncovered lines:10
Coverable lines:92
Total lines:198
Line coverage:89.1% (82 of 92)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
AvatarsLODController()0%110100%
Initialize()0%110100%
OnFeatureFlagChanged(...)0%6200%
Initialize(...)0%5.25080%
RegisterAvatar(...)0%330100%
CreateLodController(...)0%2100%
UnregisterAvatar(...)0%220100%
Update()0%220100%
UpdateAllLODs(...)0%8.018094.12%
IsInInvisibleDistance(...)0%220100%
ComposeLODControllersSortedByDistance(...)0%220100%
DistanceToOwnPlayer(...)0%330100%
IsInFrontOfCamera(...)0%110100%
Dispose()0%220100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarLOD/AvatarsLODController.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using UnityEngine;
 5
 6namespace DCL
 7{
 8    public class AvatarsLODController : IAvatarsLODController
 9    {
 10        internal const string AVATAR_LODS_FLAG_NAME = "avatar_lods";
 11        internal const float RENDERED_DOT_PRODUCT_ANGLE = 0.25f;
 12        internal const float AVATARS_INVISIBILITY_DISTANCE = 1.75f;
 13        private const float MIN_DISTANCE_BETWEEN_NAMES_PIXELS = 70f;
 14
 130415        private BaseDictionary<string, Player> otherPlayers => DataStore.i.player.otherPlayers;
 916        private BaseVariable<float> simpleAvatarDistance => DataStore.i.avatarsLOD.simpleAvatarDistance;
 017        private BaseVariable<float> LODDistance => DataStore.i.avatarsLOD.LODDistance;
 818        private BaseVariable<int> maxAvatars => DataStore.i.avatarsLOD.maxAvatars;
 819        private BaseVariable<int> maxImpostors => DataStore.i.avatarsLOD.maxImpostors;
 20        private Vector3 cameraPosition;
 21        private Vector3 cameraForward;
 22        private GPUSkinningThrottlingCurveSO gpuSkinningThrottlingCurve;
 64623        private SimpleOverlappingTracker overlappingTracker = new SimpleOverlappingTracker(MIN_DISTANCE_BETWEEN_NAMES_PI
 24
 64625        internal readonly Dictionary<string, IAvatarLODController> lodControllers = new Dictionary<string, IAvatarLODCon
 26        internal bool enabled;
 27        private UnityEngine.Camera mainCamera;
 28
 64629        public AvatarsLODController ()
 30        {
 64631            gpuSkinningThrottlingCurve = Resources.Load<GPUSkinningThrottlingCurveSO>("GPUSkinningThrottlingCurve");
 64632            DataStore.i.featureFlags.flags.OnChange += OnFeatureFlagChanged;
 64633        }
 34
 35        public void Initialize()
 36        {
 64637            Environment.i.platform.updateEventHandler.AddListener(IUpdateEventHandler.EventType.Update, Update);
 64638        }
 39
 40        private void OnFeatureFlagChanged(FeatureFlag current, FeatureFlag previous)
 41        {
 042            if (enabled == current.IsFeatureEnabled(AVATAR_LODS_FLAG_NAME))
 043                return;
 44
 045            Initialize(current);
 046        }
 47
 48        internal void Initialize(FeatureFlag current)
 49        {
 450            enabled = current.IsFeatureEnabled(AVATAR_LODS_FLAG_NAME);
 51
 452            if (!enabled)
 053                return;
 54
 855            foreach (IAvatarLODController lodController in lodControllers.Values)
 56            {
 057                lodController.Dispose();
 58            }
 59
 460            lodControllers.Clear();
 61
 1262            foreach (var keyValuePair in otherPlayers.Get())
 63            {
 264                RegisterAvatar(keyValuePair.Key, keyValuePair.Value);
 65            }
 66
 467            otherPlayers.OnAdded += RegisterAvatar;
 468            otherPlayers.OnRemoved += UnregisterAvatar;
 469        }
 70
 71        public void RegisterAvatar(string id, Player player)
 72        {
 573            if (!enabled || lodControllers.ContainsKey(id))
 174                return;
 75
 476            lodControllers.Add(id, CreateLodController(player));
 477        }
 78
 079        protected internal virtual IAvatarLODController CreateLodController(Player player) => new AvatarLODController(pl
 80
 81        public void UnregisterAvatar(string id, Player player)
 82        {
 383            if (!lodControllers.ContainsKey(id))
 184                return;
 85
 286            lodControllers[id].Dispose();
 287            lodControllers.Remove(id);
 288        }
 89
 90        public void Update()
 91        {
 694992            if (!enabled)
 694193                return;
 94
 895            cameraPosition = CommonScriptableObjects.cameraPosition.Get();
 896            cameraForward = CommonScriptableObjects.cameraForward.Get();
 97
 898            UpdateAllLODs(maxAvatars.Get(), maxImpostors.Get());
 899        }
 100
 101        internal void UpdateAllLODs(int maxAvatars = DataStore_AvatarsLOD.DEFAULT_MAX_AVATAR, int maxImpostors = DataSto
 102        {
 9103            if (mainCamera == null)
 9104                mainCamera = UnityEngine.Camera.main;
 9105            int avatarsCount = 0; //Full Avatar + Simple Avatar
 9106            int impostorCount = 0; //Impostor
 107
 9108            float simpleAvatarDistance = this.simpleAvatarDistance.Get();
 9109            Vector3 ownPlayerPosition = CommonScriptableObjects.playerUnityPosition.Get();
 110
 9111            overlappingTracker.Reset();
 112
 9113            (IAvatarLODController lodController, float distance)[] lodControllersByDistance = ComposeLODControllersSorte
 114
 66115            for (int index = 0; index < lodControllersByDistance.Length; index++)
 116            {
 24117                (IAvatarLODController lodController, float distance) = lodControllersByDistance[index];
 118
 24119                if (IsInInvisibleDistance(distance))
 120                {
 4121                    lodController.SetNameVisible(false);
 4122                    lodController.SetInvisible();
 4123                    continue;
 124                }
 125
 20126                if (avatarsCount < maxAvatars)
 127                {
 13128                    lodController.SetAnimationThrottling((int)gpuSkinningThrottlingCurve.curve.Evaluate(distance));
 13129                    if (distance < simpleAvatarDistance)
 9130                        lodController.SetLOD0();
 131                    else
 4132                        lodController.SetLOD1();
 13133                    avatarsCount++;
 134
 13135                    if (mainCamera == null)
 13136                        lodController.SetNameVisible(true);
 137                    else
 0138                        lodController.SetNameVisible(overlappingTracker.RegisterPosition(lodController.player.playerName
 139
 0140                    continue;
 141                }
 142
 7143                lodController.SetNameVisible(false);
 7144                if (impostorCount < maxImpostors)
 145                {
 6146                    lodController.SetLOD2();
 6147                    lodController.UpdateImpostorTint(distance);
 6148                    impostorCount++;
 6149                    continue;
 150                }
 151
 1152                lodController.SetInvisible();
 153            }
 9154        }
 155
 156        private bool IsInInvisibleDistance(float distance)
 157        {
 24158            bool firstPersonCamera = CommonScriptableObjects.cameraMode.Get() == CameraMode.ModeId.FirstPerson;
 159
 24160            return firstPersonCamera ? distance < AVATARS_INVISIBILITY_DISTANCE : distance < 0f; // < 0 is behind camera
 161        }
 162
 163        private (IAvatarLODController lodController, float distance)[] ComposeLODControllersSortedByDistance(IEnumerable
 164        {
 33165            (IAvatarLODController lodController, float distance)[] lodControllersWithDistance = lodControllers.Select(x 
 30166            Array.Sort(lodControllersWithDistance, (x, y) => x.distance.CompareTo(y.distance));
 9167            return lodControllersWithDistance;
 168        }
 169
 170        /// <summary>
 171        /// Returns -1 if player is not in front of camera or not found
 172        /// </summary>
 173        /// <param name="player"></param>
 174        /// <returns></returns>
 175        private float DistanceToOwnPlayer(Player player, Vector3 ownPlayerPosition)
 176        {
 24177            if (player == null || !IsInFrontOfCamera(player.worldPosition))
 3178                return -1;
 179
 21180            return Vector3.Distance(ownPlayerPosition, player.worldPosition);
 181        }
 182
 24183        private bool IsInFrontOfCamera(Vector3 position) { return Vector3.Dot(cameraForward, (position - cameraPosition)
 184
 185        public void Dispose()
 186        {
 646187            DataStore.i.featureFlags.flags.OnChange -= OnFeatureFlagChanged;
 1346188            foreach (IAvatarLODController lodController in lodControllers.Values)
 189            {
 27190                lodController.Dispose();
 191            }
 192
 646193            otherPlayers.OnAdded -= RegisterAvatar;
 646194            otherPlayers.OnRemoved -= UnregisterAvatar;
 646195            DCL.Environment.i.platform.updateEventHandler.RemoveListener(IUpdateEventHandler.EventType.Update, Update);
 646196        }
 197    }
 198}