Combine TileChangedEvents in SetTiles (#5912)

* Combine TileChangedEvents in SetTiles

* Raise event after regenerating collision

* continue, not return

* No need for GetComponent

* Swap TileRef for Tile + Vector2i

* Estimate size of tileChanges
This commit is contained in:
Tayrtahn
2025-05-15 06:22:05 -04:00
committed by GitHub
parent 92fc8722da
commit 3d8a9a41fa
6 changed files with 75 additions and 34 deletions

View File

@@ -4,6 +4,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using Robust.Shared.Collections;
using Robust.Shared.GameStates;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
@@ -833,7 +834,7 @@ public abstract partial class SharedMapSystem
}
var offset = chunk.GridTileToChunkTile(gridIndices);
SetChunkTile(uid, grid, chunk, (ushort)offset.X, (ushort)offset.Y, tile);
SetChunkTile(uid, grid, chunk, (ushort)offset.X, (ushort)offset.Y, tile, out _);
}
public void SetTiles(EntityUid uid, MapGridComponent grid, List<(Vector2i GridIndices, Tile Tile)> tiles)
@@ -842,6 +843,11 @@ public abstract partial class SharedMapSystem
return;
var modified = new HashSet<MapChunk>(Math.Max(1, tiles.Count / grid.ChunkSize));
var tileChanges = new ValueList<TileChangedEntry>(tiles.Count);
// Suppress sending out events for each tile changed
// We're going to send them all out together at the end
MapManager.SuppressOnTileChanged = true;
foreach (var (gridIndices, tile) in tiles)
{
@@ -859,8 +865,11 @@ public abstract partial class SharedMapSystem
var offset = chunk.GridTileToChunkTile(gridIndices);
chunk.SuppressCollisionRegeneration = true;
if (SetChunkTile(uid, grid, chunk, (ushort)offset.X, (ushort)offset.Y, tile))
if (SetChunkTile(uid, grid, chunk, (ushort)offset.X, (ushort)offset.Y, tile, out var oldTile))
{
modified.Add(chunk);
tileChanges.Add(new TileChangedEntry(tile, oldTile, offset, gridIndices));
}
}
foreach (var chunk in modified)
@@ -869,6 +878,13 @@ public abstract partial class SharedMapSystem
}
RegenerateCollision(uid, grid, modified);
// Notify of all tile changes in one event
var ev = new TileChangedEvent((uid, grid), tileChanges.ToArray());
RaiseLocalEvent(uid, ref ev, true);
// Back to normal
MapManager.SuppressOnTileChanged = false;
}
public TilesEnumerator GetLocalTilesEnumerator(EntityUid uid, MapGridComponent grid, Box2 aabb,

View File

@@ -14,9 +14,9 @@ public abstract partial class SharedMapSystem
/// <param name="xIndex">The X tile index relative to the chunk.</param>
/// <param name="yIndex">The Y tile index relative to the chunk.</param>
/// <param name="tile">The new tile to insert.</param>
internal bool SetChunkTile(EntityUid uid, MapGridComponent grid, MapChunk chunk, ushort xIndex, ushort yIndex, Tile tile)
internal bool SetChunkTile(EntityUid uid, MapGridComponent grid, MapChunk chunk, ushort xIndex, ushort yIndex, Tile tile, out Tile oldTile)
{
if (!chunk.TrySetTile(xIndex, yIndex, tile, out var oldTile, out var shapeChanged))
if (!chunk.TrySetTile(xIndex, yIndex, tile, out oldTile, out var shapeChanged))
return false;
var tileIndices = new Vector2i(xIndex, yIndex);

View File

@@ -173,45 +173,61 @@ namespace Robust.Shared.GameObjects
}
/// <summary>
/// Arguments for when a single tile on a grid is changed locally or remotely.
/// Raised directed at the grid when tiles are changed locally or remotely.
/// </summary>
[ByRefEvent]
public readonly record struct TileChangedEvent
{
/// <summary>
/// Creates a new instance of this class.
/// </summary>
/// <inheritdoc cref="TileChangedEvent(Entity{MapGridComponent}, Tile, Tile, Vector2i, Vector2i)"/>
public TileChangedEvent(Entity<MapGridComponent> entity, TileRef newTile, Tile oldTile, Vector2i chunkIndex)
: this(entity, newTile.Tile, oldTile, chunkIndex, newTile.GridIndices) { }
/// <summary>
/// Creates a new instance of this event for a single changed tile.
/// </summary>
/// <param name="entity">The grid entity containing the changed tile(s)</param>
/// <param name="newTile">New tile that replaced the old one.</param>
/// <param name="oldTile">Old tile that was replaced.</param>
/// <param name="chunkIndex">The index of the grid-chunk that this tile belongs to.</param>
/// <param name="gridIndices">The positional indices of this tile on the grid.</param>
public TileChangedEvent(Entity<MapGridComponent> entity, Tile newTile, Tile oldTile, Vector2i chunkIndex, Vector2i gridIndices)
{
Entity = entity;
NewTile = newTile;
OldTile = oldTile;
ChunkIndex = chunkIndex;
Changes = [new TileChangedEntry(newTile, oldTile, chunkIndex, gridIndices)];
}
/// <summary>
/// Was the tile previously empty or is it now empty.
/// Creates a new instance of this event for multiple changed tiles.
/// </summary>
public bool EmptyChanged => OldTile.IsEmpty != NewTile.Tile.IsEmpty;
public TileChangedEvent(Entity<MapGridComponent> entity, TileChangedEntry[] changes)
{
Entity = entity;
Changes = changes;
}
/// <summary>
/// Entity of the grid with the tile-change. TileRef stores the GridId.
/// Entity of the grid with the tile-change. TileRef stores the GridId.
/// </summary>
public readonly Entity<MapGridComponent> Entity;
/// <summary>
/// New tile that replaced the old one.
/// An array of all the tiles that were changed.
/// </summary>
public readonly TileRef NewTile;
public readonly TileChangedEntry[] Changes;
}
/// <summary>
/// Data about a single tile that was changed as part of a <see cref="TileChangedEvent"/>.
/// </summary>
/// <param name="NewTile">New tile that replaced the old one.</param>
/// <param name="OldTile">Old tile that was replaced.</param>
/// <param name="ChunkIndex">The index of the grid-chunk that this tile belongs to.</param>
/// <param name="GridIndices">The positional indices of this tile on the grid.</param>
public readonly record struct TileChangedEntry(Tile NewTile, Tile OldTile, Vector2i ChunkIndex, Vector2i GridIndices)
{
/// <summary>
/// Old tile that was replaced.
/// Was the tile previously empty or is it now empty.
/// </summary>
public readonly Tile OldTile;
/// <summary>
/// The index of the grid-chunk that this tile belongs to.
/// </summary>
public readonly Vector2i ChunkIndex;
public bool EmptyChanged => OldTile.IsEmpty != NewTile.IsEmpty;
}
}

View File

@@ -70,11 +70,14 @@ namespace Robust.Shared.GameObjects
private void MapManagerOnTileChanged(ref TileChangedEvent e)
{
if(e.NewTile.Tile != Tile.Empty)
return;
foreach (var change in e.Changes)
{
if(change.NewTile != Tile.Empty)
continue;
// TODO optimize this for when multiple tiles get empties simultaneously (e.g., explosions).
DeparentAllEntsOnTile(e.NewTile.GridUid, e.NewTile.GridIndices);
// TODO optimize this for when multiple tiles get empties simultaneously (e.g., explosions).
DeparentAllEntsOnTile(e.Entity, change.GridIndices);
}
}
/// <summary>