< Summary

Class:DCL.MapRenderer
Assembly:MapRenderer
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/MapRenderer/MapRenderer.cs
Covered lines:77
Uncovered lines:86
Coverable lines:163
Total lines:373
Line coverage:47.2% (77 of 163)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
MapRenderer()0%110100%
Awake()0%110100%
Initialize()0%220100%
EnsurePools()0%3.043083.33%
OnDestroy()0%110100%
Cleanup()0%550100%
Update()0%3.882022.22%
UpdateCursorMapCoords()0%6200%
IsCursorOverMapChunk()0%6200%
UpdateParcelHighlight()0%90900%
UpdateParcelHold()0%12300%
OnKernelConfigChanged(...)0%2100%
CoordinatesAreInsideTheWorld(...)0%12300%
MapRenderer_OnSceneInfoUpdated(...)0%55094.44%
OnOtherPlayersAdded(...)0%2100%
OnOtherPlayerRemoved(...)0%6200%
ConfigureUserIcon(...)0%2100%
OnCharacterMove(...)0%2.152066.67%
OnCharacterRotate(...)0%2100%
OnCharacterSetPosition(...)0%6200%
UpdateRendering(...)0%2100%
UpdateBackgroundLayer(...)0%2100%
UpdateSelectionLayer()0%2100%
UpdateOverlayLayer()0%2100%
GetViewportCenter()0%2100%
ClickMousePositionParcel()0%6200%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/MapRenderer/MapRenderer.cs

#LineLine coverage
 1using DCL.Helpers;
 2using System.Collections.Generic;
 3using UnityEngine;
 4using UnityEngine.UI;
 5using UnityEngine.EventSystems;
 6using TMPro;
 7using KernelConfigurationTypes;
 8
 9namespace DCL
 10{
 11    public class MapRenderer : MonoBehaviour
 12    {
 13        const int LEFT_BORDER_PARCELS = 25;
 14        const int RIGHT_BORDER_PARCELS = 31;
 15        const int TOP_BORDER_PARCELS = 31;
 16        const int BOTTOM_BORDER_PARCELS = 25;
 17        const int WORLDMAP_WIDTH_IN_PARCELS = 300;
 18        const string MINIMAP_USER_ICONS_POOL_NAME = "MinimapUserIconsPool";
 19        const int MINIMAP_USER_ICONS_MAX_PREWARM = 30;
 20        private const int MAX_CURSOR_PARCEL_DISTANCE = 40;
 21        private int NAVMAP_CHUNK_LAYER;
 22
 64123        public static MapRenderer i { get; private set; }
 24
 1225        [SerializeField] private float parcelHightlightScale = 1.25f;
 26        [SerializeField] private Button ParcelHighlightButton;
 27
 28        [HideInInspector] public Vector3 cursorMapCoords;
 1229        [HideInInspector] public bool showCursorCoords = true;
 30        [HideInInspector] public event System.Action OnMovedParcelCursor;
 031        public Vector3 playerGridPosition => Utils.WorldToGridPositionUnclamped(playerWorldPosition.Get());
 32        public MapAtlas atlas;
 33        public RawImage parcelHighlightImage;
 34        public TextMeshProUGUI highlightedParcelText;
 35        public Transform overlayContainer;
 36        public Transform globalUserMarkerContainer;
 37        public RectTransform playerPositionIcon;
 38
 39        public static System.Action<int, int> OnParcelClicked;
 40        public static System.Action OnCursorFarFromParcel;
 41
 1242        public float scaleFactor = 1f;
 43
 44        // Used as a reference of the coordinates origin in-map and as a parcel width/height reference
 45        public RectTransform centeredReferenceParcel;
 46
 47        public MapSceneIcon scenesOfInterestIconPrefab;
 48        public GameObject userIconPrefab;
 49        public UserMarkerObject globalUserMarkerPrefab;
 50
 051        public MapGlobalUsersPositionMarkerController usersPositionMarkerController { private set; get; }
 52
 53        private float parcelSizeInMap;
 2254        private Vector3Variable playerWorldPosition => CommonScriptableObjects.playerWorldPosition;
 2255        private Vector3Variable playerRotation => CommonScriptableObjects.cameraForward;
 1256        private Vector3[] mapWorldspaceCorners = new Vector3[4];
 57        private Vector3 worldCoordsOriginInMap;
 1258        private List<RaycastResult> uiRaycastResults = new List<RaycastResult>();
 1259        private PointerEventData uiRaycastPointerEventData = new PointerEventData(EventSystem.current);
 60
 1261        private HashSet<MinimapMetadata.MinimapSceneInfo> scenesOfInterest = new HashSet<MinimapMetadata.MinimapSceneInf
 1262        private Dictionary<MinimapMetadata.MinimapSceneInfo, GameObject> scenesOfInterestMarkers = new Dictionary<Minima
 1263        private Dictionary<string, PoolableObject> usersInfoMarkers = new Dictionary<string, PoolableObject>();
 64
 65        private Vector3 lastClickedCursorMapCoords;
 66        private Pool usersInfoPool;
 67
 4468        private BaseDictionary<string, Player> otherPlayers => DataStore.i.player.otherPlayers;
 69        private bool isInitialized = false;
 70
 71        private bool parcelHighlightEnabledValue = false;
 72
 1273        List<WorldRange> validWorldRanges = new List<WorldRange>
 74        {
 75            new WorldRange(-150, -150, 150, 150) // default range
 76        };
 77
 78        public bool parcelHighlightEnabled
 79        {
 80            set
 81            {
 082                parcelHighlightEnabledValue = value;
 083                parcelHighlightImage.gameObject.SetActive(parcelHighlightEnabledValue);
 084            }
 085            get { return parcelHighlightEnabledValue; }
 86        }
 87
 88        private void Awake()
 89        {
 1090            i = this;
 1091            Initialize();
 1092        }
 93
 94        public void Initialize()
 95        {
 1196            if (isInitialized)
 197                return;
 98
 1099            isInitialized = true;
 10100            EnsurePools();
 10101            atlas.InitializeChunks();
 10102            NAVMAP_CHUNK_LAYER = LayerMask.NameToLayer("NavmapChunk");
 103
 10104            MinimapMetadata.GetMetadata().OnSceneInfoUpdated += MapRenderer_OnSceneInfoUpdated;
 10105            otherPlayers.OnAdded += OnOtherPlayersAdded;
 10106            otherPlayers.OnRemoved += OnOtherPlayerRemoved;
 107
 10108            ParcelHighlightButton.onClick.AddListener(ClickMousePositionParcel);
 109
 10110            playerWorldPosition.OnChange += OnCharacterMove;
 10111            playerRotation.OnChange += OnCharacterRotate;
 112
 10113            parcelHighlightImage.rectTransform.localScale = new Vector3(parcelHightlightScale, parcelHightlightScale, 1f
 114
 10115            usersPositionMarkerController = new MapGlobalUsersPositionMarkerController(globalUserMarkerPrefab,
 116                globalUserMarkerContainer,
 117                MapUtils.GetTileToLocalPosition);
 118
 10119            usersPositionMarkerController.SetUpdateMode(MapGlobalUsersPositionMarkerController.UpdateMode.BACKGROUND);
 120
 10121            KernelConfig.i.OnChange += OnKernelConfigChanged;
 10122        }
 123
 124        private void EnsurePools()
 125        {
 10126            usersInfoPool = PoolManager.i.GetPool(MINIMAP_USER_ICONS_POOL_NAME);
 127
 10128            if (usersInfoPool == null)
 129            {
 10130                usersInfoPool = PoolManager.i.AddPool(
 131                    MINIMAP_USER_ICONS_POOL_NAME,
 132                    Instantiate(userIconPrefab.gameObject, overlayContainer.transform),
 133                    maxPrewarmCount: MINIMAP_USER_ICONS_MAX_PREWARM,
 134                    isPersistent: true);
 135
 10136                if (!Configuration.EnvironmentSettings.RUNNING_TESTS)
 0137                    usersInfoPool.ForcePrewarm();
 138            }
 10139        }
 140
 20141        public void OnDestroy() { Cleanup(); }
 142
 143        public void Cleanup()
 144        {
 12145            if (atlas != null)
 11146                atlas.Cleanup();
 147
 26148            foreach (var kvp in scenesOfInterestMarkers)
 149            {
 1150                if (kvp.Value != null)
 1151                    Destroy(kvp.Value);
 152            }
 153
 12154            scenesOfInterestMarkers.Clear();
 155
 12156            playerWorldPosition.OnChange -= OnCharacterMove;
 12157            playerRotation.OnChange -= OnCharacterRotate;
 12158            MinimapMetadata.GetMetadata().OnSceneInfoUpdated -= MapRenderer_OnSceneInfoUpdated;
 12159            otherPlayers.OnAdded -= OnOtherPlayersAdded;
 12160            otherPlayers.OnRemoved -= OnOtherPlayerRemoved;
 161
 12162            ParcelHighlightButton.onClick.RemoveListener(ClickMousePositionParcel);
 163
 12164            usersPositionMarkerController?.Dispose();
 165
 12166            KernelConfig.i.OnChange -= OnKernelConfigChanged;
 167
 12168            isInitialized = false;
 12169        }
 170
 171        void Update()
 172        {
 4173            if (!parcelHighlightEnabled)
 4174                return;
 175
 0176            parcelSizeInMap = centeredReferenceParcel.rect.width * centeredReferenceParcel.lossyScale.x;
 177
 178            // the reference parcel has a bottom-left pivot
 0179            centeredReferenceParcel.GetWorldCorners(mapWorldspaceCorners);
 0180            worldCoordsOriginInMap = mapWorldspaceCorners[0];
 181
 0182            UpdateCursorMapCoords();
 183
 0184            UpdateParcelHighlight();
 185
 0186            UpdateParcelHold();
 0187        }
 188
 189        void UpdateCursorMapCoords()
 190        {
 0191            if (!IsCursorOverMapChunk())
 0192                return;
 193
 0194            cursorMapCoords = Input.mousePosition - worldCoordsOriginInMap;
 0195            cursorMapCoords = cursorMapCoords / parcelSizeInMap;
 196
 0197            cursorMapCoords.x = (int)Mathf.Floor(cursorMapCoords.x);
 0198            cursorMapCoords.y = (int)Mathf.Floor(cursorMapCoords.y);
 0199        }
 200
 201        bool IsCursorOverMapChunk()
 202        {
 0203            uiRaycastPointerEventData.position = Input.mousePosition;
 0204            EventSystem.current.RaycastAll(uiRaycastPointerEventData, uiRaycastResults);
 205
 0206            return uiRaycastResults.Count > 0 && uiRaycastResults[0].gameObject.layer == NAVMAP_CHUNK_LAYER;
 207        }
 208
 209        void UpdateParcelHighlight()
 210        {
 0211            if (!CoordinatesAreInsideTheWorld((int)cursorMapCoords.x, (int)cursorMapCoords.y))
 212            {
 0213                if (parcelHighlightImage.gameObject.activeSelf)
 0214                    parcelHighlightImage.gameObject.SetActive(false);
 215
 0216                return;
 217            }
 218
 0219            if (!parcelHighlightImage.gameObject.activeSelf)
 0220                parcelHighlightImage.gameObject.SetActive(true);
 221
 0222            string previousText = highlightedParcelText.text;
 0223            parcelHighlightImage.rectTransform.SetAsLastSibling();
 0224            parcelHighlightImage.rectTransform.anchoredPosition = MapUtils.GetTileToLocalPosition(cursorMapCoords.x, cur
 0225            highlightedParcelText.text = showCursorCoords ? $"{cursorMapCoords.x}, {cursorMapCoords.y}" : string.Empty;
 226
 0227            if (highlightedParcelText.text != previousText && !Input.GetMouseButton(0))
 228            {
 0229                OnMovedParcelCursor?.Invoke();
 230            }
 231
 232            // ----------------------------------------------------
 233            // TODO: Use sceneInfo to highlight whole scene parcels and populate scenes hover info on navmap once we can
 234            // var sceneInfo = mapMetadata.GetSceneInfo(cursorMapCoords.x, cursorMapCoords.y);
 0235        }
 236
 237        void UpdateParcelHold()
 238        {
 0239            if(Vector3.Distance(lastClickedCursorMapCoords, cursorMapCoords) > MAX_CURSOR_PARCEL_DISTANCE / (scaleFactor
 240            {
 0241                OnCursorFarFromParcel?.Invoke();
 242            }
 0243        }
 244
 0245        private void OnKernelConfigChanged(KernelConfigModel current, KernelConfigModel previous) { validWorldRanges = c
 246
 247        bool CoordinatesAreInsideTheWorld(int xCoord, int yCoord)
 248        {
 0249            foreach (WorldRange worldRange in validWorldRanges)
 250            {
 0251                if (worldRange.Contains(xCoord, yCoord))
 252                {
 0253                    return true;
 254                }
 255            }
 0256            return false;
 0257        }
 258
 259        private void MapRenderer_OnSceneInfoUpdated(MinimapMetadata.MinimapSceneInfo sceneInfo)
 260        {
 3261            if (!sceneInfo.isPOI)
 2262                return;
 263
 1264            if (scenesOfInterest.Contains(sceneInfo))
 0265                return;
 266
 1267            scenesOfInterest.Add(sceneInfo);
 268
 1269            GameObject go = Object.Instantiate(scenesOfInterestIconPrefab.gameObject, overlayContainer.transform);
 270
 1271            Vector2 centerTile = Vector2.zero;
 272
 10273            foreach (var parcel in sceneInfo.parcels)
 274            {
 4275                centerTile += parcel;
 276            }
 277
 1278            centerTile /= (float)sceneInfo.parcels.Count;
 279
 1280            (go.transform as RectTransform).anchoredPosition = MapUtils.GetTileToLocalPosition(centerTile.x, centerTile.
 281
 1282            MapSceneIcon icon = go.GetComponent<MapSceneIcon>();
 283
 1284            if (icon.title != null)
 1285                icon.title.text = sceneInfo.name;
 286
 1287            scenesOfInterestMarkers.Add(sceneInfo, go);
 1288        }
 289
 290        private void OnOtherPlayersAdded(string userId, Player player)
 291        {
 0292            var poolable = usersInfoPool.Get();
 0293            var marker = poolable.gameObject.GetComponent<MapUserIcon>();
 0294            marker.gameObject.name = $"UserIcon-{player.name}";
 0295            marker.gameObject.transform.SetParent(overlayContainer.transform, true);
 0296            marker.Populate(player);
 0297            usersInfoMarkers.Add(userId, poolable);
 0298        }
 299
 300        private void OnOtherPlayerRemoved(string userId, Player player)
 301        {
 0302            if (!usersInfoMarkers.TryGetValue(userId, out PoolableObject go))
 303            {
 0304                return;
 305            }
 306
 0307            usersInfoPool.Release(go);
 0308            usersInfoMarkers.Remove(userId);
 0309        }
 310
 311        private void ConfigureUserIcon(GameObject iconGO, Vector3 pos)
 312        {
 0313            var gridPosition = Utils.WorldToGridPositionUnclamped(pos);
 0314            iconGO.transform.localPosition = MapUtils.GetTileToLocalPosition(gridPosition.x, gridPosition.y);
 0315        }
 316
 317        private void OnCharacterMove(Vector3 current, Vector3 previous)
 318        {
 10319            current.y = 0;
 10320            previous.y = 0;
 321
 10322            if (Vector3.Distance(current, previous) < 0.1f)
 10323                return;
 324
 0325            UpdateRendering(Utils.WorldToGridPositionUnclamped(current));
 0326        }
 327
 0328        private void OnCharacterRotate(Vector3 current, Vector3 previous) { UpdateRendering(Utils.WorldToGridPositionUnc
 329
 330        public void OnCharacterSetPosition(Vector2Int newCoords, Vector2Int oldCoords)
 331        {
 0332            if (oldCoords == newCoords)
 0333                return;
 334
 0335            UpdateRendering(new Vector2((float)newCoords.x, (float)newCoords.y));
 0336        }
 337
 338        public void UpdateRendering(Vector2 newCoords)
 339        {
 0340            UpdateBackgroundLayer(newCoords);
 0341            UpdateSelectionLayer();
 0342            UpdateOverlayLayer();
 0343        }
 344
 0345        void UpdateBackgroundLayer(Vector2 newCoords) { atlas.CenterToTile(newCoords); }
 346
 347        void UpdateSelectionLayer()
 348        {
 349            //TODO(Brian): Build and place here the scene highlight if applicable.
 0350        }
 351
 352        void UpdateOverlayLayer()
 353        {
 354            //NOTE(Brian): Player icon
 0355            Vector3 f = CommonScriptableObjects.cameraForward.Get();
 0356            Quaternion playerAngle = Quaternion.Euler(0, 0, Mathf.Atan2(-f.x, f.z) * Mathf.Rad2Deg);
 357
 0358            var gridPosition = playerGridPosition;
 0359            playerPositionIcon.anchoredPosition = MapUtils.GetTileToLocalPosition(gridPosition.x, gridPosition.y);
 0360            playerPositionIcon.rotation = playerAngle;
 0361        }
 362
 0363        public Vector3 GetViewportCenter() { return atlas.viewport.TransformPoint(atlas.viewport.rect.center); }
 364
 365        // Called by the parcelhighlight image button
 366        public void ClickMousePositionParcel()
 367        {
 0368            highlightedParcelText.text = string.Empty;
 0369            lastClickedCursorMapCoords = new Vector3((int)cursorMapCoords.x, (int)cursorMapCoords.y, 0);
 0370            OnParcelClicked?.Invoke((int)cursorMapCoords.x, (int)cursorMapCoords.y);
 0371        }
 372    }
 373}