From 6f809d1ad68579c2098be485bc16ea36086325d8 Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Fri, 16 May 2025 21:54:27 -0400 Subject: [PATCH] Allow protected grids to be repaired (#36989) * Allow protected grids to be repaired * Probably implement it --------- Co-authored-by: metalgearsloth --- Content.Shared/RCD/Systems/RCDSystem.cs | 2 +- Content.Shared/Tiles/FloorTileAttemptEvent.cs | 2 +- Content.Shared/Tiles/FloorTileSystem.cs | 10 +-- .../Tiles/ProtectedGridComponent.cs | 9 ++- Content.Shared/Tiles/ProtectedGridSystem.cs | 70 +++++++++++++++++++ 5 files changed, 84 insertions(+), 9 deletions(-) create mode 100644 Content.Shared/Tiles/ProtectedGridSystem.cs diff --git a/Content.Shared/RCD/Systems/RCDSystem.cs b/Content.Shared/RCD/Systems/RCDSystem.cs index 2025f2f3cc..238daf6bf7 100644 --- a/Content.Shared/RCD/Systems/RCDSystem.cs +++ b/Content.Shared/RCD/Systems/RCDSystem.cs @@ -395,7 +395,7 @@ public sealed class RCDSystem : EntitySystem if (prototype.Mode == RcdMode.ConstructTile) { // Check rule: Tile placement is valid - if (!_floors.CanPlaceTile(gridUid, mapGrid, out var reason)) + if (!_floors.CanPlaceTile(gridUid, mapGrid, tile.GridIndices, out var reason)) { if (popMsgs) _popup.PopupClient(reason, uid, user); diff --git a/Content.Shared/Tiles/FloorTileAttemptEvent.cs b/Content.Shared/Tiles/FloorTileAttemptEvent.cs index 7d4480f182..4a7dfc3d40 100644 --- a/Content.Shared/Tiles/FloorTileAttemptEvent.cs +++ b/Content.Shared/Tiles/FloorTileAttemptEvent.cs @@ -4,4 +4,4 @@ namespace Content.Shared.Tiles; /// Raised directed on a grid when attempting a floor tile placement. /// [ByRefEvent] -public record struct FloorTileAttemptEvent(bool Cancelled); +public record struct FloorTileAttemptEvent(Vector2i GridIndices, bool Cancelled = false); diff --git a/Content.Shared/Tiles/FloorTileSystem.cs b/Content.Shared/Tiles/FloorTileSystem.cs index 9b78904859..d798fa2473 100644 --- a/Content.Shared/Tiles/FloorTileSystem.cs +++ b/Content.Shared/Tiles/FloorTileSystem.cs @@ -126,14 +126,14 @@ public sealed class FloorTileSystem : EntitySystem if (mapGrid != null) { var gridUid = location.EntityId; + var tile = _map.GetTileRef(gridUid, mapGrid, location); - if (!CanPlaceTile(gridUid, mapGrid, out var reason)) + if (!CanPlaceTile(gridUid, mapGrid, tile.GridIndices, out var reason)) { _popup.PopupClient(reason, args.User, args.User); return; } - var tile = _map.GetTileRef(gridUid, mapGrid, location); var baseTurf = (ContentTileDefinition) _tileDefinitionManager[tile.Tile.TypeId]; if (HasBaseTurf(currentTileDefinition, baseTurf.ID)) @@ -182,12 +182,12 @@ public sealed class FloorTileSystem : EntitySystem _audio.PlayPredicted(placeSound, location, user); } - public bool CanPlaceTile(EntityUid gridUid, MapGridComponent component, [NotNullWhen(false)] out string? reason) + public bool CanPlaceTile(EntityUid gridUid, MapGridComponent component, Vector2i gridIndices, [NotNullWhen(false)] out string? reason) { - var ev = new FloorTileAttemptEvent(); + var ev = new FloorTileAttemptEvent(gridIndices); RaiseLocalEvent(gridUid, ref ev); - if (HasComp(gridUid) || ev.Cancelled) + if (ev.Cancelled) { reason = Loc.GetString("invalid-floor-placement"); return false; diff --git a/Content.Shared/Tiles/ProtectedGridComponent.cs b/Content.Shared/Tiles/ProtectedGridComponent.cs index cf71edbe2b..6b8e8df4ca 100644 --- a/Content.Shared/Tiles/ProtectedGridComponent.cs +++ b/Content.Shared/Tiles/ProtectedGridComponent.cs @@ -5,8 +5,13 @@ namespace Content.Shared.Tiles; /// /// Prevents floor tile updates when attached to a grid. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(ProtectedGridSystem))] public sealed partial class ProtectedGridComponent : Component { - + /// + /// A bitmask of all the initial tiles on this grid. + /// + [DataField, AutoNetworkedField] + public Dictionary BaseIndices = new(); } diff --git a/Content.Shared/Tiles/ProtectedGridSystem.cs b/Content.Shared/Tiles/ProtectedGridSystem.cs new file mode 100644 index 0000000000..0d6f5b7a6d --- /dev/null +++ b/Content.Shared/Tiles/ProtectedGridSystem.cs @@ -0,0 +1,70 @@ +using System.Linq; +using Robust.Shared.Map.Components; +using Robust.Shared.Map.Enumerators; + +namespace Content.Shared.Tiles; + +public sealed class ProtectedGridSystem : EntitySystem +{ + [Dependency] private readonly SharedMapSystem _map = default!; + + /// + public override void Initialize() + { + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnFloorTileAttempt); + } + + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + if (!TryComp(ent, out var grid)) + return; + + // Engine default is currently 16x size chunks which means we can't just easily have 64bit flags. + var chunkEnumerator = new ChunkIndicesEnumerator(grid.LocalAABB, 8); + + while (chunkEnumerator.MoveNext(out var chunk)) + { + ulong flag = 0; + + for (var x = 0; x < 8; x++) + { + for (var y = 0; y < 8; y++) + { + var index = new Vector2i(x + chunk.Value.X * 8, y + chunk.Value.Y * 8); + var tile = _map.GetTileRef(ent.Owner, grid, index); + + if (tile.Tile.IsEmpty) + continue; + + var data = SharedMapSystem.ToBitmask(new Vector2i(x, y)); + + flag |= data; + } + } + + if (flag == 0) + continue; + + ent.Comp.BaseIndices[chunk.Value] = flag; + } + + Dirty(ent); + } + + private void OnFloorTileAttempt(Entity ent, ref FloorTileAttemptEvent args) + { + var chunkOrigin = SharedMapSystem.GetChunkIndices(args.GridIndices, 8); + + if (!ent.Comp.BaseIndices.TryGetValue(chunkOrigin, out var data)) + { + args.Cancelled = true; + return; + } + + if (SharedMapSystem.FromBitmask(args.GridIndices, data)) + { + args.Cancelled = true; + } + } +}