< Summary

Class:DCL.MapRenderer
Assembly:MapRenderer
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/MapRenderer/MapRenderer.cs
Covered lines:107
Uncovered lines:66
Coverable lines:173
Total lines:395
Line coverage:61.8% (107 of 173)
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%
OnOtherPlayersAdded(...)0%110100%
OnOtherPlayerRemoved(...)0%2.032080%
ConfigureUserIcon(...)0%2100%
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
 22624        [SerializeField] private float parcelHightlightScale = 1.25f;
 22625        [SerializeField] private float parcelHoldTimeInSeconds = 1f;
 26        [SerializeField] private Button ParcelHighlightButton;
 27        private float parcelSizeInMap;
 140828        private Vector3Variable playerWorldPosition => CommonScriptableObjects.playerWorldPosition;
 85929        private Vector3Variable playerRotation => CommonScriptableObjects.cameraForward;
 22630        private Vector3[] mapWorldspaceCorners = new Vector3[4];
 31        private Vector3 worldCoordsOriginInMap;
 32        private Vector3 lastCursorMapCoords;
 33        private float parcelHoldCountdown;
 22634        private List<RaycastResult> uiRaycastResults = new List<RaycastResult>();
 22635        private PointerEventData uiRaycastPointerEventData = new PointerEventData(EventSystem.current);
 36
 37        [HideInInspector] public Vector3 cursorMapCoords;
 22638        [HideInInspector] public bool showCursorCoords = true;
 29239        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 RectTransform 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 GameObject userIconPrefab;
 53        public UserMarkerObject globalUserMarkerPrefab;
 54
 055        public MapGlobalUsersPositionMarkerController usersPositionMarkerController { private set; get; }
 56
 22657        private HashSet<MinimapMetadata.MinimapSceneInfo> scenesOfInterest = new HashSet<MinimapMetadata.MinimapSceneInf
 22658        private Dictionary<MinimapMetadata.MinimapSceneInfo, GameObject> scenesOfInterestMarkers = new Dictionary<Minima
 22659        private Dictionary<string, PoolableObject> usersInfoMarkers = new Dictionary<string, PoolableObject>();
 60
 61        private Pool usersInfoPool;
 62
 63        private bool parcelHighlightEnabledValue = false;
 64
 22665        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            {
 274                parcelHighlightEnabledValue = value;
 275                parcelHighlightImage.gameObject.SetActive(parcelHighlightEnabledValue);
 276            }
 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
 22684        private BaseDictionary<string, Player> otherPlayers => DataStore.i.player.otherPlayers;
 85
 86        private bool isInitialized = false;
 87
 88        [HideInInspector]
 89        public event System.Action OnMovedParcelCursor;
 90
 91        private void Awake()
 92        {
 11393            i = this;
 11394            Initialize();
 11395        }
 96
 97        public void Initialize()
 98        {
 11499            if (isInitialized)
 1100                return;
 101
 113102            isInitialized = true;
 113103            EnsurePools();
 113104            atlas.InitializeChunks();
 105
 113106            NAVMAP_CHUNK_LAYER = LayerMask.NameToLayer("NavmapChunk");
 107
 113108            MinimapMetadata.GetMetadata().OnSceneInfoUpdated += MapRenderer_OnSceneInfoUpdated;
 113109            otherPlayers.OnAdded += OnOtherPlayersAdded;
 113110            otherPlayers.OnRemoved += OnOtherPlayerRemoved;
 111
 113112            ParcelHighlightButton.onClick.AddListener(ClickMousePositionParcel);
 113
 113114            playerWorldPosition.OnChange += OnCharacterMove;
 113115            playerRotation.OnChange += OnCharacterRotate;
 116
 113117            parcelHighlightImage.rectTransform.localScale = new Vector3(parcelHightlightScale, parcelHightlightScale, 1f
 118
 113119            parcelHoldCountdown = parcelHoldTimeInSeconds;
 120
 113121            usersPositionMarkerController = new MapGlobalUsersPositionMarkerController(globalUserMarkerPrefab,
 122                globalUserMarkerContainer,
 123                MapUtils.GetTileToLocalPosition);
 124
 113125            usersPositionMarkerController.SetUpdateMode(MapGlobalUsersPositionMarkerController.UpdateMode.BACKGROUND);
 126
 113127            KernelConfig.i.OnChange += OnKernelConfigChanged;
 113128        }
 129
 130        private void EnsurePools()
 131        {
 113132            usersInfoPool = PoolManager.i.GetPool(MINIMAP_USER_ICONS_POOL_NAME);
 133
 113134            if (usersInfoPool == null)
 135            {
 110136                usersInfoPool = PoolManager.i.AddPool(
 137                    MINIMAP_USER_ICONS_POOL_NAME,
 138                    Instantiate(userIconPrefab.gameObject, overlayContainer.transform),
 139                    maxPrewarmCount: MINIMAP_USER_ICONS_MAX_PREWARM,
 140                    isPersistent: true);
 141
 110142                if (!Configuration.EnvironmentSettings.RUNNING_TESTS)
 0143                    usersInfoPool.ForcePrewarm();
 144            }
 113145        }
 146
 224147        public void OnDestroy() { Cleanup(); }
 148
 149        public void Cleanup()
 150        {
 746151            if (atlas != null)
 746152                atlas.Cleanup();
 153
 1494154            foreach (var kvp in scenesOfInterestMarkers)
 155            {
 1156                if (kvp.Value != null)
 1157                    Destroy(kvp.Value);
 158            }
 159
 746160            scenesOfInterestMarkers.Clear();
 161
 746162            playerWorldPosition.OnChange -= OnCharacterMove;
 746163            playerRotation.OnChange -= OnCharacterRotate;
 746164            MinimapMetadata.GetMetadata().OnSceneInfoUpdated -= MapRenderer_OnSceneInfoUpdated;
 746165            otherPlayers.OnAdded -= OnOtherPlayersAdded;
 746166            otherPlayers.OnRemoved -= OnOtherPlayerRemoved;
 167
 746168            ParcelHighlightButton.onClick.RemoveListener(ClickMousePositionParcel);
 169
 746170            usersPositionMarkerController?.Dispose();
 171
 746172            KernelConfig.i.OnChange -= OnKernelConfigChanged;
 173
 746174            isInitialized = false;
 746175        }
 176
 177        void Update()
 178        {
 20363179            if (!parcelHighlightEnabled)
 20363180                return;
 181
 0182            parcelSizeInMap = centeredReferenceParcel.rect.width * centeredReferenceParcel.lossyScale.x;
 183
 184            // the reference parcel has a bottom-left pivot
 0185            centeredReferenceParcel.GetWorldCorners(mapWorldspaceCorners);
 0186            worldCoordsOriginInMap = mapWorldspaceCorners[0];
 187
 0188            UpdateCursorMapCoords();
 189
 0190            UpdateParcelHighlight();
 191
 0192            UpdateParcelHold();
 193
 0194            lastCursorMapCoords = cursorMapCoords;
 0195        }
 196
 197        void UpdateCursorMapCoords()
 198        {
 0199            if (!IsCursorOverMapChunk())
 0200                return;
 201
 0202            cursorMapCoords = Input.mousePosition - worldCoordsOriginInMap;
 0203            cursorMapCoords = cursorMapCoords / parcelSizeInMap;
 204
 0205            cursorMapCoords.x = (int)Mathf.Floor(cursorMapCoords.x);
 0206            cursorMapCoords.y = (int)Mathf.Floor(cursorMapCoords.y);
 0207        }
 208
 209        bool IsCursorOverMapChunk()
 210        {
 0211            uiRaycastPointerEventData.position = Input.mousePosition;
 0212            EventSystem.current.RaycastAll(uiRaycastPointerEventData, uiRaycastResults);
 213
 0214            return uiRaycastResults.Count > 0 && uiRaycastResults[0].gameObject.layer == NAVMAP_CHUNK_LAYER;
 215        }
 216
 217        void UpdateParcelHighlight()
 218        {
 0219            if (!CoordinatesAreInsideTheWorld((int)cursorMapCoords.x, (int)cursorMapCoords.y))
 220            {
 0221                if (parcelHighlightImage.gameObject.activeSelf)
 0222                    parcelHighlightImage.gameObject.SetActive(false);
 223
 0224                return;
 225            }
 226
 0227            if (!parcelHighlightImage.gameObject.activeSelf)
 0228                parcelHighlightImage.gameObject.SetActive(true);
 229
 0230            string previousText = highlightedParcelText.text;
 0231            parcelHighlightImage.rectTransform.SetAsLastSibling();
 0232            parcelHighlightImage.rectTransform.anchoredPosition = MapUtils.GetTileToLocalPosition(cursorMapCoords.x, cur
 0233            highlightedParcelText.text = showCursorCoords ? $"{cursorMapCoords.x}, {cursorMapCoords.y}" : string.Empty;
 234
 0235            if (highlightedParcelText.text != previousText && !Input.GetMouseButton(0))
 236            {
 0237                OnMovedParcelCursor?.Invoke();
 238            }
 239
 240            // ----------------------------------------------------
 241            // TODO: Use sceneInfo to highlight whole scene parcels and populate scenes hover info on navmap once we can
 242            // var sceneInfo = mapMetadata.GetSceneInfo(cursorMapCoords.x, cursorMapCoords.y);
 0243        }
 244
 245        void UpdateParcelHold()
 246        {
 0247            if (cursorMapCoords == lastCursorMapCoords)
 248            {
 0249                if (parcelHoldCountdown <= 0f)
 0250                    return;
 251
 0252                parcelHoldCountdown -= Time.deltaTime;
 253
 0254                if (parcelHoldCountdown <= 0)
 255                {
 0256                    parcelHoldCountdown = 0f;
 0257                    highlightedParcelText.text = string.Empty;
 0258                    OnParcelHold?.Invoke((int)cursorMapCoords.x, (int)cursorMapCoords.y);
 259                }
 0260            }
 261            else
 262            {
 0263                parcelHoldCountdown = parcelHoldTimeInSeconds;
 0264                OnParcelHoldCancel?.Invoke();
 265            }
 0266        }
 267
 10268        private void OnKernelConfigChanged(KernelConfigModel current, KernelConfigModel previous) { validWorldRanges = c
 269
 270        bool CoordinatesAreInsideTheWorld(int xCoord, int yCoord)
 271        {
 0272            foreach (WorldRange worldRange in validWorldRanges)
 273            {
 0274                if (worldRange.Contains(xCoord, yCoord))
 275                {
 0276                    return true;
 277                }
 278            }
 0279            return false;
 0280        }
 281
 282        private void MapRenderer_OnSceneInfoUpdated(MinimapMetadata.MinimapSceneInfo sceneInfo)
 283        {
 5284            if (!sceneInfo.isPOI)
 4285                return;
 286
 1287            if (scenesOfInterest.Contains(sceneInfo))
 0288                return;
 289
 1290            scenesOfInterest.Add(sceneInfo);
 291
 1292            GameObject go = Object.Instantiate(scenesOfInterestIconPrefab.gameObject, overlayContainer.transform);
 293
 1294            Vector2 centerTile = Vector2.zero;
 295
 10296            foreach (var parcel in sceneInfo.parcels)
 297            {
 4298                centerTile += parcel;
 299            }
 300
 1301            centerTile /= (float)sceneInfo.parcels.Count;
 302
 1303            (go.transform as RectTransform).anchoredPosition = MapUtils.GetTileToLocalPosition(centerTile.x, centerTile.
 304
 1305            MapSceneIcon icon = go.GetComponent<MapSceneIcon>();
 306
 1307            if (icon.title != null)
 1308                icon.title.text = sceneInfo.name;
 309
 1310            scenesOfInterestMarkers.Add(sceneInfo, go);
 1311        }
 312
 313        private void OnOtherPlayersAdded(string userId, Player player)
 314        {
 3315            var poolable = usersInfoPool.Get();
 3316            var marker = poolable.gameObject.GetComponent<MapUserIcon>();
 3317            marker.gameObject.name = $"UserIcon-{player.name}";
 3318            marker.gameObject.transform.SetParent(overlayContainer.transform, true);
 3319            marker.Populate(player);
 3320            usersInfoMarkers.Add(userId, poolable);
 3321        }
 322
 323        private void OnOtherPlayerRemoved(string userId, Player player)
 324        {
 2325            if (!usersInfoMarkers.TryGetValue(userId, out PoolableObject go))
 326            {
 0327                return;
 328            }
 329
 2330            usersInfoPool.Release(go);
 2331            usersInfoMarkers.Remove(userId);
 2332        }
 333
 334        private void ConfigureUserIcon(GameObject iconGO, Vector3 pos)
 335        {
 0336            var gridPosition = Utils.WorldToGridPositionUnclamped(pos);
 0337            iconGO.transform.localPosition = MapUtils.GetTileToLocalPosition(gridPosition.x, gridPosition.y);
 0338        }
 339
 340        private void OnCharacterMove(Vector3 current, Vector3 previous)
 341        {
 1117342            current.y = 0;
 1117343            previous.y = 0;
 344
 1117345            if (Vector3.Distance(current, previous) < 0.1f)
 1082346                return;
 347
 35348            UpdateRendering(Utils.WorldToGridPositionUnclamped(current));
 35349        }
 350
 514351        private void OnCharacterRotate(Vector3 current, Vector3 previous) { UpdateRendering(Utils.WorldToGridPositionUnc
 352
 353        public void OnCharacterSetPosition(Vector2Int newCoords, Vector2Int oldCoords)
 354        {
 0355            if (oldCoords == newCoords)
 0356                return;
 357
 0358            UpdateRendering(new Vector2((float)newCoords.x, (float)newCoords.y));
 0359        }
 360
 361        public void UpdateRendering(Vector2 newCoords)
 362        {
 292363            UpdateBackgroundLayer(newCoords);
 292364            UpdateSelectionLayer();
 292365            UpdateOverlayLayer();
 292366        }
 367
 584368        void UpdateBackgroundLayer(Vector2 newCoords) { atlas.CenterToTile(newCoords); }
 369
 370        void UpdateSelectionLayer()
 371        {
 372            //TODO(Brian): Build and place here the scene highlight if applicable.
 0373        }
 374
 375        void UpdateOverlayLayer()
 376        {
 377            //NOTE(Brian): Player icon
 292378            Vector3 f = CommonScriptableObjects.cameraForward.Get();
 292379            Quaternion playerAngle = Quaternion.Euler(0, 0, Mathf.Atan2(-f.x, f.z) * Mathf.Rad2Deg);
 380
 292381            var gridPosition = playerGridPosition;
 292382            playerPositionIcon.anchoredPosition = MapUtils.GetTileToLocalPosition(gridPosition.x, gridPosition.y);
 292383            playerPositionIcon.rotation = playerAngle;
 292384        }
 385
 0386        public Vector3 GetViewportCenter() { return atlas.viewport.TransformPoint(atlas.viewport.rect.center); }
 387
 388        // Called by the parcelhighlight image button
 389        public void ClickMousePositionParcel()
 390        {
 0391            highlightedParcelText.text = string.Empty;
 0392            OnParcelClicked?.Invoke((int)cursorMapCoords.x, (int)cursorMapCoords.y);
 0393        }
 394    }
 395}