Puddles & spreader refactor (#15191)
This commit is contained in:
10
Content.Server/Spreader/EdgeSpreaderComponent.cs
Normal file
10
Content.Server/Spreader/EdgeSpreaderComponent.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Content.Server.Spreader;
|
||||
|
||||
/// <summary>
|
||||
/// Added to entities being considered for spreading via <see cref="SpreaderSystem"/>.
|
||||
/// This needs to be manually added and removed.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(SpreaderSystem))]
|
||||
public sealed class EdgeSpreaderComponent : Component
|
||||
{
|
||||
}
|
||||
12
Content.Server/Spreader/EdgeSpreaderPrototype.cs
Normal file
12
Content.Server/Spreader/EdgeSpreaderPrototype.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Spreader;
|
||||
|
||||
/// <summary>
|
||||
/// Adds this node group to <see cref="SpreaderSystem"/> for tick updates.
|
||||
/// </summary>
|
||||
[Prototype("edgeSpreader")]
|
||||
public sealed class EdgeSpreaderPrototype : IPrototype
|
||||
{
|
||||
[IdDataField] public string ID { get; } = string.Empty;
|
||||
}
|
||||
22
Content.Server/Spreader/GrowingKudzuComponent.cs
Normal file
22
Content.Server/Spreader/GrowingKudzuComponent.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||
|
||||
namespace Content.Server.Spreader;
|
||||
|
||||
[RegisterComponent, Access(typeof(KudzuSystem))]
|
||||
public sealed class GrowingKudzuComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// At level 3 spreading can occur; prior to that we have a chance of increasing our growth level and changing our sprite.
|
||||
/// </summary>
|
||||
[DataField("growthLevel")]
|
||||
public int GrowthLevel = 1;
|
||||
|
||||
[DataField("growthTickChance")]
|
||||
public float GrowthTickChance = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// The next time kudzu will try to tick its growth level.
|
||||
/// </summary>
|
||||
[DataField("nextTick", customTypeSerializer:typeof(TimeOffsetSerializer))]
|
||||
public TimeSpan NextTick = TimeSpan.Zero;
|
||||
}
|
||||
14
Content.Server/Spreader/KudzuComponent.cs
Normal file
14
Content.Server/Spreader/KudzuComponent.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace Content.Server.Spreader;
|
||||
|
||||
/// <summary>
|
||||
/// Handles entities that spread out when they reach the relevant growth level.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed class KudzuComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Chance to spread whenever an edge spread is possible.
|
||||
/// </summary>
|
||||
[DataField("spreadChance")]
|
||||
public float SpreadChance = 1f;
|
||||
}
|
||||
114
Content.Server/Spreader/KudzuSystem.cs
Normal file
114
Content.Server/Spreader/KudzuSystem.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
using Content.Shared.Kudzu;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Spreader;
|
||||
|
||||
public sealed class KudzuSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
|
||||
private const string KudzuGroup = "kudzu";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<KudzuComponent, ComponentStartup>(SetupKudzu);
|
||||
SubscribeLocalEvent<KudzuComponent, SpreadNeighborsEvent>(OnKudzuSpread);
|
||||
SubscribeLocalEvent<GrowingKudzuComponent, EntityUnpausedEvent>(OnKudzuUnpaused);
|
||||
SubscribeLocalEvent<SpreadGroupUpdateRate>(OnKudzuUpdateRate);
|
||||
}
|
||||
|
||||
private void OnKudzuSpread(EntityUid uid, KudzuComponent component, ref SpreadNeighborsEvent args)
|
||||
{
|
||||
if (TryComp<GrowingKudzuComponent>(uid, out var growing) && growing.GrowthLevel < 3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.NeighborFreeTiles.Count == 0 || args.Grid == null)
|
||||
{
|
||||
RemCompDeferred<EdgeSpreaderComponent>(uid);
|
||||
return;
|
||||
}
|
||||
|
||||
var prototype = MetaData(uid).EntityPrototype?.ID;
|
||||
|
||||
if (prototype == null)
|
||||
{
|
||||
RemCompDeferred<EdgeSpreaderComponent>(uid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_robustRandom.Prob(component.SpreadChance))
|
||||
return;
|
||||
|
||||
foreach (var neighbor in args.NeighborFreeTiles)
|
||||
{
|
||||
var neighborUid = Spawn(prototype, args.Grid.GridTileToLocal(neighbor));
|
||||
EnsureComp<EdgeSpreaderComponent>(neighborUid);
|
||||
args.Updates--;
|
||||
|
||||
if (args.Updates <= 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnKudzuUpdateRate(ref SpreadGroupUpdateRate args)
|
||||
{
|
||||
if (args.Name != KudzuGroup)
|
||||
return;
|
||||
|
||||
args.UpdatesPerSecond = 1;
|
||||
}
|
||||
|
||||
private void OnKudzuUnpaused(EntityUid uid, GrowingKudzuComponent component, ref EntityUnpausedEvent args)
|
||||
{
|
||||
component.NextTick += args.PausedTime;
|
||||
}
|
||||
|
||||
private void SetupKudzu(EntityUid uid, KudzuComponent component, ComponentStartup args)
|
||||
{
|
||||
if (!EntityManager.TryGetComponent<AppearanceComponent>(uid, out var appearance))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_appearance.SetData(uid, KudzuVisuals.Variant, _robustRandom.Next(1, 3), appearance);
|
||||
_appearance.SetData(uid, KudzuVisuals.GrowthLevel, 1, appearance);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
var query = EntityQueryEnumerator<GrowingKudzuComponent, AppearanceComponent>();
|
||||
var curTime = _timing.CurTime;
|
||||
|
||||
while (query.MoveNext(out var uid, out var kudzu, out var appearance))
|
||||
{
|
||||
if (kudzu.NextTick > curTime)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
kudzu.NextTick = curTime + TimeSpan.FromSeconds(0.5);
|
||||
|
||||
if (!_robustRandom.Prob(kudzu.GrowthTickChance))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
kudzu.GrowthLevel += 1;
|
||||
|
||||
if (kudzu.GrowthLevel >= 3)
|
||||
{
|
||||
// why cache when you can simply cease to be? Also saves a bit of memory/time.
|
||||
RemCompDeferred<GrowingKudzuComponent>(uid);
|
||||
}
|
||||
|
||||
_appearance.SetData(uid, KudzuVisuals.GrowthLevel, kudzu.GrowthLevel, appearance);
|
||||
}
|
||||
}
|
||||
}
|
||||
7
Content.Server/Spreader/SpreadGroupUpdateRate.cs
Normal file
7
Content.Server/Spreader/SpreadGroupUpdateRate.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Content.Server.Spreader;
|
||||
|
||||
/// <summary>
|
||||
/// Raised every tick to determine how many updates a particular spreading node group is allowed.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public record struct SpreadGroupUpdateRate(string Name, int UpdatesPerSecond = 16);
|
||||
23
Content.Server/Spreader/SpreadNeighborsEvent.cs
Normal file
23
Content.Server/Spreader/SpreadNeighborsEvent.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Robust.Shared.Collections;
|
||||
using Robust.Shared.Map.Components;
|
||||
|
||||
namespace Content.Server.Spreader;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when trying to spread to neighboring tiles.
|
||||
/// If the spread is no longer able to happen you MUST cancel this event!
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public record struct SpreadNeighborsEvent
|
||||
{
|
||||
public MapGridComponent? Grid;
|
||||
public ValueList<Vector2i> NeighborFreeTiles;
|
||||
public ValueList<Vector2i> NeighborOccupiedTiles;
|
||||
public ValueList<EntityUid> Neighbors;
|
||||
|
||||
/// <summary>
|
||||
/// How many updates allowed are remaining.
|
||||
/// Subscribers can handle as they wish.
|
||||
/// </summary>
|
||||
public int Updates;
|
||||
}
|
||||
10
Content.Server/Spreader/SpreaderGridComponent.cs
Normal file
10
Content.Server/Spreader/SpreaderGridComponent.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||
|
||||
namespace Content.Server.Spreader;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed class SpreaderGridComponent : Component
|
||||
{
|
||||
[DataField("nextUpdate", customTypeSerializer:typeof(TimeOffsetSerializer))]
|
||||
public TimeSpan NextUpdate = TimeSpan.Zero;
|
||||
}
|
||||
33
Content.Server/Spreader/SpreaderNode.cs
Normal file
33
Content.Server/Spreader/SpreaderNode.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Robust.Shared.Map.Components;
|
||||
|
||||
namespace Content.Server.Spreader;
|
||||
|
||||
/// <summary>
|
||||
/// Handles the node for <see cref="EdgeSpreaderComponent"/>.
|
||||
/// Functions as a generic tile-based entity spreader for systems such as puddles or smoke.
|
||||
/// </summary>
|
||||
public sealed class SpreaderNode : Node
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override IEnumerable<Node> GetReachableNodes(TransformComponent xform, EntityQuery<NodeContainerComponent> nodeQuery, EntityQuery<TransformComponent> xformQuery,
|
||||
MapGridComponent? grid, IEntityManager entMan)
|
||||
{
|
||||
if (grid == null)
|
||||
yield break;
|
||||
|
||||
entMan.System<SpreaderSystem>().GetNeighbors(xform.Owner, Name, out _, out _, out var neighbors);
|
||||
|
||||
foreach (var neighbor in neighbors)
|
||||
{
|
||||
if (!nodeQuery.TryGetComponent(neighbor, out var nodeContainer) ||
|
||||
!nodeContainer.TryGetNode<SpreaderNode>(Name, out var neighborNode))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return neighborNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
31
Content.Server/Spreader/SpreaderNodeGroup.cs
Normal file
31
Content.Server/Spreader/SpreaderNodeGroup.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Content.Server.NodeContainer.NodeGroups;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
|
||||
namespace Content.Server.Spreader;
|
||||
|
||||
[NodeGroup(NodeGroupID.Spreader)]
|
||||
public sealed class SpreaderNodeGroup : BaseNodeGroup
|
||||
{
|
||||
private IEntityManager _entManager = default!;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize(Node sourceNode, IEntityManager entMan)
|
||||
{
|
||||
base.Initialize(sourceNode, entMan);
|
||||
_entManager = entMan;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void RemoveNode(Node node)
|
||||
{
|
||||
base.RemoveNode(node);
|
||||
|
||||
foreach (var neighborNode in node.ReachableNodes)
|
||||
{
|
||||
if (_entManager.Deleted(neighborNode.Owner))
|
||||
continue;
|
||||
|
||||
_entManager.EnsureComponent<EdgeSpreaderComponent>(neighborNode.Owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
324
Content.Server/Spreader/SpreaderSystem.cs
Normal file
324
Content.Server/Spreader/SpreaderSystem.cs
Normal file
@@ -0,0 +1,324 @@
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Server.NodeContainer.NodeGroups;
|
||||
using Content.Shared.Atmos;
|
||||
using Robust.Shared.Collections;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Spreader;
|
||||
|
||||
/// <summary>
|
||||
/// Handles generic spreading logic, where one anchored entity spreads to neighboring tiles.
|
||||
/// </summary>
|
||||
public sealed class SpreaderSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
||||
|
||||
private static readonly TimeSpan SpreadCooldown = TimeSpan.FromSeconds(1);
|
||||
|
||||
private readonly List<string> _spreaderGroups = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<AirtightChanged>(OnAirtightChanged);
|
||||
SubscribeLocalEvent<GridInitializeEvent>(OnGridInit);
|
||||
SubscribeLocalEvent<SpreaderGridComponent, EntityUnpausedEvent>(OnGridUnpaused);
|
||||
|
||||
SetupPrototypes();
|
||||
_prototype.PrototypesReloaded += OnPrototypeReload;
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
_prototype.PrototypesReloaded -= OnPrototypeReload;
|
||||
}
|
||||
|
||||
private void OnPrototypeReload(PrototypesReloadedEventArgs obj)
|
||||
{
|
||||
if (!obj.ByType.ContainsKey(typeof(EdgeSpreaderPrototype)))
|
||||
return;
|
||||
|
||||
SetupPrototypes();
|
||||
}
|
||||
|
||||
private void SetupPrototypes()
|
||||
{
|
||||
_spreaderGroups.Clear();
|
||||
|
||||
foreach (var id in _prototype.EnumeratePrototypes<EdgeSpreaderPrototype>())
|
||||
{
|
||||
_spreaderGroups.Add(id.ID);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAirtightChanged(ref AirtightChanged ev)
|
||||
{
|
||||
var neighbors = GetNeighbors(ev.Entity, ev.Airtight);
|
||||
|
||||
foreach (var neighbor in neighbors)
|
||||
{
|
||||
EnsureComp<EdgeSpreaderComponent>(neighbor);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGridUnpaused(EntityUid uid, SpreaderGridComponent component, ref EntityUnpausedEvent args)
|
||||
{
|
||||
component.NextUpdate += args.PausedTime;
|
||||
}
|
||||
|
||||
private void OnGridInit(GridInitializeEvent ev)
|
||||
{
|
||||
var comp = EnsureComp<SpreaderGridComponent>(ev.EntityUid);
|
||||
var nextUpdate = _timing.CurTime;
|
||||
|
||||
// TODO: I believe we need grid mapinit events so we can set the time correctly only on mapinit
|
||||
// and not touch it on regular init.
|
||||
if (comp.NextUpdate < nextUpdate)
|
||||
comp.NextUpdate = nextUpdate;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
var curTime = _timing.CurTime;
|
||||
|
||||
// Check which grids are valid for spreading.
|
||||
var spreadable = new ValueList<EntityUid>();
|
||||
var spreadGrids = EntityQueryEnumerator<SpreaderGridComponent>();
|
||||
|
||||
while (spreadGrids.MoveNext(out var uid, out var grid))
|
||||
{
|
||||
if (grid.NextUpdate > curTime)
|
||||
continue;
|
||||
|
||||
spreadable.Add(uid);
|
||||
grid.NextUpdate += SpreadCooldown;
|
||||
}
|
||||
|
||||
if (spreadable.Count == 0)
|
||||
return;
|
||||
|
||||
var query = EntityQueryEnumerator<EdgeSpreaderComponent>();
|
||||
var nodeQuery = GetEntityQuery<NodeContainerComponent>();
|
||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||
var gridQuery = GetEntityQuery<SpreaderGridComponent>();
|
||||
|
||||
// Events and stuff
|
||||
var groupUpdates = new Dictionary<INodeGroup, int>();
|
||||
var spreaders = new List<(EntityUid Uid, EdgeSpreaderComponent Comp)>(Count<EdgeSpreaderComponent>());
|
||||
|
||||
while (query.MoveNext(out var uid, out var comp))
|
||||
{
|
||||
spreaders.Add((uid, comp));
|
||||
}
|
||||
|
||||
_robustRandom.Shuffle(spreaders);
|
||||
|
||||
foreach (var (uid, comp) in spreaders)
|
||||
{
|
||||
if (!xformQuery.TryGetComponent(uid, out var xform) ||
|
||||
xform.GridUid == null ||
|
||||
!gridQuery.HasComponent(xform.GridUid.Value))
|
||||
{
|
||||
RemCompDeferred<EdgeSpreaderComponent>(uid);
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var sGroup in _spreaderGroups)
|
||||
{
|
||||
// Cleanup
|
||||
if (!nodeQuery.TryGetComponent(uid, out var nodeComponent))
|
||||
{
|
||||
RemCompDeferred<EdgeSpreaderComponent>(uid);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!nodeComponent.TryGetNode<SpreaderNode>(sGroup, out var node))
|
||||
continue;
|
||||
|
||||
// Not allowed this tick?
|
||||
if (node.NodeGroup == null ||
|
||||
!spreadable.Contains(xform.GridUid.Value))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// While we could check if it's an edge here the subscribing system may have its own definition
|
||||
// of an edge so we'll let them handle it.
|
||||
if (!groupUpdates.TryGetValue(node.NodeGroup, out var updates))
|
||||
{
|
||||
var spreadEv = new SpreadGroupUpdateRate()
|
||||
{
|
||||
Name = node.Name,
|
||||
};
|
||||
RaiseLocalEvent(ref spreadEv);
|
||||
updates = (int) (spreadEv.UpdatesPerSecond * SpreadCooldown / TimeSpan.FromSeconds(1));
|
||||
}
|
||||
|
||||
if (updates <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Spread(uid, node, node.NodeGroup, ref updates);
|
||||
groupUpdates[node.NodeGroup] = updates;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
var ev = new SpreadNeighborsEvent()
|
||||
{
|
||||
Grid = grid,
|
||||
NeighborFreeTiles = freeTiles,
|
||||
NeighborOccupiedTiles = occupiedTiles,
|
||||
Neighbors = neighbors,
|
||||
Updates = updates,
|
||||
};
|
||||
|
||||
RaiseLocalEvent(uid, ref ev);
|
||||
updates = ev.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)
|
||||
{
|
||||
freeTiles = new ValueList<Vector2i>();
|
||||
occupiedTiles = new ValueList<Vector2i>();
|
||||
neighbors = new ValueList<EntityUid>();
|
||||
|
||||
if (!EntityManager.TryGetComponent<TransformComponent>(uid, out var transform))
|
||||
return;
|
||||
|
||||
if (!_mapManager.TryGetGrid(transform.GridUid, out var grid))
|
||||
return;
|
||||
|
||||
var tile = grid.TileIndicesFor(transform.Coordinates);
|
||||
var nodeQuery = GetEntityQuery<NodeContainerComponent>();
|
||||
var airtightQuery = GetEntityQuery<AirtightComponent>();
|
||||
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
var direction = (Direction) (i * 2);
|
||||
var neighborPos = SharedMapSystem.GetDirection(tile, direction);
|
||||
|
||||
if (!grid.TryGetTileRef(neighborPos, out var tileRef) || tileRef.Tile.IsEmpty)
|
||||
continue;
|
||||
|
||||
var directionEnumerator =
|
||||
grid.GetAnchoredEntitiesEnumerator(neighborPos);
|
||||
var occupied = false;
|
||||
|
||||
while (directionEnumerator.MoveNext(out var ent))
|
||||
{
|
||||
if (airtightQuery.TryGetComponent(ent, out var airtight) && airtight.AirBlocked)
|
||||
{
|
||||
// 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();
|
||||
|
||||
if (direction != airDirection && direction != oppositeDirection)
|
||||
continue;
|
||||
|
||||
blocked = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!blocked)
|
||||
continue;
|
||||
|
||||
occupied = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (occupied)
|
||||
continue;
|
||||
|
||||
var oldCount = occupiedTiles.Count;
|
||||
directionEnumerator =
|
||||
grid.GetAnchoredEntitiesEnumerator(neighborPos);
|
||||
|
||||
while (directionEnumerator.MoveNext(out var ent))
|
||||
{
|
||||
if (!nodeQuery.TryGetComponent(ent, out var nodeContainer))
|
||||
continue;
|
||||
|
||||
if (!nodeContainer.Nodes.ContainsKey(groupName))
|
||||
continue;
|
||||
|
||||
neighbors.Add(ent.Value);
|
||||
occupiedTiles.Add(neighborPos);
|
||||
break;
|
||||
}
|
||||
|
||||
if (oldCount == occupiedTiles.Count)
|
||||
freeTiles.Add(neighborPos);
|
||||
}
|
||||
}
|
||||
|
||||
public List<EntityUid> GetNeighbors(EntityUid uid, AirtightComponent comp)
|
||||
{
|
||||
var neighbors = new List<EntityUid>();
|
||||
|
||||
if (!EntityManager.TryGetComponent<TransformComponent>(uid, out var transform))
|
||||
return neighbors; // how did we get here?
|
||||
|
||||
if (!_mapManager.TryGetGrid(transform.GridUid, out var grid))
|
||||
return neighbors;
|
||||
|
||||
var tile = grid.TileIndicesFor(transform.Coordinates);
|
||||
var nodeQuery = GetEntityQuery<NodeContainerComponent>();
|
||||
|
||||
for (var i = 0; i < Atmospherics.Directions; i++)
|
||||
{
|
||||
var direction = (AtmosDirection) (1 << i);
|
||||
if (!comp.AirBlockedDirection.IsFlagSet(direction))
|
||||
continue;
|
||||
|
||||
var directionEnumerator =
|
||||
grid.GetAnchoredEntitiesEnumerator(SharedMapSystem.GetDirection(tile, direction.ToDirection()));
|
||||
|
||||
while (directionEnumerator.MoveNext(out var ent))
|
||||
{
|
||||
if (!nodeQuery.TryGetComponent(ent, out var nodeContainer))
|
||||
continue;
|
||||
|
||||
foreach (var name in _spreaderGroups)
|
||||
{
|
||||
if (!nodeContainer.Nodes.ContainsKey(name))
|
||||
continue;
|
||||
|
||||
neighbors.Add(ent.Value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return neighbors;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user