mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
271 lines
9.5 KiB
C#
271 lines
9.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using Robust.Shared.GameObjects;
|
|
using Robust.Shared.Map.Components;
|
|
using Robust.Shared.Maths;
|
|
using Robust.Shared.Physics.Dynamics;
|
|
using Robust.Shared.Timing;
|
|
using Robust.Shared.Utility;
|
|
using Robust.Shared.ViewVariables;
|
|
|
|
namespace Robust.Shared.Map
|
|
{
|
|
/// <summary>
|
|
/// A square section of a <see cref="MapGridComponent"/>.
|
|
/// </summary>
|
|
internal sealed class MapChunk
|
|
{
|
|
/// <summary>
|
|
/// New SnapGrid cells are allocated with this capacity.
|
|
/// </summary>
|
|
private const int SnapCellStartingCapacity = 1;
|
|
|
|
private readonly Vector2i _gridIndices;
|
|
|
|
[ViewVariables] internal readonly Tile[,] Tiles;
|
|
private readonly SnapGridCell[,] _snapGrid;
|
|
|
|
/// <summary>
|
|
/// Keeps a running count of the number of filled tiles in this chunk.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This will always be between 1 and <see cref="ChunkSize"/>^2.
|
|
/// </remarks>
|
|
[ViewVariables]
|
|
internal int FilledTiles { get; set; }
|
|
|
|
/// <summary>
|
|
/// Chunk-local AABB of this chunk.
|
|
/// </summary>
|
|
public Box2i CachedBounds { get; set; }
|
|
|
|
/// <summary>
|
|
/// Physics fixtures that make up this grid chunk.
|
|
/// </summary>
|
|
public List<Fixture> Fixtures { get; } = new();
|
|
|
|
/// <summary>
|
|
/// The last game simulation tick that a tile on this chunk was modified.
|
|
/// </summary>
|
|
[ViewVariables]
|
|
public GameTick LastTileModifiedTick { get; set; }
|
|
|
|
/// <summary>
|
|
/// Setting this property to <see langword="true"/> suppresses collision regeneration on the chunk until the
|
|
/// property is set to <see langword="false"/>.
|
|
/// </summary>
|
|
public bool SuppressCollisionRegeneration { get; set; }
|
|
|
|
/// <summary>
|
|
/// Constructs an instance of a MapChunk.
|
|
/// </summary>
|
|
/// <param name="x"></param>
|
|
/// <param name="y"></param>
|
|
/// <param name="chunkSize"></param>
|
|
public MapChunk(int x, int y, ushort chunkSize)
|
|
{
|
|
_gridIndices = new Vector2i(x, y);
|
|
ChunkSize = chunkSize;
|
|
|
|
Tiles = new Tile[ChunkSize, ChunkSize];
|
|
_snapGrid = new SnapGridCell[ChunkSize, ChunkSize];
|
|
}
|
|
|
|
/// <summary>
|
|
/// The number of tiles per side of the square chunk.
|
|
/// </summary>
|
|
public ushort ChunkSize { get; }
|
|
|
|
/// <summary>
|
|
/// The X index of this chunk inside the <see cref="MapGridComponent"/>.
|
|
/// </summary>
|
|
public int X => _gridIndices.X;
|
|
|
|
/// <summary>
|
|
/// The Y index of this chunk inside the <see cref="MapGridComponent"/>.
|
|
/// </summary>
|
|
public int Y => _gridIndices.Y;
|
|
|
|
/// <summary>
|
|
/// The positional indices of this chunk in the <see cref="MapGridComponent"/>.
|
|
/// </summary>
|
|
public Vector2i Indices => _gridIndices;
|
|
|
|
/// <summary>
|
|
/// Returns the tile at the given chunk indices.
|
|
/// </summary>
|
|
/// <param name="xIndex">The X tile index relative to the chunk origin.</param>
|
|
/// <param name="yIndex">The Y tile index relative to the chunk origin.</param>
|
|
/// <returns></returns>
|
|
/// <exception cref="ArgumentOutOfRangeException">The index is less than or greater than the size of the chunk.</exception>
|
|
public Tile GetTile(ushort xIndex, ushort yIndex)
|
|
{
|
|
|
|
if (xIndex >= ChunkSize)
|
|
throw new ArgumentOutOfRangeException(nameof(xIndex), "Tile indices out of bounds.");
|
|
|
|
if (yIndex >= ChunkSize)
|
|
throw new ArgumentOutOfRangeException(nameof(yIndex), "Tile indices out of bounds.");
|
|
|
|
return Tiles[xIndex, yIndex];
|
|
}
|
|
|
|
public Tile GetTile(Vector2i indices)
|
|
{
|
|
return Tiles[indices.X, indices.Y];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Transforms Tile indices relative to the grid into tile indices relative to this chunk.
|
|
/// </summary>
|
|
/// <param name="gridTile">Tile indices relative to the grid.</param>
|
|
/// <returns>Tile indices relative to this chunk.</returns>
|
|
public Vector2i GridTileToChunkTile(Vector2i gridTile)
|
|
{
|
|
var x = MathHelper.Mod(gridTile.X, ChunkSize);
|
|
var y = MathHelper.Mod(gridTile.Y, ChunkSize);
|
|
return new Vector2i(x, y);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Translates chunk tile indices to grid tile indices.
|
|
/// </summary>
|
|
/// <param name="chunkTile">The indices relative to the chunk origin.</param>
|
|
/// <returns>The indices relative to the grid origin.</returns>
|
|
public Vector2i ChunkTileToGridTile(Vector2i chunkTile)
|
|
{
|
|
return chunkTile + _gridIndices * ChunkSize;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the anchored cell at the given tile indices.
|
|
/// </summary>
|
|
public IEnumerable<EntityUid> GetSnapGridCell(ushort xCell, ushort yCell)
|
|
{
|
|
if (xCell >= ChunkSize)
|
|
throw new ArgumentOutOfRangeException(nameof(xCell), "Tile indices out of bounds.");
|
|
|
|
if (yCell >= ChunkSize)
|
|
throw new ArgumentOutOfRangeException(nameof(yCell), "Tile indices out of bounds.");
|
|
|
|
var cell = _snapGrid[xCell, yCell];
|
|
var list = cell.Center;
|
|
|
|
if (list == null)
|
|
{
|
|
return Array.Empty<EntityUid>();
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
internal List<EntityUid>? GetSnapGrid(ushort xCell, ushort yCell)
|
|
{
|
|
if (xCell >= ChunkSize)
|
|
throw new ArgumentOutOfRangeException(nameof(xCell), "Tile indices out of bounds.");
|
|
|
|
if (yCell >= ChunkSize)
|
|
throw new ArgumentOutOfRangeException(nameof(yCell), "Tile indices out of bounds.");
|
|
|
|
var cell = _snapGrid[xCell, yCell];
|
|
return cell.Center;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds an entity to the anchor cell at the given tile indices.
|
|
/// </summary>
|
|
public void AddToSnapGridCell(ushort xCell, ushort yCell, EntityUid euid)
|
|
{
|
|
if (xCell >= ChunkSize)
|
|
throw new ArgumentOutOfRangeException(nameof(xCell), "Tile indices out of bounds.");
|
|
|
|
if (yCell >= ChunkSize)
|
|
throw new ArgumentOutOfRangeException(nameof(yCell), "Tile indices out of bounds.");
|
|
|
|
ref var cell = ref _snapGrid[xCell, yCell];
|
|
cell.Center ??= new List<EntityUid>(SnapCellStartingCapacity);
|
|
|
|
DebugTools.Assert(!cell.Center.Contains(euid));
|
|
cell.Center.Add(euid);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes an entity from the anchor cell at the given tile indices.
|
|
/// </summary>
|
|
public void RemoveFromSnapGridCell(ushort xCell, ushort yCell, EntityUid euid)
|
|
{
|
|
if (xCell >= ChunkSize)
|
|
throw new ArgumentOutOfRangeException(nameof(xCell), "Tile indices out of bounds.");
|
|
|
|
if (yCell >= ChunkSize)
|
|
throw new ArgumentOutOfRangeException(nameof(yCell), "Tile indices out of bounds.");
|
|
|
|
ref var cell = ref _snapGrid[xCell, yCell];
|
|
cell.Center?.Remove(euid);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override string ToString()
|
|
{
|
|
return $"Chunk {_gridIndices}";
|
|
}
|
|
|
|
private struct SnapGridCell
|
|
{
|
|
public List<EntityUid>? Center;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the tile without any callbacks.
|
|
/// Do not call this unless you know what you are doing.
|
|
/// </summary>
|
|
internal bool TrySetTile(ushort xIndex, ushort yIndex, Tile tile, out Tile oldTile, out bool shapeChanged)
|
|
{
|
|
if (xIndex >= Tiles.Length)
|
|
throw new ArgumentOutOfRangeException(nameof(xIndex), "Tile indices out of bounds.");
|
|
|
|
if (yIndex >= Tiles.Length)
|
|
throw new ArgumentOutOfRangeException(nameof(yIndex), "Tile indices out of bounds.");
|
|
|
|
// same tile, no point to continue
|
|
if (Tiles[xIndex, yIndex] == tile)
|
|
{
|
|
oldTile = Tile.Empty;
|
|
shapeChanged = false;
|
|
return false;
|
|
}
|
|
|
|
oldTile = Tiles[xIndex, yIndex];
|
|
var oldFilledTiles = FilledTiles;
|
|
|
|
if (oldTile.IsEmpty != tile.IsEmpty)
|
|
{
|
|
if (oldTile.IsEmpty)
|
|
{
|
|
FilledTiles += 1;
|
|
}
|
|
else
|
|
{
|
|
FilledTiles -= 1;
|
|
}
|
|
}
|
|
|
|
shapeChanged = oldFilledTiles != FilledTiles;
|
|
DebugTools.Assert(FilledTiles >= 0);
|
|
|
|
Tiles[xIndex, yIndex] = tile;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Event delegate for <see cref="MapChunk.TileModified"/>.
|
|
/// </summary>
|
|
/// <param name="mapChunk">Chunk that the tile was on.</param>
|
|
/// <param name="tileIndices">hunk Indices of the tile that was modified.</param>
|
|
/// <param name="newTile">New version of the tile.</param>
|
|
/// <param name="oldTile">Old version of the tile.</param>
|
|
/// <param name="chunkShapeChanged">If changing this tile changed the shape of the chunk.</param>
|
|
internal delegate void TileModifiedDelegate(EntityUid uid, MapGridComponent grid, MapChunk mapChunk, Vector2i tileIndices, Tile newTile, Tile oldTile, bool chunkShapeChanged);
|
|
}
|