< Summary

Class:DCL.MapRenderer
Assembly:MapRenderer
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/MapRenderer/MapRenderer.cs
Covered lines:110
Uncovered lines:62
Coverable lines:172
Total lines:396
Line coverage:63.9% (110 of 172)
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%4.052020%
UpdateCursorMapCoords()0%6200%
IsCursorOverMapChunk()0%6200%
UpdateParcelHighlight()0%90900%
UpdateParcelHold()0%42600%
OnKernelConfigChanged(...)0%110100%
CoordinatesAreInsideTheWorld(...)0%12300%
MapRenderer_OnSceneInfoUpdated(...)0%55094.44%
MapRenderer_OnUserInfoUpdated(...)0%220100%
MapRenderer_OnUserInfoRemoved(...)0%2.032080%
ConfigureUserIcon(...)0%110100%
OnCharacterMove(...)0%220100%
OnCharacterRotate(...)0%110100%
OnCharacterSetPosition(...)0%6200%
UpdateRendering(...)0%110100%
UpdateBackgroundLayer(...)0%110100%
UpdateSelectionLayer()0%2100%
UpdateOverlayLayer()0%110100%
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 int NAVMAP_CHUNK_LAYER;
 21
 022        public static MapRenderer i { get; private set; }
 23
 21624        [SerializeField] private float parcelHightlightScale = 1.25f;
 21625        [SerializeField] private float parcelHoldTimeInSeconds = 1f;
 26        [SerializeField] private Button ParcelHighlightButton;
 27        private float parcelSizeInMap;
 87228        private Vector3Variable playerWorldPosition => CommonScriptableObjects.playerWorldPosition;
 70929        private Vector3Variable playerRotation => CommonScriptableObjects.cameraForward;
 21630        private Vector3[] mapWorldspaceCorners = new Vector3[4];
 31        private Vector3 worldCoordsOriginInMap;
 32        private Vector3 lastCursorMapCoords;
 33        private float parcelHoldCountdown;
 21634        private List<RaycastResult> uiRaycastResults = new List<RaycastResult>();
 21635        private PointerEventData uiRaycastPointerEventData = new PointerEventData(EventSystem.current);
 36
 37        [HideInInspector] public Vector3 cursorMapCoords;
 21638        [HideInInspector] public bool showCursorCoords = true;
 13839        public Vector3 playerGridPosition => Utils.WorldToGridPositionUnclamped(playerWorldPosition.Get());
 40        public MapAtlas atlas;
 41        public RawImage parcelHighlightImage;
 42        public TextMeshProUGUI highlightedParcelText;
 43        public Transform overlayContainer;
 44        public Transform globalUserMarkerContainer;
 45
 46        public Image playerPositionIcon;
 47
 48        // Used as a reference of the coordinates origin in-map and as a parcel width/height reference
 49        public RectTransform centeredReferenceParcel;
 50
 51        public MapSceneIcon scenesOfInterestIconPrefab;
 52        public MapSceneIcon userIconPrefab;
 53        public UserMarkerObject globalUserMarkerPrefab;
 54
 055        public MapGlobalUsersPositionMarkerController usersPositionMarkerController { private set; get; }
 56
 21657        private HashSet<MinimapMetadata.MinimapSceneInfo> scenesOfInterest = new HashSet<MinimapMetadata.MinimapSceneInf
 21658        private Dictionary<MinimapMetadata.MinimapSceneInfo, GameObject> scenesOfInterestMarkers = new Dictionary<Minima
 21659        private Dictionary<string, PoolableObject> usersInfoMarkers = new Dictionary<string, PoolableObject>();
 60
 61        private Pool usersInfoPool;
 62
 63        private bool parcelHighlightEnabledValue = false;
 64
 21665        List<WorldRange> validWorldRanges = new List<WorldRange>
 66        {
 67            new WorldRange(-150, -150, 150, 150) // default range
 68        };
 69
 70        public bool parcelHighlightEnabled
 71        {
 72            set
 73            {
 174                parcelHighlightEnabledValue = value;
 175                parcelHighlightImage.gameObject.SetActive(parcelHighlightEnabledValue);
 176            }
 077            get { return parcelHighlightEnabledValue; }
 78        }
 79
 80        public static System.Action<int, int> OnParcelClicked;
 81        public static System.Action<int, int> OnParcelHold;
 82        public static System.Action OnParcelHoldCancel;
 83
 84        private bool isInitialized = false;
 85
 86        [HideInInspector]
 87        public event System.Action OnMovedParcelCursor;
 88
 89        private void Awake()
 90        {
 10891            i = this;
 10892            Initialize();
 10893        }
 94
 95        public void Initialize()
 96        {
 11097            if (isInitialized)
 198                return;
 99
 109100            isInitialized = true;
 109101            EnsurePools();
 109102            atlas.InitializeChunks();
 103
 109104            NAVMAP_CHUNK_LAYER = LayerMask.NameToLayer("NavmapChunk");
 105
 109106            MinimapMetadata.GetMetadata().OnSceneInfoUpdated += MapRenderer_OnSceneInfoUpdated;
 109107            MinimapMetadata.GetMetadata().OnUserInfoUpdated += MapRenderer_OnUserInfoUpdated;
 109108            MinimapMetadata.GetMetadata().OnUserInfoRemoved += MapRenderer_OnUserInfoRemoved;
 109
 109110            ParcelHighlightButton.onClick.AddListener(ClickMousePositionParcel);
 111
 109112            playerWorldPosition.OnChange += OnCharacterMove;
 109113            playerRotation.OnChange += OnCharacterRotate;
 114
 109115            parcelHighlightImage.rectTransform.localScale = new Vector3(parcelHightlightScale, parcelHightlightScale, 1f
 116
 109117            parcelHoldCountdown = parcelHoldTimeInSeconds;
 118
 109119            usersPositionMarkerController = new MapGlobalUsersPositionMarkerController(globalUserMarkerPrefab,
 120                globalUserMarkerContainer,
 121                MapUtils.GetTileToLocalPosition);
 122
 109123            usersPositionMarkerController.SetUpdateMode(MapGlobalUsersPositionMarkerController.UpdateMode.BACKGROUND);
 124
 109125            KernelConfig.i.OnChange += OnKernelConfigChanged;
 109126        }
 127
 128        private void EnsurePools()
 129        {
 109130            usersInfoPool = PoolManager.i.GetPool(MINIMAP_USER_ICONS_POOL_NAME);
 131
 109132            if (usersInfoPool == null)
 133            {
 106134                usersInfoPool = PoolManager.i.AddPool(
 135                    MINIMAP_USER_ICONS_POOL_NAME,
 136                    Instantiate(userIconPrefab.gameObject, overlayContainer.transform),
 137                    maxPrewarmCount: MINIMAP_USER_ICONS_MAX_PREWARM,
 138                    isPersistent: true);
 139
 106140                if (!Configuration.EnvironmentSettings.RUNNING_TESTS)
 0141                    usersInfoPool.ForcePrewarm();
 142            }
 109143        }
 144
 214145        public void OnDestroy() { Cleanup(); }
 146
 147        public void Cleanup()
 148        {
 600149            if (atlas != null)
 600150                atlas.Cleanup();
 151
 1202152            foreach (var kvp in scenesOfInterestMarkers)
 153            {
 1154                if (kvp.Value != null)
 1155                    Destroy(kvp.Value);
 156            }
 157
 600158            scenesOfInterestMarkers.Clear();
 159
 600160            playerWorldPosition.OnChange -= OnCharacterMove;
 600161            playerRotation.OnChange -= OnCharacterRotate;
 600162            MinimapMetadata.GetMetadata().OnSceneInfoUpdated -= MapRenderer_OnSceneInfoUpdated;
 600163            MinimapMetadata.GetMetadata().OnUserInfoUpdated -= MapRenderer_OnUserInfoUpdated;
 600164            MinimapMetadata.GetMetadata().OnUserInfoRemoved -= MapRenderer_OnUserInfoRemoved;
 165
 600166            ParcelHighlightButton.onClick.RemoveListener(ClickMousePositionParcel);
 167
 600168            usersPositionMarkerController?.Dispose();
 169
 600170            KernelConfig.i.OnChange -= OnKernelConfigChanged;
 171
 600172            isInitialized = false;
 600173        }
 174
 175        void Update()
 176        {
 13115177            if (!parcelHighlightEnabled)
 13115178                return;
 179
 0180            parcelSizeInMap = centeredReferenceParcel.rect.width * centeredReferenceParcel.lossyScale.x;
 181
 182            // the reference parcel has a bottom-left pivot
 0183            centeredReferenceParcel.GetWorldCorners(mapWorldspaceCorners);
 0184            worldCoordsOriginInMap = mapWorldspaceCorners[0];
 185
 0186            UpdateCursorMapCoords();
 187
 0188            UpdateParcelHighlight();
 189
 0190            UpdateParcelHold();
 191
 0192            lastCursorMapCoords = cursorMapCoords;
 0193        }
 194
 195        void UpdateCursorMapCoords()
 196        {
 0197            if (!IsCursorOverMapChunk())
 0198                return;
 199
 0200            cursorMapCoords = Input.mousePosition - worldCoordsOriginInMap;
 0201            cursorMapCoords = cursorMapCoords / parcelSizeInMap;
 202
 0203            cursorMapCoords.x = (int)Mathf.Floor(cursorMapCoords.x);
 0204            cursorMapCoords.y = (int)Mathf.Floor(cursorMapCoords.y);
 0205        }
 206
 207        bool IsCursorOverMapChunk()
 208        {
 0209            uiRaycastPointerEventData.position = Input.mousePosition;
 0210            EventSystem.current.RaycastAll(uiRaycastPointerEventData, uiRaycastResults);
 211
 0212            return uiRaycastResults.Count > 0 && uiRaycastResults[0].gameObject.layer == NAVMAP_CHUNK_LAYER;
 213        }
 214
 215        void UpdateParcelHighlight()
 216        {
 0217            if (!CoordinatesAreInsideTheWorld((int)cursorMapCoords.x, (int)cursorMapCoords.y))
 218            {
 0219                if (parcelHighlightImage.gameObject.activeSelf)
 0220                    parcelHighlightImage.gameObject.SetActive(false);
 221
 0222                return;
 223            }
 224
 0225            if (!parcelHighlightImage.gameObject.activeSelf)
 0226                parcelHighlightImage.gameObject.SetActive(true);
 227
 0228            string previousText = highlightedParcelText.text;
 0229            parcelHighlightImage.transform.position = worldCoordsOriginInMap + cursorMapCoords * parcelSizeInMap + new V
 0230            highlightedParcelText.text = showCursorCoords ? $"{cursorMapCoords.x}, {cursorMapCoords.y}" : string.Empty;
 231
 0232            if (highlightedParcelText.text != previousText && !Input.GetMouseButton(0))
 233            {
 0234                OnMovedParcelCursor?.Invoke();
 235            }
 236
 237            // ----------------------------------------------------
 238            // TODO: Use sceneInfo to highlight whole scene parcels and populate scenes hover info on navmap once we can
 239            // var sceneInfo = mapMetadata.GetSceneInfo(cursorMapCoords.x, cursorMapCoords.y);
 0240        }
 241
 242        void UpdateParcelHold()
 243        {
 0244            if (cursorMapCoords == lastCursorMapCoords)
 245            {
 0246                if (parcelHoldCountdown <= 0f)
 0247                    return;
 248
 0249                parcelHoldCountdown -= Time.deltaTime;
 250
 0251                if (parcelHoldCountdown <= 0)
 252                {
 0253                    parcelHoldCountdown = 0f;
 0254                    highlightedParcelText.text = string.Empty;
 0255                    OnParcelHold?.Invoke((int)cursorMapCoords.x, (int)cursorMapCoords.y);
 256                }
 0257            }
 258            else
 259            {
 0260                parcelHoldCountdown = parcelHoldTimeInSeconds;
 0261                OnParcelHoldCancel?.Invoke();
 262            }
 0263        }
 264
 10265        private void OnKernelConfigChanged(KernelConfigModel current, KernelConfigModel previous) { validWorldRanges = c
 266
 267        bool CoordinatesAreInsideTheWorld(int xCoord, int yCoord)
 268        {
 0269            foreach (WorldRange worldRange in validWorldRanges)
 270            {
 0271                if (worldRange.Contains(xCoord, yCoord))
 272                {
 0273                    return true;
 274                }
 275            }
 0276            return false;
 0277        }
 278
 279        private void MapRenderer_OnSceneInfoUpdated(MinimapMetadata.MinimapSceneInfo sceneInfo)
 280        {
 5281            if (!sceneInfo.isPOI)
 4282                return;
 283
 1284            if (scenesOfInterest.Contains(sceneInfo))
 0285                return;
 286
 1287            scenesOfInterest.Add(sceneInfo);
 288
 1289            GameObject go = Object.Instantiate(scenesOfInterestIconPrefab.gameObject, overlayContainer.transform);
 290
 1291            Vector2 centerTile = Vector2.zero;
 292
 10293            foreach (var parcel in sceneInfo.parcels)
 294            {
 4295                centerTile += parcel;
 296            }
 297
 1298            centerTile /= (float)sceneInfo.parcels.Count;
 299
 1300            (go.transform as RectTransform).anchoredPosition = MapUtils.GetTileToLocalPosition(centerTile.x, centerTile.
 301
 1302            MapSceneIcon icon = go.GetComponent<MapSceneIcon>();
 303
 1304            if (icon.title != null)
 1305                icon.title.text = sceneInfo.name;
 306
 1307            scenesOfInterestMarkers.Add(sceneInfo, go);
 1308        }
 309
 310        private void MapRenderer_OnUserInfoUpdated(MinimapMetadata.MinimapUserInfo userInfo)
 311        {
 5312            if (!usersInfoMarkers.TryGetValue(userInfo.userId, out PoolableObject marker))
 313            {
 4314                marker = usersInfoPool.Get();
 4315                marker.gameObject.name = $"UserIcon-{userInfo.userName}";
 4316                marker.gameObject.transform.SetParent(overlayContainer.transform, true);
 4317                marker.gameObject.transform.localScale = Vector3.one;
 4318                usersInfoMarkers.Add(userInfo.userId, marker);
 319            }
 320
 5321            ConfigureUserIcon(marker.gameObject, userInfo.worldPosition);
 5322        }
 323
 324        private void MapRenderer_OnUserInfoRemoved(string userId)
 325        {
 3326            if (!usersInfoMarkers.TryGetValue(userId, out PoolableObject go))
 327            {
 0328                return;
 329            }
 330
 3331            usersInfoPool.Release(go);
 3332            usersInfoMarkers.Remove(userId);
 3333        }
 334
 335        private void ConfigureUserIcon(GameObject iconGO, Vector3 pos)
 336        {
 5337            var gridPosition = Utils.WorldToGridPositionUnclamped(pos);
 5338            iconGO.transform.localPosition = MapUtils.GetTileToLocalPosition(gridPosition.x, gridPosition.y);
 5339        }
 340
 341        private void OnCharacterMove(Vector3 current, Vector3 previous)
 342        {
 886343            current.y = 0;
 886344            previous.y = 0;
 345
 886346            if (Vector3.Distance(current, previous) < 0.1f)
 773347                return;
 348
 113349            UpdateRendering(Utils.WorldToGridPositionUnclamped(current));
 113350        }
 351
 50352        private void OnCharacterRotate(Vector3 current, Vector3 previous) { UpdateRendering(Utils.WorldToGridPositionUnc
 353
 354        public void OnCharacterSetPosition(Vector2Int newCoords, Vector2Int oldCoords)
 355        {
 0356            if (oldCoords == newCoords)
 0357                return;
 358
 0359            UpdateRendering(new Vector2((float)newCoords.x, (float)newCoords.y));
 0360        }
 361
 362        public void UpdateRendering(Vector2 newCoords)
 363        {
 138364            UpdateBackgroundLayer(newCoords);
 138365            UpdateSelectionLayer();
 138366            UpdateOverlayLayer();
 138367        }
 368
 276369        void UpdateBackgroundLayer(Vector2 newCoords) { atlas.CenterToTile(newCoords); }
 370
 371        void UpdateSelectionLayer()
 372        {
 373            //TODO(Brian): Build and place here the scene highlight if applicable.
 0374        }
 375
 376        void UpdateOverlayLayer()
 377        {
 378            //NOTE(Brian): Player icon
 138379            Vector3 f = CommonScriptableObjects.cameraForward.Get();
 138380            Quaternion playerAngle = Quaternion.Euler(0, 0, Mathf.Atan2(-f.x, f.z) * Mathf.Rad2Deg);
 381
 138382            var gridPosition = this.playerGridPosition;
 138383            playerPositionIcon.transform.localPosition = MapUtils.GetTileToLocalPosition(gridPosition.x, gridPosition.y)
 138384            playerPositionIcon.transform.rotation = playerAngle;
 138385        }
 386
 0387        public Vector3 GetViewportCenter() { return atlas.viewport.TransformPoint(atlas.viewport.rect.center); }
 388
 389        // Called by the parcelhighlight image button
 390        public void ClickMousePositionParcel()
 391        {
 0392            highlightedParcelText.text = string.Empty;
 0393            OnParcelClicked?.Invoke((int)cursorMapCoords.x, (int)cursorMapCoords.y);
 0394        }
 395    }
 396}