using System; using System.Collections.Generic; using System.Linq; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; using Robust.Shared.IoC; using Robust.Shared.Log; using Robust.Shared.Map; using Robust.Shared.Maths; using Robust.Shared.Serialization; namespace Robust.Shared.GameObjects.Components.Transform { /// /// Makes it possible to look this entity up with the snap grid. /// public class SnapGridComponent : Component, IComponentDebug { public const string LogCategory = "go.comp.snapgrid"; public sealed override string Name => "SnapGrid"; private bool IsSet; private SnapGridOffset _offset = SnapGridOffset.Center; [Dependency] private readonly IMapManager _mapManager = default!; public event Action? OnPositionChanged; private GridId _lastGrid; public MapIndices Position { get; private set; } public SnapGridOffset Offset => _offset; /// public override void Initialize() { base.Initialize(); UpdatePosition(); } /// protected override void Shutdown() { base.Shutdown(); if (IsSet) { if (_mapManager.TryGetGrid(_lastGrid, out var grid)) { grid.RemoveFromSnapGridCell(Position, Offset, this); return; } IsSet = false; } } public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); serializer.DataFieldCached(ref _offset, "offset", SnapGridOffset.Center); } /// /// Returns an enumerable over all the entities which are one tile over in a certain direction. /// public IEnumerable GetInDir(Direction dir) { var grid = _mapManager.GetGrid(Owner.Transform.GridID); var pos = SnapGridPosAt(dir); return grid.GetSnapGridCell(pos, Offset).Select(s => s.Owner); } public IEnumerable GetLocal() { var grid = _mapManager.GetGrid(Owner.Transform.GridID); return grid.GetSnapGridCell(Position, Offset).Select(s => s.Owner); } public string GetDebugString() { return $"ofs/pos: {Offset}/{Position}"; } public GridCoordinates DirectionToGrid(Direction direction) { var ownerGrid = _mapManager.GetGrid(Owner.Transform.GridID); var grid = ownerGrid.GridTileToLocal(SnapGridPosAt(direction)); return grid; } MapIndices SnapGridPosAt(Direction dir, int dist = 1) { switch (dir) { case Direction.East: return Position + new MapIndices(dist, 0); case Direction.SouthEast: return Position + new MapIndices(dist, -dist); case Direction.South: return Position + new MapIndices(0, -dist); case Direction.SouthWest: return Position + new MapIndices(-dist, -dist); case Direction.West: return Position + new MapIndices(-dist, 0); case Direction.NorthWest: return Position + new MapIndices(-dist, dist); case Direction.North: return Position + new MapIndices(0, dist); case Direction.NorthEast: return Position + new MapIndices(dist, dist); default: throw new NotImplementedException(); } } public IEnumerable GetCardinalNeighborCells() { var grid = _mapManager.GetGrid(Owner.Transform.GridID); foreach (var cell in grid.GetSnapGridCell(Position, Offset)) yield return cell; foreach (var cell in grid.GetSnapGridCell(Position + new MapIndices(0, 1), Offset)) yield return cell; foreach (var cell in grid.GetSnapGridCell(Position + new MapIndices(0, -1), Offset)) yield return cell; foreach (var cell in grid.GetSnapGridCell(Position + new MapIndices(1, 0), Offset)) yield return cell; foreach (var cell in grid.GetSnapGridCell(Position + new MapIndices(-1, 0), Offset)) yield return cell; } public IEnumerable GetCellsInSquareArea(int n = 1) { var grid = _mapManager.GetGrid(Owner.Transform.GridID); for (var y = -n; y <= n; ++y) for (var x = -n; x <= n; ++x) { foreach (var cell in grid.GetSnapGridCell(Position + new MapIndices(x, y), Offset)) yield return cell; } } internal void UpdatePosition() { if (IsSet) { if (!_mapManager.TryGetGrid(_lastGrid, out var lastGrid)) { Logger.WarningS(LogCategory, "Entity {0} snapgrid didn't find grid {1}. Race condition?", Owner.Uid, Owner.Transform.GridID); return; } lastGrid.RemoveFromSnapGridCell(Position, Offset, this); } if (!_mapManager.TryGetGrid(Owner.Transform.GridID, out var grid)) { Logger.WarningS(LogCategory, "Entity {0} snapgrid didn't find grid {1}. Race condition?", Owner.Uid, Owner.Transform.GridID); return; } IsSet = true; var oldPos = Position; Position = grid.SnapGridCellFor(Owner.Transform.GridPosition, Offset); _lastGrid = Owner.Transform.GridID; grid.AddToSnapGridCell(Position, Offset, this); if (oldPos != Position) { OnPositionChanged?.Invoke(); } } } public enum SnapGridOffset { /// /// Center snap grid (wires, pipes, ...). /// Center, /// /// Edge snap grid (walls, ...). /// Edge, } }