using Content.Server.Atmos.EntitySystems;
using Content.Server.NodeContainer;
using Content.Server.NodeContainer.NodeGroups;
+using Content.Server.Shuttles.Components;
using Content.Shared.Atmos;
using Content.Shared.Spreader;
+using Content.Shared.Tag;
using Robust.Shared.Collections;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
private readonly List<string> _spreaderGroups = new();
+ private const string IgnoredTag = "SpreaderIgnore";
+
/// <inheritdoc/>
public override void Initialize()
{
private void Spread(EntityUid uid, SpreaderNode node, INodeGroup group, ref int updates)
{
- GetNeighbors(uid, node.Name, out var freeTiles, out var occupiedTiles, out var neighbors);
-
- TryComp<MapGridComponent>(Transform(uid).GridUid, out var grid);
+ GetNeighbors(uid, node.Name, out var freeTiles, out _, out var neighbors);
var ev = new SpreadNeighborsEvent()
{
- Grid = grid,
NeighborFreeTiles = freeTiles,
- NeighborOccupiedTiles = occupiedTiles,
Neighbors = neighbors,
Updates = updates,
};
/// <summary>
/// Gets the neighboring node data for the specified entity and the specified node group.
/// </summary>
- public void GetNeighbors(EntityUid uid, string groupName, out ValueList<Vector2i> freeTiles, out ValueList<Vector2i> occupiedTiles, out ValueList<EntityUid> neighbors)
+ public void GetNeighbors(EntityUid uid, string groupName, out ValueList<(MapGridComponent Grid, Vector2i Tile)> freeTiles, out ValueList<Vector2i> occupiedTiles, out ValueList<EntityUid> neighbors)
{
- freeTiles = new ValueList<Vector2i>();
+ freeTiles = new ValueList<(MapGridComponent Grid, Vector2i Tile)>();
occupiedTiles = new ValueList<Vector2i>();
neighbors = new ValueList<EntityUid>();
var tile = grid.TileIndicesFor(transform.Coordinates);
var nodeQuery = GetEntityQuery<NodeContainerComponent>();
var airtightQuery = GetEntityQuery<AirtightComponent>();
+ var dockQuery = GetEntityQuery<DockingComponent>();
+ var xformQuery = GetEntityQuery<TransformComponent>();
+ var tagQuery = GetEntityQuery<TagComponent>();
+ var blockedAtmosDirs = AtmosDirection.Invalid;
+
+ // Due to docking ports they may not necessarily be opposite directions.
+ var neighborTiles = new ValueList<(MapGridComponent grid, Vector2i Indices, AtmosDirection OtherDir, AtmosDirection OurDir)>();
+
+ // Check if anything on our own tile blocking that direction.
+ var ourEnts = grid.GetAnchoredEntitiesEnumerator(tile);
+
+ while (ourEnts.MoveNext(out var ent))
+ {
+ // Spread via docks in a special-case.
+ if (dockQuery.TryGetComponent(ent, out var dock) &&
+ dock.Docked &&
+ xformQuery.TryGetComponent(ent, out var xform) &&
+ xformQuery.TryGetComponent(dock.DockedWith, out var dockedXform) &&
+ TryComp<MapGridComponent>(dockedXform.GridUid, out var dockedGrid))
+ {
+ neighborTiles.Add((dockedGrid, dockedGrid.CoordinatesToTile(dockedXform.Coordinates), xform.LocalRotation.ToAtmosDirection(), dockedXform.LocalRotation.ToAtmosDirection()));
+ }
+ // If we're on a blocked tile work out which directions we can go.
+ if (!airtightQuery.TryGetComponent(ent, out var airtight) || !airtight.AirBlocked ||
+ tagQuery.TryGetComponent(ent, out var tags) && tags.Tags.Contains(IgnoredTag))
+ {
+ continue;
+ }
+
+ foreach (var value in new[] { AtmosDirection.North, AtmosDirection.East, AtmosDirection.South, AtmosDirection.West})
+ {
+ if ((value & airtight.AirBlockedDirection) == 0x0)
+ continue;
+
+ blockedAtmosDirs |= value;
+ break;
+ }
+ break;
+ }
+
+ // Add the normal neighbors.
for (var i = 0; i < 4; i++)
{
var direction = (Direction) (i * 2);
+ var atmosDir = direction.ToAtmosDirection();
var neighborPos = SharedMapSystem.GetDirection(tile, direction);
+ neighborTiles.Add((grid, neighborPos, atmosDir, atmosDir.GetOpposite()));
+ }
- if (!grid.TryGetTileRef(neighborPos, out var tileRef) || tileRef.Tile.IsEmpty)
+ foreach (var (neighborGrid, neighborPos, ourAtmosDir, otherAtmosDir) in neighborTiles)
+ {
+ // This tile is blocked to that direction.
+ if ((blockedAtmosDirs & ourAtmosDir) != 0x0)
+ continue;
+
+ if (!neighborGrid.TryGetTileRef(neighborPos, out var tileRef) || tileRef.Tile.IsEmpty)
continue;
var directionEnumerator =
- grid.GetAnchoredEntitiesEnumerator(neighborPos);
+ neighborGrid.GetAnchoredEntitiesEnumerator(neighborPos);
var occupied = false;
while (directionEnumerator.MoveNext(out var ent))
{
- if (airtightQuery.TryGetComponent(ent, out var airtight) && airtight.AirBlocked)
+ if (!airtightQuery.TryGetComponent(ent, out var airtight) || !airtight.AirBlocked ||
+ tagQuery.TryGetComponent(ent, out var tags) && tags.Tags.Contains(IgnoredTag))
{
- // Check if air direction matters.
- var blocked = false;
-
- foreach (var value in new[] { AtmosDirection.North, AtmosDirection.East})
- {
- if ((value & airtight.AirBlockedDirection) == 0x0)
- continue;
-
- var airDirection = value.ToDirection();
- var oppositeDirection = value.ToDirection().GetOpposite();
-
- if (direction != airDirection && direction != oppositeDirection)
- continue;
-
- blocked = true;
- break;
- }
+ continue;
+ }
- if (!blocked)
- continue;
+ if ((airtight.AirBlockedDirection & otherAtmosDir) == 0x0)
+ continue;
- occupied = true;
- break;
- }
+ occupied = true;
+ break;
}
if (occupied)
var oldCount = occupiedTiles.Count;
directionEnumerator =
- grid.GetAnchoredEntitiesEnumerator(neighborPos);
+ neighborGrid.GetAnchoredEntitiesEnumerator(neighborPos);
while (directionEnumerator.MoveNext(out var ent))
{
}
if (oldCount == occupiedTiles.Count)
- freeTiles.Add(neighborPos);
+ freeTiles.Add((neighborGrid, neighborPos));
}
}