< Summary

Class:DCL.MapRenderer
Assembly:MapRenderer
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/MapRenderer/MapRenderer.cs
Covered lines:106
Uncovered lines:66
Coverable lines:172
Total lines:394
Line coverage:61.6% (106 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%
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
 22224        [SerializeField] private float parcelHightlightScale = 1.25f;
 22225        [SerializeField] private float parcelHoldTimeInSeconds = 1f;
 26        [SerializeField] private Button ParcelHighlightButton;
 27        private float parcelSizeInMap;
 152328        private Vector3Variable playerWorldPosition => CommonScriptableObjects.playerWorldPosition;
 84829        private Vector3Variable playerRotation => CommonScriptableObjects.cameraForward;
 22230        private Vector3[] mapWorldspaceCorners = new Vector3[4];
 31        private Vector3 worldCoordsOriginInMap;
 32        private Vector3 lastCursorMapCoords;
 33        private float parcelHoldCountdown;
 22234        private List<RaycastResult> uiRaycastResults = new List<RaycastResult>();
 22235        private PointerEventData uiRaycastPointerEventData = new PointerEventData(EventSystem.current);
 36
 37        [HideInInspector] public Vector3 cursorMapCoords;
 22238        [HideInInspector] public bool showCursorCoords = true;
 39539        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 GameObject userIconPrefab;
 53        public UserMarkerObject globalUserMarkerPrefab;
 54
 055        public MapGlobalUsersPositionMarkerController usersPositionMarkerController { private set; get; }
 56
 22257        private HashSet<MinimapMetadata.MinimapSceneInfo> scenesOfInterest = new HashSet<MinimapMetadata.MinimapSceneInf
 22258        private Dictionary<MinimapMetadata.MinimapSceneInfo, GameObject> scenesOfInterestMarkers = new Dictionary<Minima
 22259        private Dictionary<string, PoolableObject> usersInfoMarkers = new Dictionary<string, PoolableObject>();
 60
 61        private Pool usersInfoPool;
 62
 63        private bool parcelHighlightEnabledValue = false;
 64
 22265        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
 084        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        {
 11193            i = this;
 11194            Initialize();
 11195        }
 96
 97        public void Initialize()
 98        {
 11299            if (isInitialized)
 1100                return;
 101
 111102            isInitialized = true;
 111103            EnsurePools();
 111104            atlas.InitializeChunks();
 105
 111106            NAVMAP_CHUNK_LAYER = LayerMask.NameToLayer("NavmapChunk");
 107
 111108            MinimapMetadata.GetMetadata().OnSceneInfoUpdated += MapRenderer_OnSceneInfoUpdated;
 111109            otherPlayers.OnAdded += OnOtherPlayersAdded;
 111110            otherPlayers.OnRemoved += OnOtherPlayerRemoved;
 111
 111112            ParcelHighlightButton.onClick.AddListener(ClickMousePositionParcel);
 113
 111114            playerWorldPosition.OnChange += OnCharacterMove;
 111115            playerRotation.OnChange += OnCharacterRotate;
 116
 111117            parcelHighlightImage.rectTransform.localScale = new Vector3(parcelHightlightScale, parcelHightlightScale, 1f
 118
 111119            parcelHoldCountdown = parcelHoldTimeInSeconds;
 120
 111121            usersPositionMarkerController = new MapGlobalUsersPositionMarkerController(globalUserMarkerPrefab,
 122                globalUserMarkerContainer,
 123                MapUtils.GetTileToLocalPosition);
 124
 111125            usersPositionMarkerController.SetUpdateMode(MapGlobalUsersPositionMarkerController.UpdateMode.BACKGROUND);
 126
 111127            KernelConfig.i.OnChange += OnKernelConfigChanged;
 111128        }
 129
 130        private void EnsurePools()
 131        {
 111132            usersInfoPool = PoolManager.i.GetPool(MINIMAP_USER_ICONS_POOL_NAME);
 133
 111134            if (usersInfoPool == null)
 135            {
 108136                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
 108142                if (!Configuration.EnvironmentSettings.RUNNING_TESTS)
 0143                    usersInfoPool.ForcePrewarm();
 144            }
 111145        }
 146
 220147        public void OnDestroy() { Cleanup(); }
 148
 149        public void Cleanup()
 150        {
 737151            if (atlas != null)
 737152                atlas.Cleanup();
 153
 1476154            foreach (var kvp in scenesOfInterestMarkers)
 155            {
 1156                if (kvp.Value != null)
 1157                    Destroy(kvp.Value);
 158            }
 159
 737160            scenesOfInterestMarkers.Clear();
 161
 737162            playerWorldPosition.OnChange -= OnCharacterMove;
 737163            playerRotation.OnChange -= OnCharacterRotate;
 737164            MinimapMetadata.GetMetadata().OnSceneInfoUpdated -= MapRenderer_OnSceneInfoUpdated;
 737165            otherPlayers.OnAdded -= OnOtherPlayersAdded;
 737166            otherPlayers.OnRemoved -= OnOtherPlayerRemoved;
 167
 737168            ParcelHighlightButton.onClick.RemoveListener(ClickMousePositionParcel);
 169
 737170            usersPositionMarkerController?.Dispose();
 171
 737172            KernelConfig.i.OnChange -= OnKernelConfigChanged;
 173
 737174            isInitialized = false;
 737175        }
 176
 177        void Update()
 178        {
 20097179            if (!parcelHighlightEnabled)
 20097180                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.transform.position = worldCoordsOriginInMap + cursorMapCoords * parcelSizeInMap + new V
 0232            highlightedParcelText.text = showCursorCoords ? $"{cursorMapCoords.x}, {cursorMapCoords.y}" : string.Empty;
 233
 0234            if (highlightedParcelText.text != previousText && !Input.GetMouseButton(0))
 235            {
 0236                OnMovedParcelCursor?.Invoke();
 237            }
 238
 239            // ----------------------------------------------------
 240            // TODO: Use sceneInfo to highlight whole scene parcels and populate scenes hover info on navmap once we can
 241            // var sceneInfo = mapMetadata.GetSceneInfo(cursorMapCoords.x, cursorMapCoords.y);
 0242        }
 243
 244        void UpdateParcelHold()
 245        {
 0246            if (cursorMapCoords == lastCursorMapCoords)
 247            {
 0248                if (parcelHoldCountdown <= 0f)
 0249                    return;
 250
 0251                parcelHoldCountdown -= Time.deltaTime;
 252
 0253                if (parcelHoldCountdown <= 0)
 254                {
 0255                    parcelHoldCountdown = 0f;
 0256                    highlightedParcelText.text = string.Empty;
 0257                    OnParcelHold?.Invoke((int)cursorMapCoords.x, (int)cursorMapCoords.y);
 258                }
 0259            }
 260            else
 261            {
 0262                parcelHoldCountdown = parcelHoldTimeInSeconds;
 0263                OnParcelHoldCancel?.Invoke();
 264            }
 0265        }
 266
 10267        private void OnKernelConfigChanged(KernelConfigModel current, KernelConfigModel previous) { validWorldRanges = c
 268
 269        bool CoordinatesAreInsideTheWorld(int xCoord, int yCoord)
 270        {
 0271            foreach (WorldRange worldRange in validWorldRanges)
 272            {
 0273                if (worldRange.Contains(xCoord, yCoord))
 274                {
 0275                    return true;
 276                }
 277            }
 0278            return false;
 0279        }
 280
 281        private void MapRenderer_OnSceneInfoUpdated(MinimapMetadata.MinimapSceneInfo sceneInfo)
 282        {
 5283            if (!sceneInfo.isPOI)
 4284                return;
 285
 1286            if (scenesOfInterest.Contains(sceneInfo))
 0287                return;
 288
 1289            scenesOfInterest.Add(sceneInfo);
 290
 1291            GameObject go = Object.Instantiate(scenesOfInterestIconPrefab.gameObject, overlayContainer.transform);
 292
 1293            Vector2 centerTile = Vector2.zero;
 294
 10295            foreach (var parcel in sceneInfo.parcels)
 296            {
 4297                centerTile += parcel;
 298            }
 299
 1300            centerTile /= (float)sceneInfo.parcels.Count;
 301
 1302            (go.transform as RectTransform).anchoredPosition = MapUtils.GetTileToLocalPosition(centerTile.x, centerTile.
 303
 1304            MapSceneIcon icon = go.GetComponent<MapSceneIcon>();
 305
 1306            if (icon.title != null)
 1307                icon.title.text = sceneInfo.name;
 308
 1309            scenesOfInterestMarkers.Add(sceneInfo, go);
 1310        }
 311
 312        private void OnOtherPlayersAdded(string userId, Player player)
 313        {
 3314            var poolable = usersInfoPool.Get();
 3315            var marker = poolable.gameObject.GetComponent<MapUserIcon>();
 3316            marker.gameObject.name = $"UserIcon-{player.name}";
 3317            marker.gameObject.transform.SetParent(overlayContainer.transform, true);
 3318            marker.Populate(player);
 3319            usersInfoMarkers.Add(userId, poolable);
 3320        }
 321
 322        private void OnOtherPlayerRemoved(string userId, Player player)
 323        {
 2324            if (!usersInfoMarkers.TryGetValue(userId, out PoolableObject go))
 325            {
 0326                return;
 327            }
 328
 2329            usersInfoPool.Release(go);
 2330            usersInfoMarkers.Remove(userId);
 2331        }
 332
 333        private void ConfigureUserIcon(GameObject iconGO, Vector3 pos)
 334        {
 0335            var gridPosition = Utils.WorldToGridPositionUnclamped(pos);
 0336            iconGO.transform.localPosition = MapUtils.GetTileToLocalPosition(gridPosition.x, gridPosition.y);
 0337        }
 338
 339        private void OnCharacterMove(Vector3 current, Vector3 previous)
 340        {
 778341            current.y = 0;
 778342            previous.y = 0;
 343
 778344            if (Vector3.Distance(current, previous) < 0.1f)
 663345                return;
 346
 115347            UpdateRendering(Utils.WorldToGridPositionUnclamped(current));
 115348        }
 349
 560350        private void OnCharacterRotate(Vector3 current, Vector3 previous) { UpdateRendering(Utils.WorldToGridPositionUnc
 351
 352        public void OnCharacterSetPosition(Vector2Int newCoords, Vector2Int oldCoords)
 353        {
 0354            if (oldCoords == newCoords)
 0355                return;
 356
 0357            UpdateRendering(new Vector2((float)newCoords.x, (float)newCoords.y));
 0358        }
 359
 360        public void UpdateRendering(Vector2 newCoords)
 361        {
 395362            UpdateBackgroundLayer(newCoords);
 395363            UpdateSelectionLayer();
 395364            UpdateOverlayLayer();
 395365        }
 366
 790367        void UpdateBackgroundLayer(Vector2 newCoords) { atlas.CenterToTile(newCoords); }
 368
 369        void UpdateSelectionLayer()
 370        {
 371            //TODO(Brian): Build and place here the scene highlight if applicable.
 0372        }
 373
 374        void UpdateOverlayLayer()
 375        {
 376            //NOTE(Brian): Player icon
 395377            Vector3 f = CommonScriptableObjects.cameraForward.Get();
 395378            Quaternion playerAngle = Quaternion.Euler(0, 0, Mathf.Atan2(-f.x, f.z) * Mathf.Rad2Deg);
 379
 395380            var gridPosition = this.playerGridPosition;
 395381            playerPositionIcon.transform.localPosition = MapUtils.GetTileToLocalPosition(gridPosition.x, gridPosition.y)
 395382            playerPositionIcon.transform.rotation = playerAngle;
 395383        }
 384
 0385        public Vector3 GetViewportCenter() { return atlas.viewport.TransformPoint(atlas.viewport.rect.center); }
 386
 387        // Called by the parcelhighlight image button
 388        public void ClickMousePositionParcel()
 389        {
 0390            highlightedParcelText.text = string.Empty;
 0391            OnParcelClicked?.Invoke((int)cursorMapCoords.x, (int)cursorMapCoords.y);
 0392        }
 393    }
 394}