< 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:89
Uncovered lines:7
Coverable lines:96
Total lines:200
Line coverage:92.7% (89 of 96)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
AvatarsLODController()0%110100%
OnKernelConfigChanged(...)0%220100%
Initialize(...)0%5.065086.67%
RegisterAvatar(...)0%330100%
CreateLodController(...)0%2100%
UnregisterAvatar(...)0%220100%
Update()0%220100%
UpdateLODsBillboard()0%330100%
UpdateAllLODs(...)0%880100%
ComposeLODControllersSortedByDistance(...)0%220100%
SqrDistanceToOwnPlayer(...)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;
 5using DCL.Interface;
 6
 7namespace DCL
 8{
 9    public class AvatarsLODController : IAvatarsLODController
 10    {
 11        internal const float RENDERED_DOT_PRODUCT_ANGLE = 0.25f;
 12
 013        private BaseDictionary<string, Player> otherPlayers => DataStore.i.player.otherPlayers;
 014        private BaseVariable<float> simpleAvatarDistance => DataStore.i.avatarsLOD.simpleAvatarDistance;
 015        private BaseVariable<float> LODDistance => DataStore.i.avatarsLOD.LODDistance;
 016        private BaseVariable<int> maxAvatars => DataStore.i.avatarsLOD.maxAvatars;
 017        private BaseVariable<int> maxImpostors => DataStore.i.avatarsLOD.maxImpostors;
 18        private Vector3 cameraPosition;
 19        private Vector3 cameraForward;
 20
 68421        internal readonly Dictionary<string, IAvatarLODController> lodControllers = new Dictionary<string, IAvatarLODCon
 22        internal bool enabled;
 23
 68424        public AvatarsLODController()
 25        {
 68426            KernelConfig.i.EnsureConfigInitialized()
 27                        .Then(config =>
 28                        {
 68429                            KernelConfig.i.OnChange += OnKernelConfigChanged;
 68430                            OnKernelConfigChanged(config, null);
 68431                        });
 68432        }
 33
 34        private void OnKernelConfigChanged(KernelConfigModel current, KernelConfigModel previous)
 35        {
 264436            if (enabled == current.features.enableAvatarLODs)
 262937                return;
 1538            Initialize(current);
 1539        }
 40
 41        internal void Initialize(KernelConfigModel config)
 42        {
 1943            enabled = config.features.enableAvatarLODs;
 1944            if (!enabled)
 1545                return;
 46
 847            foreach (IAvatarLODController lodController in lodControllers.Values)
 48            {
 049                lodController.Dispose();
 50            }
 451            lodControllers.Clear();
 52
 1253            foreach (var keyValuePair in otherPlayers.Get())
 54            {
 255                RegisterAvatar(keyValuePair.Key, keyValuePair.Value);
 56            }
 457            otherPlayers.OnAdded += RegisterAvatar;
 458            otherPlayers.OnRemoved += UnregisterAvatar;
 459        }
 60
 61        public void RegisterAvatar(string id, Player player)
 62        {
 563            if (!enabled || lodControllers.ContainsKey(id))
 164                return;
 65
 466            lodControllers.Add(id, CreateLodController(player));
 467        }
 68
 069        protected internal virtual IAvatarLODController CreateLodController(Player player) => new AvatarLODController(pl
 70
 71        public void UnregisterAvatar(string id, Player player)
 72        {
 373            if (!lodControllers.ContainsKey(id))
 174                return;
 75
 276            lodControllers[id].Dispose();
 277            lodControllers.Remove(id);
 278        }
 79
 80        public void Update()
 81        {
 1697282            if (!enabled)
 1696583                return;
 84
 785            cameraPosition = CommonScriptableObjects.cameraPosition.Get();
 786            cameraForward = CommonScriptableObjects.cameraForward.Get();
 87
 788            UpdateAllLODs(maxAvatars.Get(), maxImpostors.Get());
 789            UpdateLODsBillboard();
 790        }
 91
 92        internal void UpdateLODsBillboard()
 93        {
 5894            foreach (var kvp in lodControllers)
 95            {
 2296                Player player = kvp.Value.player;
 97
 2298                if (!IsInFrontOfCamera(player.worldPosition))
 99                    continue;
 100
 21101                Vector3 previousForward = player.forwardDirection;
 21102                Vector3 lookAtDir = (cameraPosition - player.worldPosition).normalized;
 103
 21104                lookAtDir.y = previousForward.y;
 21105                player.renderer.SetImpostorForward(lookAtDir);
 106            }
 7107        }
 108
 109        internal void UpdateAllLODs(int maxAvatars = DataStore.DataStore_AvatarsLOD.DEFAULT_MAX_AVATAR, int maxImpostors
 110        {
 9111            int avatarsCount = 0; //Full Avatar + Simple Avatar
 9112            int impostorCount = 0; //Impostor
 113
 114            //Cache .Get() to boost performance. Also use squared values to boost distance comparison
 9115            float lodDistance = LODDistance.Get() * LODDistance.Get();
 9116            float squaredSimpleAvatarDistance = simpleAvatarDistance.Get() * simpleAvatarDistance.Get();
 9117            Vector3 ownPlayerPosition = CommonScriptableObjects.playerUnityPosition.Get();
 118
 9119            (IAvatarLODController lodController, float sqrDistance)[] lodControllersByDistance = ComposeLODControllersSo
 70120            for (int index = 0; index < lodControllersByDistance.Length; index++)
 121            {
 26122                (IAvatarLODController lodController, float sqrtDistance) = lodControllersByDistance[index];
 26123                if (sqrtDistance < 0) //Behind camera
 124                {
 5125                    lodController.SetInvisible();
 5126                    continue;
 127                }
 128
 129                //Nearby player
 21130                if (sqrtDistance < lodDistance)
 131                {
 15132                    if (avatarsCount < maxAvatars)
 133                    {
 12134                        if (sqrtDistance < squaredSimpleAvatarDistance)
 9135                            lodController.SetFullAvatar();
 136                        else
 3137                            lodController.SetSimpleAvatar();
 12138                        avatarsCount++;
 12139                        continue;
 140                    }
 141
 3142                    lodController.SetInvisible();
 3143                    continue;
 144                }
 145
 6146                if (avatarsCount < maxAvatars)
 147                {
 2148                    lodController.SetSimpleAvatar();
 2149                    avatarsCount++;
 2150                    continue;
 151                }
 4152                if (impostorCount < maxImpostors)
 153                {
 3154                    lodController.SetImpostor();
 155
 3156                    lodController.UpdateImpostorTint(Mathf.Sqrt(sqrtDistance));
 157
 3158                    impostorCount++;
 3159                    continue;
 160                }
 161
 1162                lodController.SetInvisible();
 163            }
 9164        }
 165
 166        private (IAvatarLODController lodController, float sqrDistance)[] ComposeLODControllersSortedByDistance(IEnumera
 167        {
 35168            (IAvatarLODController lodController, float sqrDistance)[] lodControllersWithDistance = lodControllers.Select
 32169            Array.Sort(lodControllersWithDistance, (x, y) => x.sqrDistance.CompareTo(y.sqrDistance));
 9170            return lodControllersWithDistance;
 171        }
 172
 173        /// <summary>
 174        /// Returns -1 if player is not in front of camera or not found
 175        /// </summary>
 176        /// <param name="player"></param>
 177        /// <returns></returns>
 178        private float SqrDistanceToOwnPlayer(Player player, Vector3 ownPlayerPosition)
 179        {
 26180            if (player == null || !IsInFrontOfCamera(player.worldPosition))
 5181                return -1;
 182
 21183            return Vector3.SqrMagnitude(ownPlayerPosition - player.worldPosition);
 184        }
 185
 48186        private bool IsInFrontOfCamera(Vector3 position) { return Vector3.Dot(cameraForward, (position - cameraPosition)
 187
 188        public void Dispose()
 189        {
 704190            KernelConfig.i.OnChange -= OnKernelConfigChanged;
 1468191            foreach (IAvatarLODController lodController in lodControllers.Values)
 192            {
 30193                lodController.Dispose();
 194            }
 195
 704196            otherPlayers.OnAdded -= RegisterAvatar;
 704197            otherPlayers.OnRemoved -= UnregisterAvatar;
 704198        }
 199    }
 200}