mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-09-02 01:57:07 +02:00
177 lines
5.9 KiB
C#
177 lines
5.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics.Contracts;
|
|
using System.Numerics;
|
|
using Robust.Shared.GameObjects;
|
|
using Robust.Shared.GameStates;
|
|
using Robust.Shared.Maths;
|
|
using Robust.Shared.Physics;
|
|
using Robust.Shared.Serialization;
|
|
using Robust.Shared.Serialization.Manager.Attributes;
|
|
using Robust.Shared.Timing;
|
|
using Robust.Shared.Utility;
|
|
using Robust.Shared.ViewVariables;
|
|
|
|
namespace Robust.Shared.Map.Components;
|
|
|
|
/// <summary>
|
|
/// <para>
|
|
/// Provides a tile grid as part of an entity, with APIs to manipulate it provided on <see cref="MapSystem"/>.
|
|
/// Grids function as the optional second level in the physics hierarchy, and implicitly provide physics and the ability to collide with one-another.
|
|
/// </para>
|
|
/// <para>
|
|
/// Map grids are an unbounded 2D grid composed of <see cref="Tile"/>s,
|
|
/// which have their properties defined by <see cref="ITileDefinition"/> inheriting prototypes.
|
|
/// A tile with the id 0 is automatically assumed to be the "empty" tile and is the default state of any tile that has not been assigned to.
|
|
/// </para>
|
|
/// <para>
|
|
/// Collision is automatically generated from set grid tiles (excluding tiles with id 0, i.e. empty).
|
|
/// Map grids have an implied additional level of physics acceleration structures,
|
|
/// functioning as an optimization for games that rely on moving grids regularly by avoiding the need to update the grids' children.
|
|
/// </para>
|
|
/// </summary>
|
|
[RegisterComponent, NetworkedComponent]
|
|
public sealed partial class MapGridComponent : Component
|
|
{
|
|
public const ushort DefaultChunkSize = 16;
|
|
|
|
// This field is used for deserialization internally in the map loader.
|
|
// If you want to remove this, you would have to restructure the map save file.
|
|
[DataField("index")]
|
|
internal int GridIndex;
|
|
// the grid section now writes the grid's EntityUID. as long as existing maps get updated (just a load+save),
|
|
// this can be removed
|
|
|
|
[DataField]
|
|
internal ushort ChunkSize = DefaultChunkSize;
|
|
|
|
[ViewVariables]
|
|
public int ChunkCount => Chunks.Count;
|
|
|
|
/// <summary>
|
|
/// The length of the side of a square tile in world units.
|
|
/// </summary>
|
|
[DataField]
|
|
public ushort TileSize { get; internal set; } = 1;
|
|
|
|
/// <summary>
|
|
/// A square the size of one tile.
|
|
/// </summary>
|
|
public Vector2 TileSizeVector => new(TileSize, TileSize);
|
|
|
|
/// <summary>
|
|
/// A square the size of a quarter tile.
|
|
/// </summary>
|
|
public Vector2 TileSizeHalfVector => new(TileSize / 2f, TileSize / 2f);
|
|
|
|
[ViewVariables]
|
|
internal readonly List<(GameTick tick, Vector2i indices)> ChunkDeletionHistory = new();
|
|
|
|
/// <summary>
|
|
/// Last game tick that the map was modified.
|
|
/// </summary>
|
|
[ViewVariables]
|
|
public GameTick LastTileModifiedTick { get; internal set; }
|
|
|
|
/// <summary>
|
|
/// Map DynamicTree proxy to lookup for grid intersection.
|
|
/// </summary>
|
|
internal DynamicTree.Proxy MapProxy = DynamicTree.Proxy.Free;
|
|
|
|
/// <summary>
|
|
/// Grid chunks than make up this grid.
|
|
/// </summary>
|
|
[DataField]
|
|
internal Dictionary<Vector2i, MapChunk> Chunks = new();
|
|
|
|
[ViewVariables]
|
|
public Box2 LocalAABB { get; internal set; }
|
|
|
|
/// <summary>
|
|
/// Set to enable or disable grid splitting.
|
|
/// You must ensure you handle this properly and check for splits afterwards if relevant!
|
|
/// </summary>
|
|
[DataField]
|
|
public bool CanSplit = true;
|
|
|
|
/// <returns>True if the specified chunk exists on this grid.</returns>
|
|
[Pure]
|
|
public bool HasChunk(Vector2i indices)
|
|
{
|
|
return Chunks.ContainsKey(indices);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Serialized state of a <see cref="MapGridComponentState"/>.
|
|
/// </summary>
|
|
[Serializable, NetSerializable]
|
|
internal sealed class MapGridComponentState(ushort chunkSize, Dictionary<Vector2i, ChunkDatum> fullGridData, GameTick lastTileModifiedTick) : ComponentState
|
|
{
|
|
/// <summary>
|
|
/// The size of the chunks in the map grid.
|
|
/// </summary>
|
|
public ushort ChunkSize = chunkSize;
|
|
|
|
/// <summary>
|
|
/// Networked chunk data containing the full grid state.
|
|
/// </summary>
|
|
public Dictionary<Vector2i, ChunkDatum> FullGridData = fullGridData;
|
|
|
|
/// <summary>
|
|
/// Last game tick that the tile on the grid was modified.
|
|
/// </summary>
|
|
public GameTick LastTileModifiedTick = lastTileModifiedTick;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Serialized state of a <see cref="MapGridComponentState"/>.
|
|
/// </summary>
|
|
[Serializable, NetSerializable]
|
|
internal sealed class MapGridComponentDeltaState(ushort chunkSize, Dictionary<Vector2i, ChunkDatum>? chunkData, GameTick lastTileModifiedTick)
|
|
: ComponentState, IComponentDeltaState<MapGridComponentState>
|
|
{
|
|
/// <summary>
|
|
/// The size of the chunks in the map grid.
|
|
/// </summary>
|
|
public readonly ushort ChunkSize = chunkSize;
|
|
|
|
/// <summary>
|
|
/// Networked chunk data.
|
|
/// </summary>
|
|
public readonly Dictionary<Vector2i, ChunkDatum>? ChunkData = chunkData;
|
|
|
|
/// <summary>
|
|
/// Last game tick that the tile on the grid was modified.
|
|
/// </summary>
|
|
public GameTick LastTileModifiedTick = lastTileModifiedTick;
|
|
|
|
public void ApplyToFullState(MapGridComponentState state)
|
|
{
|
|
state.ChunkSize = ChunkSize;
|
|
|
|
if (ChunkData == null)
|
|
return;
|
|
|
|
foreach (var (index, data) in ChunkData)
|
|
{
|
|
if (data.IsDeleted())
|
|
state.FullGridData.Remove(index);
|
|
else
|
|
state.FullGridData[index] = data;
|
|
}
|
|
|
|
state.LastTileModifiedTick = LastTileModifiedTick;
|
|
}
|
|
|
|
public MapGridComponentState CreateNewFullState(MapGridComponentState state)
|
|
{
|
|
if (ChunkData == null)
|
|
return new(ChunkSize, state.FullGridData, state.LastTileModifiedTick);
|
|
|
|
var newState = new MapGridComponentState(ChunkSize, state.FullGridData.ShallowClone(), LastTileModifiedTick);
|
|
ApplyToFullState(newState);
|
|
return newState;
|
|
}
|
|
}
|