< Summary

Class:DCLServices.MapRendererV2.MapLayers.UsersMarkers.ColdArea.UsersMarkersColdAreaController
Assembly:MapRendererV2
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/DCLServices/MapRendererV2/MapLayers/UsersMarkers/ColdArea/UsersMarkersColdAreaController.cs
Covered lines:35
Uncovered lines:38
Coverable lines:73
Total lines:196
Line coverage:47.9% (35 of 73)
Covered branches:0
Total branches:0
Covered methods:5
Total methods:16
Method coverage:31.2% (5 of 16)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
UsersMarkersColdAreaController(...)0%110100%
Initialize()0%330100%
<Initialize()0%550100%
SetData(...)0%2100%
RandomizeCoord(...)0%2100%
ResolveVisibility(...)0%2100%
DisposeImpl()0%110100%
ColdAreasUpdateLoop()0%1561200%
RenewSceneInfos(...)0%12300%
OnRealmNameChange(...)0%6200%
ResolveRealm(...)0%6200%
OnUserPositionChange(...)0%6200%
OnMapObjectBecameVisible(...)0%2100%
OnMapObjectCulled(...)0%2100%
Enable(...)0%6200%
Disable(...)0%330100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/DCLServices/MapRendererV2/MapLayers/UsersMarkers/ColdArea/UsersMarkersColdAreaController.cs

#LineLine coverage
 1using Cysharp.Threading.Tasks;
 2using DCL;
 3using DCLServices.MapRendererV2.CoordsUtils;
 4using DCLServices.MapRendererV2.Culling;
 5using DCLServices.MapRendererV2.MapCameraController;
 6using MainScripts.DCL.Controllers.HotScenes;
 7using System;
 8using System.Collections.Generic;
 9using System.Runtime.CompilerServices;
 10using System.Threading;
 11using UnityEngine;
 12using Random = UnityEngine.Random;
 13
 14namespace DCLServices.MapRendererV2.MapLayers.UsersMarkers.ColdArea
 15{
 16    /// <summary>
 17    /// This controller is responsible for updating User Markers outside of the comms area.
 18    /// Whereas the comms area is the region around the player where avatars (and therefore the users) are fetched accor
 19    /// </summary>
 20    internal partial class UsersMarkersColdAreaController : MapLayerControllerBase, IMapLayerController, IMapCullingList
 21    {
 22        internal delegate IColdUserMarker ColdUserMarkerBuilder(
 23            ColdUserMarkerObject prefab,
 24            Transform parent);
 25
 26        internal const int CREATE_PER_BATCH = 20;
 27        internal const int COMMS_RADIUS_THRESHOLD = 2;
 28
 29        private IHotScenesFetcher hotScenesFetcher;
 30
 31        private readonly ColdUserMarkerObject prefab;
 32        private readonly int maxMarkers;
 33        private readonly ColdUserMarkerBuilder builder;
 34        private readonly BaseVariable<string> realmName;
 35        private readonly Vector2IntVariable userPosition;
 36
 37        private ExclusionAreaProvider exclusionArea;
 38        private ColdUserMarkersStorage storage;
 39
 40        private CancellationTokenSource cancellationTokenSource;
 41        IColdUserMarker[] instances;
 42
 43        public UsersMarkersColdAreaController(Transform parent, ColdUserMarkerObject prefab, ColdUserMarkerBuilder build
 44            IHotScenesFetcher hotScenesFetcher, BaseVariable<string> realmName, Vector2IntVariable userPosition,
 45            KernelConfig kernelConfig, ICoordsUtils coordsUtils, IMapCullingController cullingController, int maxMarkers
 9646            : base(parent, coordsUtils, cullingController)
 47        {
 9648            this.prefab = prefab;
 9649            this.maxMarkers = maxMarkers;
 9650            this.builder = builder;
 9651            this.realmName = realmName;
 9652            this.userPosition = userPosition;
 9653            this.hotScenesFetcher = hotScenesFetcher;
 54
 9655            exclusionArea = new ExclusionAreaProvider(kernelConfig, COMMS_RADIUS_THRESHOLD);
 9656        }
 57
 58        public async UniTask Initialize(CancellationToken cancellationToken)
 59        {
 9660            cancellationTokenSource = LinkWithDisposeToken(cancellationToken);
 9661            cancellationToken = cancellationTokenSource.Token;
 9662            instances = new IColdUserMarker[maxMarkers];
 63            async UniTask InstantiateMarkers(CancellationToken ct)
 64            {
 61465                for (var i = 0; i < maxMarkers;)
 66                {
 44967                    var batchSize = Mathf.Min(maxMarkers - i, CREATE_PER_BATCH);
 68
 1885869                    for (var j = 0; j < batchSize; j++)
 70                    {
 898071                        var marker = builder(prefab, instantiationParent);
 898072                        marker.SetActive(false);
 898073                        instances[i] = marker;
 898074                        i++;
 75                    }
 76
 77                    // NextFrame does not work in Tests (see the implementation, there is a special case if Application 
 134778                    await UniTask.DelayFrame(1, cancellationToken: ct);
 79                }
 80
 6981                storage = new ColdUserMarkersStorage(instances, SetData);
 6982            }
 83
 28884            await UniTask.WhenAll(InstantiateMarkers(cancellationToken), exclusionArea.Initialize(cancellationToken));
 85
 686            realmName.OnChange += OnRealmNameChange;
 687            userPosition.OnChange += OnUserPositionChange;
 688        }
 89
 90        private void SetData(IColdUserMarker marker, (string realmServer, Vector2Int coords) data)
 91        {
 092            var randomizedCoords = new Vector2Int(
 93                RandomizeCoord(data.coords.x),
 94                RandomizeCoord(data.coords.y));
 95
 096            var position = coordsUtils.CoordsToPosition(randomizedCoords, marker);
 097            marker.SetData(data.realmServer, realmName.Get(), data.coords, position);
 098            ResolveVisibility(marker);
 099        }
 100
 101        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 102        private static int RandomizeCoord(int coord) =>
 0103            Mathf.RoundToInt(coord + Random.Range(-0.5f, 0.5f));
 104
 105        private void ResolveVisibility(IColdUserMarker marker)
 106        {
 0107            marker.SetActive(!exclusionArea.Contains(marker.Coords));
 0108        }
 109
 110        protected override void DisposeImpl()
 111        {
 6112            realmName.OnChange -= OnRealmNameChange;
 6113            userPosition.OnChange -= OnUserPositionChange;
 6114            storage.Dispose();
 6115        }
 116
 117        private async UniTaskVoid ColdAreasUpdateLoop(CancellationToken cancellationToken)
 118        {
 0119            await foreach (var data in hotScenesFetcher.ScenesInfo)
 120            {
 0121                if (cancellationToken.IsCancellationRequested)
 122                    return;
 123
 0124                RenewSceneInfos(data);
 125            }
 0126        }
 127
 128        private void RenewSceneInfos(IReadOnlyList<IHotScenesController.HotSceneInfo> sceneInfos)
 129        {
 130            // it is forbidden to declare Spans variables in the async flow so we have to have a separate sync method fo
 0131            storage.Update(sceneInfos, out var newRents, out var recycledRents);
 132
 0133            foreach (var marker in recycledRents)
 0134                mapCullingController.StopTracking(marker);
 135
 0136            foreach (var marker in newRents)
 137            {
 0138                mapCullingController.StartTracking(marker, this);
 0139                mapCullingController.SetTrackedObjectPositionDirty(marker);
 140            }
 0141        }
 142
 143        private void OnRealmNameChange(string current, string previous)
 144        {
 0145            if (!string.IsNullOrEmpty(current))
 0146                ResolveRealm(current);
 0147        }
 148
 149        private void ResolveRealm(string realmName)
 150        {
 0151            foreach (var marker in storage.Markers)
 0152                marker.OnRealmChanged(realmName);
 0153        }
 154
 155        private void OnUserPositionChange(Vector2Int current, Vector2Int previous)
 156        {
 0157            exclusionArea.SetExclusionAreaCenter(current);
 158
 0159            foreach (IColdUserMarker userMarker in storage.Markers)
 0160                ResolveVisibility(userMarker);
 0161        }
 162
 163        public void OnMapObjectBecameVisible(IColdUserMarker marker)
 164        {
 0165            marker.SetCulled(false);
 0166        }
 167
 168        public void OnMapObjectCulled(IColdUserMarker marker)
 169        {
 0170            marker.SetCulled(true);
 0171        }
 172
 173        public UniTask Enable(CancellationToken cancellationToken)
 174        {
 0175            hotScenesFetcher.SetUpdateMode(IHotScenesFetcher.UpdateMode.FOREGROUND);
 0176            ColdAreasUpdateLoop(LinkWithDisposeToken(cancellationToken).Token).Forget();
 0177            foreach (IColdUserMarker coldUserMarker in instances)
 178            {
 0179                coldUserMarker.SetActive(true);
 180            }
 0181            return UniTask.CompletedTask;
 182        }
 183
 184        public UniTask Disable(CancellationToken cancellationToken)
 185        {
 88186            hotScenesFetcher.SetUpdateMode(IHotScenesFetcher.UpdateMode.BACKGROUND);
 17776187            foreach (IColdUserMarker coldUserMarker in instances)
 188            {
 8800189                if(coldUserMarker != null)
 8740190                    coldUserMarker.SetActive(false);
 191            }
 192            // cancellation of `ColdAreasUpdateLoop` is handled by the cancellation token
 88193            return UniTask.CompletedTask;
 194        }
 195    }
 196}