Exemplo n.º 1
0
 private void PlaceMetaTile(MetaTileMap metaTileMap, Vector3Int position, MetaTile metaTile)
 {
     foreach (LayerTile tile in metaTile.GetTiles())
     {
         metaTileMap.RemoveTile(position, tile.LayerType);
         metaTileMap.SetTile(position, tile, cells[0].matrix);
     }
 }
Exemplo n.º 2
0
    private void OnDrawGizmos()
    {
        Gizmos.color = Color;
        BoundsInt bounds = MetaTileMap.GetWorldBounds();

        DebugGizmoUtils.DrawText(gameObject.name, bounds.max, 11, 5);
        DebugGizmoUtils.DrawRect(bounds);
    }
Exemplo n.º 3
0
    void Awake()
    {
        tileChangeManager = transform.GetComponentInParent <TileChangeManager>();
        metaDataLayer     = transform.GetComponentInParent <MetaDataLayer>();
        metaTileMap       = transform.GetComponentInParent <MetaTileMap>();

        Layer = GetComponent <Layer>();
    }
Exemplo n.º 4
0
 private void Start()
 {
     metaTileMap       = GetComponentInChildren <MetaTileMap>();
     matrix            = GetComponentInChildren <Matrix>();
     objectLayer       = GetComponentInChildren <ObjectLayer>();
     tileChangeManager = GetComponent <TileChangeManager>();
     CacheTileMaps();
 }
Exemplo n.º 5
0
 private void SetTile(MetaTileMap metaTileMap, Vector3Int position, LayerTile tile)
 {
     foreach (LayerTile requiredTile in tile.RequiredTiles)
     {
         SetTile(metaTileMap, position, requiredTile);
     }
     metaTileMap.SetTile(position, tile, cells[0].matrix, cells[0].color);
 }
Exemplo n.º 6
0
    /// <summary>
    ///     Returns LayerTile eligible to be displayed in the Item List Tab
    /// </summary>
    /// <param name="position">Position where to look for tile</param>
    public static LayerTile GetTileAtPosition(Vector3 position)
    {
        MetaTileMap metaTileMap = PlayerManager.LocalPlayerScript.gameObject.GetComponentInParent <MetaTileMap>();

        position = metaTileMap.transform.InverseTransformPoint(position);
        Vector3Int tilePosition = Vector3Int.FloorToInt(position);

        return(metaTileMap.GetTile(tilePosition));
    }
Exemplo n.º 7
0
        /// <summary>
        /// Checks if the grille's location has exposed floor plating,
        /// that a cable overlap exists there,
        /// and returns the highest voltage detected (for now).
        /// </summary>
        /// <returns>The voltage found on the cable</returns>
        private float ServerGetGrilleVoltage()
        {
            Vector3Int  targetCellPos = interaction.TargetCellPos;
            MetaTileMap metaTileMap   = interaction.TileChangeManager.MetaTileMap;
            Matrix      matrix        = metaTileMap.Layers[LayerType.Underfloor].matrix;

            // Check if the floor plating is exposed.
            if (metaTileMap.HasTile(targetCellPos, LayerType.Floors))
            {
                return(0);
            }

            // Check for cables underneath the grille.
            var eConns = matrix.GetElectricalConnections(targetCellPos);

            if (eConns == null)
            {
                return(0);
            }

            // Get the highest voltage and whether there is a connection overlap.
            // The current powernet implementation means the cable
            // will only report a voltage if there is current flow, it seems.
            // That's why we cannot simply the overlap connection's voltage,
            // and both ends of the cable need to be connected to the powernet.
            //
            // One possible workaround is to allow a Connection.Overlap to draw
            // a small amount of current, so that it registers a voltage.
            // Then, we don't need to check for the highest voltage and not worry
            // about whether the overlap is actually connected to a live cable.
            bool  overlapExists = false;
            float voltage       = 0;

            foreach (var conn in eConns)
            {
                if (conn.WireEndA == Connection.Overlap || conn.WireEndB == Connection.Overlap)
                {
                    overlapExists = true;
                }

                ElectricityFunctions.WorkOutActualNumbers(conn);
                if (conn.Data.ActualVoltage > voltage)
                {
                    voltage = conn.Data.ActualVoltage;
                }
            }

            // Check that there is a cable overlap.
            if (!overlapExists)
            {
                return(0);
            }

            // All checks passed, electrocute the performer!
            return(voltage);
        }
Exemplo n.º 8
0
    public void OnHover()
    {
        if (!UIManager.IsMouseInteractionDisabled && UIManager.Hands.CurrentSlot != null)
        {
            // get mouse position
            Vector3 mousePosition = Camera.main.ScreenToWorldPoint(CommonInput.mousePosition);
            // round mouse position
            Vector3Int roundedMousePosition = Vector3Int.RoundToInt(mousePosition);

            // if distance is greater than interaction distance
            if (Vector2.Distance(transform.position, (Vector3)roundedMousePosition) > PlayerScript.interactionDistance)
            {
                DisableVisualisation();
                return;
            }

            // if position has changed and player has cable in hand
            if (roundedMousePosition != lastMouseWordlPositionInt &&
                Validations.HasItemTrait(UIManager.Hands.CurrentSlot.ItemObject, CommonTraits.Instance.Cable))
            {
                lastMouseWordlPositionInt = roundedMousePosition;

                // get metaTileMap and top tile
                // MetaTileMap metaTileMap = MatrixManager.AtPoint(roundedMousePosition, false).MetaTileMap;
                // LayerTile topTile = metaTileMap.GetTile(metaTileMap.WorldToCell(mousePosition), true);
                // *code above works only on Station matrix
                // TODO: replace GetComponent solution with some built-in method?

                var         hit         = MouseUtils.GetOrderedObjectsUnderMouse().FirstOrDefault();
                MetaTileMap metaTileMap = hit.GetComponentInChildren <MetaTileMap>();
                if (metaTileMap)
                {
                    LayerTile topTile = metaTileMap.GetTile(metaTileMap.WorldToCell(roundedMousePosition), true);
                    if (topTile && (topTile.LayerType == LayerType.Base || topTile.LayerType == LayerType.Underfloor))
                    {
                        // move cable placement visualisation to rounded mouse position and enable it
                        cablePlacementVisualisation.transform.position = roundedMousePosition - new Vector3(0.5f, 0.5f, 0);;
                        cablePlacementVisualisation.SetActive(true);
                    }
                    // disable visualisation if active
                    else
                    {
                        DisableVisualisation();
                    }
                }
                else
                {
                    DisableVisualisation();
                }
            }
        }
        else
        {
            DisableVisualisation();
        }
    }
Exemplo n.º 9
0
 /// Can one pass from `origin` to adjacent `position`?
 /// <param name="origin">Position object is at now</param>
 /// <param name="position">Adjacent position object wants to move to</param>
 /// <param name="includingPlayers">Set this to false to ignore players from check</param>
 /// <param name="context">Is excluded from passable check</param>
 /// <param name="isReach">True if we're seeing if an object can be reached through</param>
 /// <param name="onlyExcludeLayerOnDestination">false if every involved tile should have the layers excluded, true if only the destination tile</param>
 /// <returns></returns>
 public bool IsPassableAtOneMatrix(Vector3Int origin, Vector3Int position, bool isServer,
                                   CollisionType collisionType    = CollisionType.Player, bool includingPlayers = true, GameObject context = null,
                                   List <LayerType> excludeLayers = null, List <TileType> excludeTiles          = null, bool ignoreObjects = false,
                                   bool isReach = false, bool onlyExcludeLayerOnDestination = false)
 {
     return(MetaTileMap.IsPassableAtOneTileMap(origin, position, isServer, collisionType: collisionType,
                                               inclPlayers: includingPlayers, context: context, excludeLayers: excludeLayers,
                                               excludeTiles: excludeTiles, ignoreObjects: ignoreObjects, isReach: isReach,
                                               onlyExcludeLayerOnDestination: onlyExcludeLayerOnDestination));
 }
Exemplo n.º 10
0
    /// Should player NOT stick to the station at this position?
    public bool IsNonStickyAt(Vector3Int position, bool isServer)
    {
        foreach (Vector3Int pos in position.BoundsAround().allPositionsWithin)
        {
            if (!MetaTileMap.IsNoGravityAt(pos, isServer))
            {
                return(false);
            }
        }

        return(true);
    }
Exemplo n.º 11
0
    /// Is this position and surrounding area completely clear of solid objects except for provided one?
    public bool IsFloatingAt(GameObject[] context, Vector3Int position, bool isServer)
    {
        foreach (Vector3Int pos in position.BoundsAround().allPositionsWithin)
        {
            if (!MetaTileMap.IsEmptyAt(context, pos, isServer))
            {
                return(false);
            }
        }

        return(true);
    }
Exemplo n.º 12
0
 private void Start()
 {
     metaTileMap = GetComponent <MetaTileMap>();
     try
     {
         objects = ((ObjectLayer)metaTileMap.Layers[LayerType.Objects]).Objects;
     }
     catch
     {
         Debug.LogError("CAST ERROR: Make sure everything is in its proper layer type.");
     }
 }
Exemplo n.º 13
0
    private static void Json2Map()
    {
        GameObject  map         = GameObject.FindGameObjectWithTag("Map");
        MetaTileMap metaTileMap = map.GetComponentInChildren <MetaTileMap>();

        metaTileMap.ClearAllTiles();

        TilemapConverter converter = new TilemapConverter();

        TileMapBuilder builder = new TileMapBuilder(metaTileMap, true);

        Dictionary <string, TilemapLayer> layers = DeserializeJson();

        List <Tuple <Vector3Int, ObjectTile> > objects = new List <Tuple <Vector3Int, ObjectTile> >();

        foreach (KeyValuePair <string, TilemapLayer> layer in layers)
        {
            List <Vector3Int> positions =
                layer.Value.TilePositions.ConvertAll(coord => new Vector3Int(coord.X, coord.Y, 0));

            for (int i = 0; i < positions.Count; i++)
            {
                Vector3Int  position = positions[i];
                GenericTile tile     = converter.DataToTile(layer.Value.Tiles[i]);

                if (tile is ObjectTile)
                {
                    if (!objects.Exists(t => t.Item1.Equals(position) && t.Item2 == tile))
                    {
                        objects.Add(new Tuple <Vector3Int, ObjectTile>(position, (ObjectTile)tile));
                    }
                }
                else
                {
                    builder.PlaceTile(position, tile);
                }
            }
        }

        foreach (Tuple <Vector3Int, ObjectTile> tuple in objects)
        {
            Vector3Int position = tuple.Item1;
            ObjectTile obj      = tuple.Item2;

            Matrix4x4 matrix = obj.Rotatable ? FindObjectPosition(metaTileMap, ref position, obj) : Matrix4x4.identity;

            builder.PlaceTile(position, obj, matrix);
        }

        // mark as dirty, otherwise the scene can't be saved.
        EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene());
        Logger.Log("Import kinda finished");
    }
Exemplo n.º 14
0
    private void Start()
    {
        metaTileMap       = GetComponentInChildren <MetaTileMap>();
        matrix            = GetComponentInChildren <Matrix>();
        objectLayer       = GetComponentInChildren <ObjectLayer>();
        tileChangeManager = GetComponent <TileChangeManager>();
        CacheTileMaps();

        // register message handler for CableCuttingMessage here because CableCuttingWindow prefab won't be loaded on server
        // so registration cannot be inside Start or Awake method inside CableCuttingWindow
        NetworkServer.RegisterHandler <CableCuttingWindow.CableCuttingMessage>(ServerPerformCableCuttingInteraction);
    }
Exemplo n.º 15
0
    public void RunOreGenerator()
    {
        metaTileMap       = GetComponentInChildren <MetaTileMap>();
        wallTilemap       = metaTileMap.Layers[LayerType.Walls].GetComponent <Tilemap>();
        tileChangeManager = GetComponent <TileChangeManager>();

        if (CustomNetworkManager.IsServer)
        {
            List <OreProbability> weightedList = new List <OreProbability>();
            foreach (var ores in config.OreProbabilities)
            {
                for (int i = 0; i < ores.SpawnChance; i++)
                {
                    weightedList.Add(ores);
                }
            }

            //TODO move BoundsInt bounds = wallTilemap.cellBounds to metaTileMap
            BoundsInt         bounds      = wallTilemap.cellBounds;
            List <Vector3Int> miningTiles = new List <Vector3Int>();

            for (int n = bounds.xMin; n < bounds.xMax; n++)
            {
                for (int p = bounds.yMin; p < bounds.yMax; p++)
                {
                    Vector3Int localPlace = (new Vector3Int(n, p, 0));

                    if (metaTileMap.HasTile(localPlace))
                    {
                        var tile = metaTileMap.GetTile(localPlace);
                        if (tile.name.Contains("rock_wall"))
                        {
                            miningTiles.Add(localPlace);
                        }
                    }
                }
            }

            int numberOfTiles = (int)((miningTiles.Count / 100f) * config.Density);
            for (int i = 0; i < numberOfTiles; i++)
            {
                var oreTile     = miningTiles[RANDOM.Next(miningTiles.Count)];
                var oreCategory = weightedList[RANDOM.Next(weightedList.Count)];
                tileChangeManager.UpdateTile(oreTile, oreCategory.WallTile);
                var intLocation = oreTile + Vector3Int.zero;
                intLocation.z = -1;
                tileChangeManager.AddOverlay(intLocation, oreCategory.OverlayTile as OverlayTile);

                NodeScatter(oreTile, oreCategory);
            }
        }
    }
Exemplo n.º 16
0
 private void Start()
 {
     metaDataLayer = GetComponentInChildren <MetaDataLayer>(true);
     metaTileMap   = GetComponent <MetaTileMap>();
     try
     {
         objects = ((ObjectLayer)metaTileMap.Layers[LayerType.Objects]).Objects;
     }
     catch
     {
         Logger.LogError("CAST ERROR: Make sure everything is in its proper layer type.", Category.Matrix);
     }
 }
Exemplo n.º 17
0
    private void OnDrawGizmos()
    {
        Gizmos.color = Color;

        if (metaTileMap == null)
        {
            metaTileMap = GetComponent <MetaTileMap>();
        }

        BoundsInt bounds = MetaTileMap.GetWorldBounds();

        DebugGizmoUtils.DrawText(gameObject.name, bounds.max, 11, 5);
        DebugGizmoUtils.DrawRect(bounds);
    }
Exemplo n.º 18
0
    private void Awake()
    {
        metaTileMap = GetComponent <MetaTileMap>();
        if (metaTileMap == null)
        {
            Logger.LogError($"MetaTileMap was null on {gameObject.name}");
        }

        networkedMatrix   = transform.parent.GetComponent <NetworkedMatrix>();
        initialOffset     = Vector3Int.CeilToInt(gameObject.transform.position);
        reactionManager   = GetComponent <ReactionManager>();
        metaDataLayer     = GetComponent <MetaDataLayer>();
        MatrixMove        = GetComponentInParent <MatrixMove>();
        tileChangeManager = GetComponentInParent <TileChangeManager>();
        underFloorLayer   = GetComponentInChildren <UnderFloorLayer>();
        tilemapsDamage    = GetComponentsInChildren <TilemapDamage>().ToList();

        if (MatrixManager.Instance.InitializingMatrixes.ContainsKey(gameObject.scene) == false)
        {
            MatrixManager.Instance.InitializingMatrixes.Add(gameObject.scene, new List <Matrix>());
        }
        MatrixManager.Instance.InitializingMatrixes[gameObject.scene].Add(this);


        OnEarthquake.AddListener((worldPos, magnitude) =>
        {
            var cellPos = metaTileMap.WorldToCell(worldPos);

            var bounds =
                new BoundsInt(cellPos - new Vector3Int(magnitude, magnitude, 0),
                              new Vector3Int(magnitude * 2, magnitude * 2, 1));

            foreach (var pos in bounds.allPositionsWithin)
            {
                foreach (var player in Get <PlayerScript>(pos, true))
                {
                    if (player.IsGhost)
                    {
                        continue;
                    }

                    player.registerTile.ServerSlip(true);
                }

                //maybe shake items somehow, too
            }
        });
    }
Exemplo n.º 19
0
    private void Start()
    {
        metaTileMap       = GetComponentInChildren <MetaTileMap>();
        matrix            = GetComponentInChildren <Matrix>();
        objectLayer       = GetComponentInChildren <ObjectLayer>();
        tileChangeManager = GetComponent <TileChangeManager>();
        CacheTileMaps();

        // Register message handler for CableCuttingMessage here because CableCuttingWindow prefab won't be loaded on server
        // so registration cannot be inside Start or Awake method inside CableCuttingWindow. ReplaceHandler does the same
        // thing as RegisterHandler, except RegisterHandler warns about conflicting ID types. See Mirror's documentation or
        // Mirror's implementation of these methods in NetworkServer.cs.
        // TODO: This is somehow called multiple times. Not sure why. Figure out if it's an issue and document why this
        //       happens.
        NetworkServer.ReplaceHandler <CableCuttingWindow.CableCuttingMessage>(ServerPerformCableCuttingInteraction);
    }
Exemplo n.º 20
0
    public override void BoxErase(GridLayout grid, GameObject layer, BoundsInt area)
    {
        MetaTileMap metaTileMap = grid.GetComponent <MetaTileMap>();

        foreach (Vector3Int position in area.allPositionsWithin)
        {
            if (metaTileMap)
            {
                metaTileMap.RemoveTile(position, false);
            }
            else
            {
                layer.GetComponent <Layer>().SetTile(position, null, Matrix4x4.identity, Color.white);
            }
        }
    }
Exemplo n.º 21
0
        public override void BoxErase(GridLayout grid, GameObject layer, BoundsInt area)
        {
            MetaTileMap metaTileMap = grid.GetComponent <MetaTileMap>();

            foreach (Vector3Int position in area.allPositionsWithin)
            {
                if (metaTileMap)
                {
                    metaTileMap.RemoveTile(position, LayerType.None);
                }
                else
                {
                    layer.GetComponent <Tilemap>().SetTile(position, null);
                }
            }
        }
Exemplo n.º 22
0
    public override void PaintPreview(GridLayout gridLayout, GameObject brushTarget, Vector3Int position)
    {
        if (brushTarget == null)
        {
            return;
        }

        MetaTileMap metaTilemap = brushTarget.GetComponent <MetaTileMap>();

        if (!metaTilemap)
        {
            return;
        }

        TileBase tile = brush.cells[0].tile;

        if (tile != _currentPreviewTile)
        {
            if (tile is LayerTile)
            {
                ObjectTile objectTile = tile as ObjectTile;
                if (objectTile && objectTile.Offset)
                {
                    brush.cells[0].matrix = Matrix4x4.TRS(Vector3.up, Quaternion.identity, Vector3.one);
                }

                previewTiles = new[] { (LayerTile)tile };
            }
            else if (tile is MetaTile)
            {
                previewTiles = ((MetaTile)tile).GetTiles().ToArray();
            }

            _currentPreviewTile = tile;
        }

        if (previewTiles != null)
        {
            for (int i = 0; i < previewTiles.Length; i++)
            {
                SetPreviewTile(metaTilemap, position, previewTiles[i]);
            }
        }

        _currentPreviewTilemap = metaTilemap;
    }
Exemplo n.º 23
0
    public static bool IsMineableAt(Vector2 targetWorldPosition, MetaTileMap metaTileMap)
    {
        var wallTile = metaTileMap.GetTileAtWorldPos(targetWorldPosition, LayerType.Walls);

        if (wallTile == null)
        {
            return(false);
        }
        if (!(wallTile is BasicTile))
        {
            return(false);
        }

        var basicWallTile = wallTile as BasicTile;

        return(basicWallTile.Mineable);
    }
Exemplo n.º 24
0
        private void SetPreviewTile(MetaTileMap metaTilemap, Vector3Int position, LayerTile tile)
        {
            if (tile is ObjectTile)
            {
                if (previewTile == null)
                {
                    previewTile = CreateInstance <PreviewTile>();
                }

                previewTile.ReferenceTile = tile;
                tile = previewTile;

                position.z++; // to draw the object over already existing stuff
            }

            metaTilemap.SetPreviewTile(position, tile, brush.cells[0].matrix);
        }
Exemplo n.º 25
0
        public override void Interact(GameObject originator, Vector3 position, string hand)
        {
            metaTileMap = originator.GetComponentInParent <MetaTileMap>();
            objectLayer = originator.GetComponentInParent <ObjectLayer>();

            Vector3Int pos = objectLayer.transform.InverseTransformPoint(position).RoundToInt();

            pos.z = 0;

            LayerTile tile = metaTileMap.GetTile(pos);

            if (tile?.TileType == TileType.Table)
            {
                TableInteraction interaction = new TableInteraction(gameObject, originator, position, hand);

                interaction.Interact(isServer);
            }
        }
    public void OnHover()
    {
        if (!UIManager.IsMouseInteractionDisabled)
        {
            // get mouse position
            Vector3 mousePosition = Camera.main.ScreenToWorldPoint(CommonInput.mousePosition);
            // round mouse position
            Vector3Int roundedMousePosition = Vector3Int.RoundToInt(mousePosition);

            // if distance is greater than interaction distance
            if (Vector2.Distance(transform.position, (Vector3)roundedMousePosition) > PlayerScript.interactionDistance)
            {
                DisableVisualisation();
                return;
            }

            // if position has changed and player has cable in hand
            if (roundedMousePosition != lastMouseWordlPositionInt &&
                Validations.HasItemTrait(UIManager.Hands.CurrentSlot.ItemObject, CommonTraits.Instance.Cable))
            {
                lastMouseWordlPositionInt = roundedMousePosition;

                // get metaTileMap and top tile
                MetaTileMap metaTileMap = MatrixManager.AtPoint(roundedMousePosition, false).MetaTileMap;
                LayerTile   topTile     = metaTileMap.GetTile(metaTileMap.WorldToCell(mousePosition), true);

                if (topTile && (topTile.LayerType == LayerType.Base || topTile.LayerType == LayerType.Underfloor))
                {
                    // move cable placement visualisation to rounded mouse position and enable it
                    cablePlacementVisualisation.transform.position = roundedMousePosition - new Vector3(0.5f, 0.5f, 0);;
                    cablePlacementVisualisation.SetActive(true);
                }
                // disable visualisation if active
                else
                {
                    DisableVisualisation();
                }
            }
        }
        else
        {
            DisableVisualisation();
        }
    }
Exemplo n.º 27
0
    /// <summary>
    /// Checks if the tile is Passable by the ColliderType
    /// It will return the default Passable bool unless an exception is avalaible in PassableException
    /// </summary>
    /// <param name="colliderType"></param>
    /// <returns>IsPassable</returns>
    public bool IsPassable(CollisionType colliderType, Vector3Int origin, MetaTileMap metaTileMap)
    {
        if (this.LayerType == LayerType.Tables)
        {
            if (metaTileMap.IsTableAt(origin))
            {
                return(true);
            }
        }

        if (passableException.ContainsKey(colliderType))
        {
            return(passableException[colliderType]);
        }
        else
        {
            return(passable);
        }
    }
Exemplo n.º 28
0
        public override void PaintPreview(GridLayout gridLayout, GameObject brushTarget, Vector3Int position)
        {
            if (brushTarget == null)
            {
                return;
            }

            var metaTilemap = brushTarget.GetComponent <MetaTileMap>();

            if (!metaTilemap)
            {
                return;
            }

            var tile = brush.cells[0].tile;

            if (tile is LayerTile)
            {
                if (tile != _currentPreviewTile)
                {
                    var layerTile = tile as LayerTile;

                    var objectTile = tile as ObjectTile;
                    if (objectTile && objectTile.Offset)
                    {
                        brush.cells[0].matrix = Matrix4x4.TRS(Vector3.up, Quaternion.identity, Vector3.one);
                    }

                    _currentPreviewTile = tile;
                }

                SetPreviewTile(metaTilemap, position, (LayerTile)tile);
            }
            else if (tile is MetaTile)
            {
                foreach (var layerTile in ((MetaTile)tile).GetTiles())
                {
                    SetPreviewTile(metaTilemap, position, layerTile);
                }
            }

            _currentPreviewTilemap = metaTilemap;
        }
Exemplo n.º 29
0
 public bool IsClearUnderfloorConstruction(Vector3Int position, bool isServer)
 {
     if (MetaTileMap.HasTile(position, LayerType.Floors, isServer))
     {
         return(false);
     }
     else if (MetaTileMap.HasTile(position, LayerType.Walls, isServer))
     {
         return(false);
     }
     else if (MetaTileMap.HasTile(position, LayerType.Windows, isServer))
     {
         return(false);
     }
     else if (MetaTileMap.HasTile(position, LayerType.Grills, isServer))
     {
         return(false);
     }
     return(true);
 }
Exemplo n.º 30
0
    /// <summary>
    ///     Returns LayerTile eligible to be displayed in the Item List Tab
    /// </summary>
    /// <param name="position">Position where to look for tile</param>
    public static LayerTile GetTileAtPosition(Vector3 position)
    {
        MetaTileMap metaTileMap  = PlayerManager.LocalPlayerScript.gameObject.GetComponentInParent <MetaTileMap>();
        Vector3Int  tilePosition = new Vector3Int(
            Mathf.FloorToInt(position.x),
            Mathf.FloorToInt(position.y),
            Mathf.FloorToInt(position.z)
            );

        foreach (LayerType layer in Enum.GetValues(typeof(LayerType)))
        {
            LayerTile tile = metaTileMap.GetTile(tilePosition, layer);
            if (tile != null)
            {
                return(tile);
            }
        }

        return(null);
    }