Remove SpreaderNodeGroup (#20230)
* Remove SpreaderNodeGroup * Fix airtight updates * more smoke stuff * more smoke fixes * wtf is smoke code * Fix merge * Fix divide by zero
This commit is contained in:
@@ -21,7 +21,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
SubscribeLocalEvent<AirtightComponent, ComponentShutdown>(OnAirtightShutdown);
|
SubscribeLocalEvent<AirtightComponent, ComponentShutdown>(OnAirtightShutdown);
|
||||||
SubscribeLocalEvent<AirtightComponent, AnchorStateChangedEvent>(OnAirtightPositionChanged);
|
SubscribeLocalEvent<AirtightComponent, AnchorStateChangedEvent>(OnAirtightPositionChanged);
|
||||||
SubscribeLocalEvent<AirtightComponent, ReAnchorEvent>(OnAirtightReAnchor);
|
SubscribeLocalEvent<AirtightComponent, ReAnchorEvent>(OnAirtightReAnchor);
|
||||||
SubscribeLocalEvent<AirtightComponent, MoveEvent>(OnAirtightRotated);
|
SubscribeLocalEvent<AirtightComponent, MoveEvent>(OnAirtightMoved);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAirtightInit(EntityUid uid, AirtightComponent airtight, ComponentInit args)
|
private void OnAirtightInit(EntityUid uid, AirtightComponent airtight, ComponentInit args)
|
||||||
@@ -31,7 +31,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
if (airtight.FixAirBlockedDirectionInitialize)
|
if (airtight.FixAirBlockedDirectionInitialize)
|
||||||
{
|
{
|
||||||
var moveEvent = new MoveEvent(uid, default, default, Angle.Zero, xform.LocalRotation, xform, false);
|
var moveEvent = new MoveEvent(uid, default, default, Angle.Zero, xform.LocalRotation, xform, false);
|
||||||
if (AirtightRotate(uid, airtight, ref moveEvent))
|
if (AirtightMove(uid, airtight, ref moveEvent))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,19 +78,20 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAirtightRotated(EntityUid uid, AirtightComponent airtight, ref MoveEvent ev)
|
private void OnAirtightMoved(EntityUid uid, AirtightComponent airtight, ref MoveEvent ev)
|
||||||
{
|
{
|
||||||
AirtightRotate(uid, airtight, ref ev);
|
AirtightMove(uid, airtight, ref ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool AirtightRotate(EntityUid uid, AirtightComponent airtight, ref MoveEvent ev)
|
private bool AirtightMove(EntityUid uid, AirtightComponent airtight, ref MoveEvent ev)
|
||||||
{
|
{
|
||||||
if (!airtight.RotateAirBlocked || airtight.InitialAirBlockedDirection == (int)AtmosDirection.Invalid)
|
if (!airtight.RotateAirBlocked || airtight.InitialAirBlockedDirection == (int)AtmosDirection.Invalid)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
airtight.CurrentAirBlockedDirection = (int) Rotate((AtmosDirection)airtight.InitialAirBlockedDirection, ev.NewRotation);
|
airtight.CurrentAirBlockedDirection = (int) Rotate((AtmosDirection)airtight.InitialAirBlockedDirection, ev.NewRotation);
|
||||||
|
var pos = airtight.LastPosition;
|
||||||
UpdatePosition(airtight, ev.Component);
|
UpdatePosition(airtight, ev.Component);
|
||||||
var airtightEv = new AirtightChanged(uid, airtight);
|
var airtightEv = new AirtightChanged(uid, airtight, pos);
|
||||||
RaiseLocalEvent(uid, ref airtightEv, true);
|
RaiseLocalEvent(uid, ref airtightEv, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -100,11 +101,13 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
if (airtight.AirBlocked == airblocked)
|
if (airtight.AirBlocked == airblocked)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!Resolve(airtight.Owner, ref xform)) return;
|
if (!Resolve(uid, ref xform))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var pos = airtight.LastPosition;
|
||||||
airtight.AirBlocked = airblocked;
|
airtight.AirBlocked = airblocked;
|
||||||
UpdatePosition(airtight, xform);
|
UpdatePosition(airtight, xform);
|
||||||
var airtightEv = new AirtightChanged(uid, airtight);
|
var airtightEv = new AirtightChanged(uid, airtight, pos);
|
||||||
RaiseLocalEvent(uid, ref airtightEv, true);
|
RaiseLocalEvent(uid, ref airtightEv, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,5 +157,6 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
}
|
}
|
||||||
|
|
||||||
[ByRefEvent]
|
[ByRefEvent]
|
||||||
public readonly record struct AirtightChanged(EntityUid Entity, AirtightComponent Airtight);
|
public readonly record struct AirtightChanged(EntityUid Entity, AirtightComponent Airtight,
|
||||||
|
(EntityUid Grid, Vector2i Tile) Position);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
|||||||
|
|
||||||
if (overflow.Volume == FixedPoint2.Zero)
|
if (overflow.Volume == FixedPoint2.Zero)
|
||||||
{
|
{
|
||||||
RemCompDeferred<EdgeSpreaderComponent>(uid);
|
RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +137,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
args.Updates--;
|
args.Updates--;
|
||||||
EnsureComp<EdgeSpreaderComponent>(neighbor);
|
EnsureComp<ActiveEdgeSpreaderComponent>(neighbor);
|
||||||
|
|
||||||
if (args.Updates <= 0)
|
if (args.Updates <= 0)
|
||||||
break;
|
break;
|
||||||
@@ -145,7 +145,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
|||||||
|
|
||||||
if (overflow.Volume == FixedPoint2.Zero)
|
if (overflow.Volume == FixedPoint2.Zero)
|
||||||
{
|
{
|
||||||
RemCompDeferred<EdgeSpreaderComponent>(uid);
|
RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,7 +168,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
RemCompDeferred<EdgeSpreaderComponent>(uid);
|
RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +192,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
|||||||
if (!_solutionContainerSystem.TryAddSolution(neighbor, neighborSolution, split))
|
if (!_solutionContainerSystem.TryAddSolution(neighbor, neighborSolution, split))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
EnsureComp<EdgeSpreaderComponent>(neighbor);
|
EnsureComp<ActiveEdgeSpreaderComponent>(neighbor);
|
||||||
args.Updates--;
|
args.Updates--;
|
||||||
|
|
||||||
if (args.Updates <= 0)
|
if (args.Updates <= 0)
|
||||||
@@ -438,7 +438,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
|||||||
|
|
||||||
if (checkForOverflow && IsOverflowing(puddleUid, puddleComponent))
|
if (checkForOverflow && IsOverflowing(puddleUid, puddleComponent))
|
||||||
{
|
{
|
||||||
EnsureComp<EdgeSpreaderComponent>(puddleUid);
|
EnsureComp<ActiveEdgeSpreaderComponent>(puddleUid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sound)
|
if (!sound)
|
||||||
@@ -638,7 +638,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
|||||||
|
|
||||||
if (TryAddSolution(ent.Value, solution, sound, puddleComponent: puddle))
|
if (TryAddSolution(ent.Value, solution, sound, puddleComponent: puddle))
|
||||||
{
|
{
|
||||||
EnsureComp<EdgeSpreaderComponent>(ent.Value);
|
EnsureComp<ActiveEdgeSpreaderComponent>(ent.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
puddleUid = ent.Value;
|
puddleUid = ent.Value;
|
||||||
@@ -650,7 +650,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
|||||||
EnsureComp<PuddleComponent>(puddleUid);
|
EnsureComp<PuddleComponent>(puddleUid);
|
||||||
if (TryAddSolution(puddleUid, solution, sound))
|
if (TryAddSolution(puddleUid, solution, sound))
|
||||||
{
|
{
|
||||||
EnsureComp<EdgeSpreaderComponent>(puddleUid);
|
EnsureComp<ActiveEdgeSpreaderComponent>(puddleUid);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,16 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.Administration.Logs;
|
|
||||||
using Content.Server.Body.Components;
|
|
||||||
using Content.Server.Body.Systems;
|
|
||||||
using Content.Server.Chemistry.Components;
|
using Content.Server.Chemistry.Components;
|
||||||
using Content.Server.Chemistry.EntitySystems;
|
using Content.Server.Chemistry.EntitySystems;
|
||||||
using Content.Server.Chemistry.ReactionEffects;
|
using Content.Server.Chemistry.ReactionEffects;
|
||||||
using Content.Server.Spreader;
|
using Content.Server.Spreader;
|
||||||
using Content.Shared.Chemistry;
|
|
||||||
using Content.Shared.Chemistry.Components;
|
using Content.Shared.Chemistry.Components;
|
||||||
using Content.Shared.Chemistry.Reaction;
|
using Content.Shared.Chemistry.Reaction;
|
||||||
using Content.Shared.Chemistry.Reagent;
|
|
||||||
using Content.Shared.Coordinates.Helpers;
|
|
||||||
using Content.Shared.Database;
|
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Content.Shared.Smoking;
|
using Content.Shared.Smoking;
|
||||||
using Robust.Shared.Spawners;
|
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Spawners;
|
using Robust.Shared.Spawners;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using TimedDespawnComponent = Robust.Shared.Spawners.TimedDespawnComponent;
|
using TimedDespawnComponent = Robust.Shared.Spawners.TimedDespawnComponent;
|
||||||
@@ -36,6 +29,7 @@ public sealed class SmokeSystem : EntitySystem
|
|||||||
[Dependency] private readonly AppearanceSystem _appearance = default!;
|
[Dependency] private readonly AppearanceSystem _appearance = default!;
|
||||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||||
[Dependency] private readonly SolutionContainerSystem _solutionSystem = default!;
|
[Dependency] private readonly SolutionContainerSystem _solutionSystem = default!;
|
||||||
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
@@ -45,15 +39,6 @@ public sealed class SmokeSystem : EntitySystem
|
|||||||
SubscribeLocalEvent<SmokeComponent, ReactionAttemptEvent>(OnReactionAttempt);
|
SubscribeLocalEvent<SmokeComponent, ReactionAttemptEvent>(OnReactionAttempt);
|
||||||
SubscribeLocalEvent<SmokeComponent, SpreadNeighborsEvent>(OnSmokeSpread);
|
SubscribeLocalEvent<SmokeComponent, SpreadNeighborsEvent>(OnSmokeSpread);
|
||||||
SubscribeLocalEvent<SmokeDissipateSpawnComponent, TimedDespawnEvent>(OnSmokeDissipate);
|
SubscribeLocalEvent<SmokeDissipateSpawnComponent, TimedDespawnEvent>(OnSmokeDissipate);
|
||||||
SubscribeLocalEvent<SpreadGroupUpdateRate>(OnSpreadUpdateRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSpreadUpdateRate(ref SpreadGroupUpdateRate ev)
|
|
||||||
{
|
|
||||||
if (ev.Name != "smoke")
|
|
||||||
return;
|
|
||||||
|
|
||||||
ev.UpdatesPerSecond = 8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnSmokeDissipate(EntityUid uid, SmokeDissipateSpawnComponent component, ref TimedDespawnEvent args)
|
private void OnSmokeDissipate(EntityUid uid, SmokeDissipateSpawnComponent component, ref TimedDespawnEvent args)
|
||||||
@@ -68,11 +53,10 @@ public sealed class SmokeSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnSmokeSpread(EntityUid uid, SmokeComponent component, ref SpreadNeighborsEvent args)
|
private void OnSmokeSpread(EntityUid uid, SmokeComponent component, ref SpreadNeighborsEvent args)
|
||||||
{
|
{
|
||||||
if (component.SpreadAmount == 0 ||
|
if (component.SpreadAmount == 0
|
||||||
!_solutionSystem.TryGetSolution(uid, SmokeComponent.SolutionName, out var solution) ||
|
|| !_solutionSystem.TryGetSolution(uid, SmokeComponent.SolutionName, out var solution))
|
||||||
args.NeighborFreeTiles.Count == 0)
|
|
||||||
{
|
{
|
||||||
RemCompDeferred<EdgeSpreaderComponent>(uid);
|
RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,52 +64,48 @@ public sealed class SmokeSystem : EntitySystem
|
|||||||
|
|
||||||
if (prototype == null)
|
if (prototype == null)
|
||||||
{
|
{
|
||||||
RemCompDeferred<EdgeSpreaderComponent>(uid);
|
RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TryComp<TimedDespawnComponent>(uid, out var timer);
|
TryComp<TimedDespawnComponent>(uid, out var timer);
|
||||||
|
_appearance.TryGetData(uid, SmokeVisuals.Color, out var color);
|
||||||
|
|
||||||
var smokePerSpread = component.SpreadAmount / args.NeighborFreeTiles.Count;
|
// wtf is the logic behind any of this.
|
||||||
component.SpreadAmount -= smokePerSpread;
|
var smokePerSpread = 1 + component.SpreadAmount / Math.Max(1, args.NeighborFreeTiles.Count);
|
||||||
|
|
||||||
foreach (var neighbor in args.NeighborFreeTiles)
|
foreach (var neighbor in args.NeighborFreeTiles)
|
||||||
{
|
{
|
||||||
var coords = neighbor.Grid.GridTileToLocal(neighbor.Tile);
|
var coords = neighbor.Grid.GridTileToLocal(neighbor.Tile);
|
||||||
var ent = Spawn(prototype.ID, coords.SnapToGrid());
|
var ent = Spawn(prototype.ID, coords);
|
||||||
var neighborSmoke = EnsureComp<SmokeComponent>(ent);
|
var neighborSmoke = EnsureComp<SmokeComponent>(ent);
|
||||||
neighborSmoke.SpreadAmount = Math.Max(0, smokePerSpread - 1);
|
neighborSmoke.SpreadAmount = Math.Max(0, smokePerSpread - 2); // why - 2? who the fuck knows.
|
||||||
|
component.SpreadAmount--;
|
||||||
args.Updates--;
|
args.Updates--;
|
||||||
|
|
||||||
// Listen this is the old behaviour iunno
|
// Listen this is the old behaviour iunno
|
||||||
Start(ent, neighborSmoke, solution.Clone(), timer?.Lifetime ?? 10f);
|
Start(ent, neighborSmoke, solution.Clone(), timer?.Lifetime ?? 10f);
|
||||||
|
|
||||||
if (_appearance.TryGetData(uid, SmokeVisuals.Color, out var color))
|
if (color != null)
|
||||||
{
|
|
||||||
_appearance.SetData(ent, SmokeVisuals.Color, color);
|
_appearance.SetData(ent, SmokeVisuals.Color, color);
|
||||||
}
|
|
||||||
|
|
||||||
// Only 1 spread then ig?
|
|
||||||
if (smokePerSpread == 0)
|
|
||||||
{
|
|
||||||
component.SpreadAmount--;
|
|
||||||
|
|
||||||
if (component.SpreadAmount == 0)
|
if (component.SpreadAmount == 0)
|
||||||
{
|
{
|
||||||
RemCompDeferred<EdgeSpreaderComponent>(uid);
|
RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (args.Updates <= 0)
|
if (args.Updates <= 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Give our spread to neighbor tiles.
|
if (args.NeighborFreeTiles.Count > 0 || args.Neighbors.Count == 0 || component.SpreadAmount < 1)
|
||||||
if (args.NeighborFreeTiles.Count == 0 && args.Neighbors.Count > 0 && component.SpreadAmount > 0)
|
return;
|
||||||
{
|
|
||||||
|
// We have no more neighbours to spread to. So instead we will randomly distribute our volume to neighbouring smoke tiles.
|
||||||
|
|
||||||
var smokeQuery = GetEntityQuery<SmokeComponent>();
|
var smokeQuery = GetEntityQuery<SmokeComponent>();
|
||||||
|
|
||||||
|
_random.Shuffle(args.Neighbors);
|
||||||
foreach (var neighbor in args.Neighbors)
|
foreach (var neighbor in args.Neighbors)
|
||||||
{
|
{
|
||||||
if (!smokeQuery.TryGetComponent(neighbor, out var smoke))
|
if (!smokeQuery.TryGetComponent(neighbor, out var smoke))
|
||||||
@@ -133,14 +113,12 @@ public sealed class SmokeSystem : EntitySystem
|
|||||||
|
|
||||||
smoke.SpreadAmount++;
|
smoke.SpreadAmount++;
|
||||||
args.Updates--;
|
args.Updates--;
|
||||||
|
component.SpreadAmount--;
|
||||||
|
EnsureComp<ActiveEdgeSpreaderComponent>(neighbor);
|
||||||
|
|
||||||
if (component.SpreadAmount == 0)
|
if (component.SpreadAmount == 0)
|
||||||
{
|
{
|
||||||
RemCompDeferred<EdgeSpreaderComponent>(uid);
|
RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.Updates <= 0)
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -248,7 +226,7 @@ public sealed class SmokeSystem : EntitySystem
|
|||||||
public void Start(EntityUid uid, SmokeComponent component, Solution solution, float duration)
|
public void Start(EntityUid uid, SmokeComponent component, Solution solution, float duration)
|
||||||
{
|
{
|
||||||
TryAddSolution(uid, component, solution);
|
TryAddSolution(uid, component, solution);
|
||||||
EnsureComp<EdgeSpreaderComponent>(uid);
|
EnsureComp<ActiveEdgeSpreaderComponent>(uid);
|
||||||
var timer = EnsureComp<TimedDespawnComponent>(uid);
|
var timer = EnsureComp<TimedDespawnComponent>(uid);
|
||||||
timer.Lifetime = duration;
|
timer.Lifetime = duration;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ namespace Content.Server.NodeContainer.NodeGroups
|
|||||||
AMEngine,
|
AMEngine,
|
||||||
Pipe,
|
Pipe,
|
||||||
WireNet,
|
WireNet,
|
||||||
Spreader,
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Group used by the TEG.
|
/// Group used by the TEG.
|
||||||
|
|||||||
10
Content.Server/Spreader/ActiveEdgeSpreaderComponent.cs
Normal file
10
Content.Server/Spreader/ActiveEdgeSpreaderComponent.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]
|
||||||
|
public sealed partial class ActiveEdgeSpreaderComponent : Component
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -1,10 +1,14 @@
|
|||||||
|
using Content.Shared.Spreader;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Server.Spreader;
|
namespace Content.Server.Spreader;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Added to entities being considered for spreading via <see cref="SpreaderSystem"/>.
|
/// Entity capable of becoming cloning and replicating itself to adjacent edges. See <see cref="SpreaderSystem"/>
|
||||||
/// This needs to be manually added and removed.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent, Access(typeof(SpreaderSystem))]
|
[RegisterComponent, Access(typeof(SpreaderSystem))]
|
||||||
public sealed partial class EdgeSpreaderComponent : Component
|
public sealed partial class EdgeSpreaderComponent : Component
|
||||||
{
|
{
|
||||||
|
[DataField(required:true)]
|
||||||
|
public ProtoId<EdgeSpreaderPrototype> Id;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,6 @@ namespace Content.Server.Spreader;
|
|||||||
[RegisterComponent, Access(typeof(KudzuSystem))]
|
[RegisterComponent, Access(typeof(KudzuSystem))]
|
||||||
public sealed partial class GrowingKudzuComponent : Component
|
public sealed partial 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;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The next time kudzu will try to tick its growth level.
|
/// The next time kudzu will try to tick its growth level.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -8,6 +8,12 @@ namespace Content.Server.Spreader;
|
|||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
public sealed partial class KudzuComponent : Component
|
public sealed partial class KudzuComponent : 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]
|
||||||
|
public int GrowthLevel = 1;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Chance to spread whenever an edge spread is possible.
|
/// Chance to spread whenever an edge spread is possible.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using Content.Shared.Damage;
|
|||||||
using Content.Shared.Spreader;
|
using Content.Shared.Spreader;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Server.Spreader;
|
namespace Content.Server.Spreader;
|
||||||
|
|
||||||
@@ -13,7 +14,7 @@ public sealed class KudzuSystem : EntitySystem
|
|||||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||||
|
|
||||||
[ValidatePrototypeId<EdgeSpreaderPrototype>]
|
[ValidatePrototypeId<EdgeSpreaderPrototype>]
|
||||||
private const string KudzuGroup = "kudzu";
|
private const string KudzuGroup = "Kudzu";
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
@@ -21,7 +22,6 @@ public sealed class KudzuSystem : EntitySystem
|
|||||||
SubscribeLocalEvent<KudzuComponent, ComponentStartup>(SetupKudzu);
|
SubscribeLocalEvent<KudzuComponent, ComponentStartup>(SetupKudzu);
|
||||||
SubscribeLocalEvent<KudzuComponent, SpreadNeighborsEvent>(OnKudzuSpread);
|
SubscribeLocalEvent<KudzuComponent, SpreadNeighborsEvent>(OnKudzuSpread);
|
||||||
SubscribeLocalEvent<GrowingKudzuComponent, EntityUnpausedEvent>(OnKudzuUnpaused);
|
SubscribeLocalEvent<GrowingKudzuComponent, EntityUnpausedEvent>(OnKudzuUnpaused);
|
||||||
SubscribeLocalEvent<SpreadGroupUpdateRate>(OnKudzuUpdateRate);
|
|
||||||
SubscribeLocalEvent<KudzuComponent, DamageChangedEvent>(OnDamageChanged);
|
SubscribeLocalEvent<KudzuComponent, DamageChangedEvent>(OnDamageChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,59 +36,50 @@ public sealed class KudzuSystem : EntitySystem
|
|||||||
if (!TryComp(uid, out growing))
|
if (!TryComp(uid, out growing))
|
||||||
{
|
{
|
||||||
growing = AddComp<GrowingKudzuComponent>(uid);
|
growing = AddComp<GrowingKudzuComponent>(uid);
|
||||||
growing.GrowthLevel = 3;
|
component.GrowthLevel = 3;
|
||||||
}
|
}
|
||||||
growing.GrowthLevel = Math.Max(1, growing.GrowthLevel - growthDamage);
|
component.GrowthLevel = Math.Max(1, component.GrowthLevel - growthDamage);
|
||||||
if (EntityManager.TryGetComponent<AppearanceComponent>(uid, out var appearance))
|
if (EntityManager.TryGetComponent<AppearanceComponent>(uid, out var appearance))
|
||||||
{
|
{
|
||||||
_appearance.SetData(uid, KudzuVisuals.GrowthLevel, growing.GrowthLevel, appearance);
|
_appearance.SetData(uid, KudzuVisuals.GrowthLevel, component.GrowthLevel, appearance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnKudzuSpread(EntityUid uid, KudzuComponent component, ref SpreadNeighborsEvent args)
|
private void OnKudzuSpread(EntityUid uid, KudzuComponent component, ref SpreadNeighborsEvent args)
|
||||||
{
|
{
|
||||||
if (TryComp<GrowingKudzuComponent>(uid, out var growing) && growing.GrowthLevel < 3)
|
if (component.GrowthLevel < 3)
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (args.NeighborFreeTiles.Count == 0)
|
if (args.NeighborFreeTiles.Count == 0)
|
||||||
{
|
{
|
||||||
RemCompDeferred<EdgeSpreaderComponent>(uid);
|
RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var prototype = MetaData(uid).EntityPrototype?.ID;
|
|
||||||
|
|
||||||
if (prototype == null)
|
|
||||||
{
|
|
||||||
RemCompDeferred<EdgeSpreaderComponent>(uid);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_robustRandom.Prob(component.SpreadChance))
|
if (!_robustRandom.Prob(component.SpreadChance))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var prototype = MetaData(uid).EntityPrototype?.ID;
|
||||||
|
|
||||||
|
if (prototype == null)
|
||||||
|
{
|
||||||
|
RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var neighbor in args.NeighborFreeTiles)
|
foreach (var neighbor in args.NeighborFreeTiles)
|
||||||
{
|
{
|
||||||
var neighborUid = Spawn(prototype, neighbor.Grid.GridTileToLocal(neighbor.Tile));
|
var neighborUid = Spawn(prototype, neighbor.Grid.GridTileToLocal(neighbor.Tile));
|
||||||
EnsureComp<EdgeSpreaderComponent>(neighborUid);
|
DebugTools.Assert(HasComp<EdgeSpreaderComponent>(neighborUid));
|
||||||
|
DebugTools.Assert(HasComp<ActiveEdgeSpreaderComponent>(neighborUid));
|
||||||
|
DebugTools.Assert(Comp<EdgeSpreaderComponent>(neighborUid).Id == KudzuGroup);
|
||||||
args.Updates--;
|
args.Updates--;
|
||||||
|
|
||||||
if (args.Updates <= 0)
|
if (args.Updates <= 0)
|
||||||
return;
|
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)
|
private void OnKudzuUnpaused(EntityUid uid, GrowingKudzuComponent component, ref EntityUnpausedEvent args)
|
||||||
{
|
{
|
||||||
component.NextTick += args.PausedTime;
|
component.NextTick += args.PausedTime;
|
||||||
@@ -109,24 +100,30 @@ public sealed class KudzuSystem : EntitySystem
|
|||||||
public override void Update(float frameTime)
|
public override void Update(float frameTime)
|
||||||
{
|
{
|
||||||
var appearanceQuery = GetEntityQuery<AppearanceComponent>();
|
var appearanceQuery = GetEntityQuery<AppearanceComponent>();
|
||||||
var query = EntityQueryEnumerator<GrowingKudzuComponent, KudzuComponent>();
|
var query = EntityQueryEnumerator<GrowingKudzuComponent>();
|
||||||
|
var kudzuQuery = GetEntityQuery<KudzuComponent>();
|
||||||
|
var damageableQuery = GetEntityQuery<DamageableComponent>();
|
||||||
var curTime = _timing.CurTime;
|
var curTime = _timing.CurTime;
|
||||||
|
|
||||||
while (query.MoveNext(out var uid, out var grow, out var kudzu))
|
while (query.MoveNext(out var uid, out var grow))
|
||||||
{
|
{
|
||||||
if (grow.NextTick > curTime)
|
if (grow.NextTick > curTime)
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
grow.NextTick = curTime + TimeSpan.FromSeconds(0.5);
|
grow.NextTick = curTime + TimeSpan.FromSeconds(0.5);
|
||||||
|
|
||||||
|
if (!kudzuQuery.TryGetComponent(uid, out var kudzu))
|
||||||
|
{
|
||||||
|
RemCompDeferred(uid, grow);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!_robustRandom.Prob(kudzu.GrowthTickChance))
|
if (!_robustRandom.Prob(kudzu.GrowthTickChance))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TryComp<DamageableComponent>(uid, out var damage))
|
if (damageableQuery.TryGetComponent(uid, out var damage))
|
||||||
{
|
{
|
||||||
if (damage.TotalDamage > 1.0)
|
if (damage.TotalDamage > 1.0)
|
||||||
{
|
{
|
||||||
@@ -146,17 +143,17 @@ public sealed class KudzuSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
grow.GrowthLevel += 1;
|
kudzu.GrowthLevel += 1;
|
||||||
|
|
||||||
if (grow.GrowthLevel >= 3)
|
if (kudzu.GrowthLevel >= 3)
|
||||||
{
|
{
|
||||||
// why cache when you can simply cease to be? Also saves a bit of memory/time.
|
// why cache when you can simply cease to be? Also saves a bit of memory/time.
|
||||||
RemCompDeferred<GrowingKudzuComponent>(uid);
|
RemCompDeferred(uid, grow);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (appearanceQuery.TryGetComponent(uid, out var appearance))
|
if (appearanceQuery.TryGetComponent(uid, out var appearance))
|
||||||
{
|
{
|
||||||
_appearance.SetData(uid, KudzuVisuals.GrowthLevel, grow.GrowthLevel, appearance);
|
_appearance.SetData(uid, KudzuVisuals.GrowthLevel, kudzu.GrowthLevel, appearance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
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);
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
using Content.Server.NodeContainer;
|
|
||||||
using Content.Server.NodeContainer.EntitySystems;
|
|
||||||
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 partial class SpreaderNode : Node
|
|
||||||
{
|
|
||||||
// [Dependency] private readonly NodeContainerSystem _nodeContainer = default!;
|
|
||||||
|
|
||||||
/// <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);
|
|
||||||
|
|
||||||
var _nodeContainer = entMan.System<NodeContainerSystem>();
|
|
||||||
|
|
||||||
foreach (var neighbor in neighbors)
|
|
||||||
{
|
|
||||||
if (!nodeQuery.TryGetComponent(neighbor, out var nodeContainer) ||
|
|
||||||
!_nodeContainer.TryGetNode<SpreaderNode>(nodeContainer, Name, out var neighborNode))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield return neighborNode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,5 @@
|
|||||||
using Content.Server.Atmos.Components;
|
using Content.Server.Atmos.Components;
|
||||||
using Content.Server.Atmos.EntitySystems;
|
using Content.Server.Atmos.EntitySystems;
|
||||||
using Content.Server.NodeContainer;
|
|
||||||
using Content.Server.NodeContainer.EntitySystems;
|
|
||||||
using Content.Server.NodeContainer.NodeGroups;
|
|
||||||
using Content.Server.Shuttles.Components;
|
using Content.Server.Shuttles.Components;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
using Content.Shared.Spreader;
|
using Content.Shared.Spreader;
|
||||||
@@ -13,6 +10,7 @@ using Robust.Shared.Map.Components;
|
|||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Server.Spreader;
|
namespace Content.Server.Spreader;
|
||||||
|
|
||||||
@@ -25,11 +23,20 @@ public sealed class SpreaderSystem : EntitySystem
|
|||||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||||
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
||||||
[Dependency] private readonly NodeContainerSystem _nodeContainer = default!;
|
|
||||||
|
|
||||||
private static readonly TimeSpan SpreadCooldown = TimeSpan.FromSeconds(1);
|
private static readonly TimeSpan SpreadCooldown = TimeSpan.FromSeconds(SpreadCooldownSeconds);
|
||||||
|
|
||||||
private readonly List<string> _spreaderGroups = new();
|
/// <summary>
|
||||||
|
/// Cached maximum number of updates per spreader prototype. This is applied per-grid.
|
||||||
|
/// </summary>
|
||||||
|
private Dictionary<string, int> _prototypeUpdates = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remaining number of updates per grid & prototype.
|
||||||
|
/// </summary>
|
||||||
|
private Dictionary<EntityUid, Dictionary<string, int>> _gridUpdates = new();
|
||||||
|
|
||||||
|
private const float SpreadCooldownSeconds = 1;
|
||||||
|
|
||||||
[ValidatePrototypeId<TagPrototype>]
|
[ValidatePrototypeId<TagPrototype>]
|
||||||
private const string IgnoredTag = "SpreaderIgnore";
|
private const string IgnoredTag = "SpreaderIgnore";
|
||||||
@@ -42,6 +49,7 @@ public sealed class SpreaderSystem : EntitySystem
|
|||||||
|
|
||||||
SubscribeLocalEvent<SpreaderGridComponent, EntityUnpausedEvent>(OnGridUnpaused);
|
SubscribeLocalEvent<SpreaderGridComponent, EntityUnpausedEvent>(OnGridUnpaused);
|
||||||
|
|
||||||
|
SubscribeLocalEvent<EdgeSpreaderComponent, EntityTerminatingEvent>(OnTerminating);
|
||||||
SetupPrototypes();
|
SetupPrototypes();
|
||||||
_prototype.PrototypesReloaded += OnPrototypeReload;
|
_prototype.PrototypesReloaded += OnPrototypeReload;
|
||||||
}
|
}
|
||||||
@@ -62,21 +70,20 @@ public sealed class SpreaderSystem : EntitySystem
|
|||||||
|
|
||||||
private void SetupPrototypes()
|
private void SetupPrototypes()
|
||||||
{
|
{
|
||||||
_spreaderGroups.Clear();
|
_prototypeUpdates = new Dictionary<string, int>();
|
||||||
|
foreach (var proto in _prototype.EnumeratePrototypes<EdgeSpreaderPrototype>())
|
||||||
foreach (var id in _prototype.EnumeratePrototypes<EdgeSpreaderPrototype>())
|
|
||||||
{
|
{
|
||||||
_spreaderGroups.Add(id.ID);
|
_prototypeUpdates.Add(proto.ID, proto.UpdatesPerSecond);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAirtightChanged(ref AirtightChanged ev)
|
private void OnAirtightChanged(ref AirtightChanged ev)
|
||||||
{
|
{
|
||||||
var neighbors = GetNeighbors(ev.Entity, ev.Airtight);
|
var neighbors = GetSpreadableNeighbors(ev.Entity, ev.Airtight, ev.Position);
|
||||||
|
|
||||||
foreach (var neighbor in neighbors)
|
foreach (var neighbor in neighbors)
|
||||||
{
|
{
|
||||||
EnsureComp<EdgeSpreaderComponent>(neighbor);
|
EnsureComp<ActiveEdgeSpreaderComponent>(neighbor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +94,17 @@ public sealed class SpreaderSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnGridInit(GridInitializeEvent ev)
|
private void OnGridInit(GridInitializeEvent ev)
|
||||||
{
|
{
|
||||||
var comp = EnsureComp<SpreaderGridComponent>(ev.EntityUid);
|
EnsureComp<SpreaderGridComponent>(ev.EntityUid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTerminating(EntityUid uid, EdgeSpreaderComponent component, ref EntityTerminatingEvent args)
|
||||||
|
{
|
||||||
|
var neighbors = GetSpreadableNeighbors(uid);
|
||||||
|
|
||||||
|
foreach (var neighbor in neighbors)
|
||||||
|
{
|
||||||
|
EnsureComp<ActiveEdgeSpreaderComponent>(neighbor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -96,31 +113,26 @@ public sealed class SpreaderSystem : EntitySystem
|
|||||||
var curTime = _timing.CurTime;
|
var curTime = _timing.CurTime;
|
||||||
|
|
||||||
// Check which grids are valid for spreading
|
// Check which grids are valid for spreading
|
||||||
var spreadable = new ValueList<EntityUid>();
|
|
||||||
var spreadGrids = EntityQueryEnumerator<SpreaderGridComponent>();
|
var spreadGrids = EntityQueryEnumerator<SpreaderGridComponent>();
|
||||||
|
|
||||||
|
_gridUpdates.Clear();
|
||||||
while (spreadGrids.MoveNext(out var uid, out var grid))
|
while (spreadGrids.MoveNext(out var uid, out var grid))
|
||||||
{
|
{
|
||||||
if (grid.NextUpdate > curTime)
|
if (grid.NextUpdate > curTime)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
spreadable.Add(uid);
|
_gridUpdates[uid] = _prototypeUpdates.ShallowClone();
|
||||||
grid.NextUpdate += SpreadCooldown;
|
grid.NextUpdate += SpreadCooldown;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spreadable.Count == 0)
|
if (_gridUpdates.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var query = EntityQueryEnumerator<EdgeSpreaderComponent>();
|
var query = EntityQueryEnumerator<ActiveEdgeSpreaderComponent>();
|
||||||
var nodeQuery = GetEntityQuery<NodeContainerComponent>();
|
var xforms = GetEntityQuery<TransformComponent>();
|
||||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
var spreaderQuery = GetEntityQuery<EdgeSpreaderComponent>();
|
||||||
var gridQuery = GetEntityQuery<SpreaderGridComponent>();
|
|
||||||
|
|
||||||
// Each INode group has a certain number of updates
|
var spreaders = new List<(EntityUid Uid, ActiveEdgeSpreaderComponent Comp)>(Count<ActiveEdgeSpreaderComponent>());
|
||||||
// allowed per SpreadCooldown
|
|
||||||
var groupUpdates = new Dictionary<INodeGroup, int>();
|
|
||||||
|
|
||||||
var spreaders = new List<(EntityUid Uid, EdgeSpreaderComponent Comp)>(Count<EdgeSpreaderComponent>());
|
|
||||||
|
|
||||||
// Build a list of all existing Edgespreaders, shuffle them
|
// Build a list of all existing Edgespreaders, shuffle them
|
||||||
while (query.MoveNext(out var uid, out var comp))
|
while (query.MoveNext(out var uid, out var comp))
|
||||||
@@ -134,64 +146,43 @@ public sealed class SpreaderSystem : EntitySystem
|
|||||||
// that doesn't meet a few trivial prerequisites
|
// that doesn't meet a few trivial prerequisites
|
||||||
foreach (var (uid, comp) in spreaders)
|
foreach (var (uid, comp) in spreaders)
|
||||||
{
|
{
|
||||||
if (!xformQuery.TryGetComponent(uid, out var xform) ||
|
// Get xform first, as entity may have been deleted due to interactions triggered by other spreaders.
|
||||||
xform.GridUid == null ||
|
if (!xforms.TryGetComponent(uid, out var xform))
|
||||||
!gridQuery.HasComponent(xform.GridUid.Value))
|
continue;
|
||||||
|
|
||||||
|
if (xform.GridUid == null)
|
||||||
{
|
{
|
||||||
RemCompDeferred<EdgeSpreaderComponent>(uid);
|
RemComp(uid, comp);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var sGroup in _spreaderGroups)
|
if (!_gridUpdates.TryGetValue(xform.GridUid.Value, out var groupUpdates))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!spreaderQuery.TryGetComponent(uid, out var spreader))
|
||||||
{
|
{
|
||||||
// Get the NodeContainer and Node from every EdgeSpreader entity found
|
RemComp(uid, comp);
|
||||||
if (!nodeQuery.TryGetComponent(uid, out var nodeContainer))
|
|
||||||
{
|
|
||||||
RemCompDeferred<EdgeSpreaderComponent>(uid);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_nodeContainer.TryGetNode<SpreaderNode>(nodeContainer, sGroup, out var node))
|
if (!groupUpdates.TryGetValue(spreader.Id, out var updates) || updates < 1)
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
// Not allowed this tick?
|
|
||||||
if (node.NodeGroup == null ||
|
|
||||||
!spreadable.Contains(xform.GridUid.Value))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try get an integer update rate associated with a node group,
|
|
||||||
// getting it instead from the spreader itself on failure
|
|
||||||
if (!groupUpdates.TryGetValue(node.NodeGroup, out var updates))
|
|
||||||
{
|
|
||||||
var spreadEv = new SpreadGroupUpdateRate(node.Name);
|
|
||||||
RaiseLocalEvent(ref spreadEv);
|
|
||||||
updates = (int) (spreadEv.UpdatesPerSecond * SpreadCooldown / TimeSpan.FromSeconds(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
// "updates" integer dictates the amount of nodes that
|
|
||||||
// are to be spawned around a NodeGroup
|
|
||||||
if (updates <= 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Edge detection logic is to be handled
|
// Edge detection logic is to be handled
|
||||||
// by the subscribing system, see KudzuSystem
|
// by the subscribing system, see KudzuSystem
|
||||||
// for a simple example
|
// for a simple example
|
||||||
|
Spread(uid, xform, spreader.Id, ref updates);
|
||||||
|
|
||||||
Spread(uid, node, node.NodeGroup, ref updates);
|
if (updates < 1)
|
||||||
groupUpdates[node.NodeGroup] = updates;
|
groupUpdates.Remove(spreader.Id);
|
||||||
}
|
else
|
||||||
|
groupUpdates[spreader.Id] = updates;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Spread(EntityUid uid, SpreaderNode node, INodeGroup group, ref int updates)
|
private void Spread(EntityUid uid, TransformComponent xform, string prototype, ref int updates)
|
||||||
{
|
{
|
||||||
GetNeighbors(uid, node.Name, out var freeTiles, out _, out var neighbors);
|
GetNeighbors(uid, xform, prototype, out var freeTiles, out _, out var neighbors);
|
||||||
|
|
||||||
var ev = new SpreadNeighborsEvent()
|
var ev = new SpreadNeighborsEvent()
|
||||||
{
|
{
|
||||||
@@ -207,20 +198,19 @@ public sealed class SpreaderSystem : EntitySystem
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the neighboring node data for the specified entity and the specified node group.
|
/// Gets the neighboring node data for the specified entity and the specified node group.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void GetNeighbors(EntityUid uid, string groupName, out ValueList<(MapGridComponent Grid, Vector2i Tile)> freeTiles, out ValueList<Vector2i> occupiedTiles, out ValueList<EntityUid> neighbors)
|
public void GetNeighbors(EntityUid uid, TransformComponent transform, string prototype, out ValueList<(MapGridComponent Grid, Vector2i Tile)> freeTiles, out ValueList<Vector2i> occupiedTiles, out ValueList<EntityUid> neighbors)
|
||||||
{
|
{
|
||||||
|
// TODO remove occupiedTiles -- its currently unused and just slows this method down.
|
||||||
|
DebugTools.Assert(_prototype.HasIndex<EdgeSpreaderPrototype>(prototype));
|
||||||
freeTiles = new ValueList<(MapGridComponent Grid, Vector2i Tile)>();
|
freeTiles = new ValueList<(MapGridComponent Grid, Vector2i Tile)>();
|
||||||
occupiedTiles = new ValueList<Vector2i>();
|
occupiedTiles = new ValueList<Vector2i>();
|
||||||
neighbors = new ValueList<EntityUid>();
|
neighbors = new ValueList<EntityUid>();
|
||||||
|
|
||||||
if (!EntityManager.TryGetComponent<TransformComponent>(uid, out var transform))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!_mapManager.TryGetGrid(transform.GridUid, out var grid))
|
if (!_mapManager.TryGetGrid(transform.GridUid, out var grid))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var tile = grid.TileIndicesFor(transform.Coordinates);
|
var tile = grid.TileIndicesFor(transform.Coordinates);
|
||||||
var nodeQuery = GetEntityQuery<NodeContainerComponent>();
|
var spreaderQuery = GetEntityQuery<EdgeSpreaderComponent>();
|
||||||
var airtightQuery = GetEntityQuery<AirtightComponent>();
|
var airtightQuery = GetEntityQuery<AirtightComponent>();
|
||||||
var dockQuery = GetEntityQuery<DockingComponent>();
|
var dockQuery = GetEntityQuery<DockingComponent>();
|
||||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||||
@@ -309,10 +299,10 @@ public sealed class SpreaderSystem : EntitySystem
|
|||||||
|
|
||||||
while (directionEnumerator.MoveNext(out var ent))
|
while (directionEnumerator.MoveNext(out var ent))
|
||||||
{
|
{
|
||||||
if (!nodeQuery.TryGetComponent(ent, out var nodeContainer))
|
if (!spreaderQuery.TryGetComponent(ent, out var spreader))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!nodeContainer.Nodes.ContainsKey(groupName))
|
if (spreader.Id != prototype)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
neighbors.Add(ent.Value);
|
neighbors.Add(ent.Value);
|
||||||
@@ -325,23 +315,38 @@ public sealed class SpreaderSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<EntityUid> GetNeighbors(EntityUid uid, AirtightComponent comp)
|
/// <summary>
|
||||||
|
/// Given an entity, this returns a list of all adjacent entities with a <see cref="EdgeSpreaderComponent"/>.
|
||||||
|
/// </summary>
|
||||||
|
public List<EntityUid> GetSpreadableNeighbors(EntityUid uid, AirtightComponent? comp = null,
|
||||||
|
(EntityUid Grid, Vector2i Tile)? position = null)
|
||||||
{
|
{
|
||||||
|
Resolve(uid, ref comp, false);
|
||||||
var neighbors = new List<EntityUid>();
|
var neighbors = new List<EntityUid>();
|
||||||
|
|
||||||
if (!EntityManager.TryGetComponent<TransformComponent>(uid, out var transform))
|
Vector2i tile;
|
||||||
return neighbors; // how did we get here?
|
MapGridComponent? grid;
|
||||||
|
|
||||||
if (!_mapManager.TryGetGrid(transform.GridUid, out var grid))
|
if (position == null)
|
||||||
|
{
|
||||||
|
var transform = Transform(uid);
|
||||||
|
if (!_mapManager.TryGetGrid(transform.GridUid, out grid))
|
||||||
return neighbors;
|
return neighbors;
|
||||||
|
tile = grid.TileIndicesFor(transform.Coordinates);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!_mapManager.TryGetGrid(position.Value.Grid, out grid))
|
||||||
|
return neighbors;
|
||||||
|
tile = position.Value.Tile;
|
||||||
|
}
|
||||||
|
|
||||||
var tile = grid.TileIndicesFor(transform.Coordinates);
|
var spreaderQuery = GetEntityQuery<EdgeSpreaderComponent>();
|
||||||
var nodeQuery = GetEntityQuery<NodeContainerComponent>();
|
|
||||||
|
|
||||||
for (var i = 0; i < Atmospherics.Directions; i++)
|
for (var i = 0; i < Atmospherics.Directions; i++)
|
||||||
{
|
{
|
||||||
var direction = (AtmosDirection) (1 << i);
|
var direction = (AtmosDirection) (1 << i);
|
||||||
if (!comp.AirBlockedDirection.IsFlagSet(direction))
|
if (comp != null && !comp.AirBlockedDirection.IsFlagSet(direction))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var directionEnumerator =
|
var directionEnumerator =
|
||||||
@@ -349,17 +354,9 @@ public sealed class SpreaderSystem : EntitySystem
|
|||||||
|
|
||||||
while (directionEnumerator.MoveNext(out var ent))
|
while (directionEnumerator.MoveNext(out var ent))
|
||||||
{
|
{
|
||||||
if (!nodeQuery.TryGetComponent(ent, out var nodeContainer))
|
DebugTools.Assert(Transform(ent.Value).Anchored);
|
||||||
continue;
|
if (spreaderQuery.HasComponent(ent))
|
||||||
|
|
||||||
foreach (var name in _spreaderGroups)
|
|
||||||
{
|
|
||||||
if (!nodeContainer.Nodes.ContainsKey(name))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
neighbors.Add(ent.Value);
|
neighbors.Add(ent.Value);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,4 +9,5 @@ namespace Content.Shared.Spreader;
|
|||||||
public sealed class EdgeSpreaderPrototype : IPrototype
|
public sealed class EdgeSpreaderPrototype : IPrototype
|
||||||
{
|
{
|
||||||
[IdDataField] public string ID { get; } = string.Empty;
|
[IdDataField] public string ID { get; } = string.Empty;
|
||||||
|
[DataField(required:true)] public int UpdatesPerSecond;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,9 @@
|
|||||||
- type: Transform
|
- type: Transform
|
||||||
anchored: true
|
anchored: true
|
||||||
- type: Smoke
|
- type: Smoke
|
||||||
- type: NodeContainer
|
- type: ActiveEdgeSpreader
|
||||||
nodes:
|
|
||||||
smoke:
|
|
||||||
!type:SpreaderNode
|
|
||||||
nodeGroupID: Spreader
|
|
||||||
- type: EdgeSpreader
|
- type: EdgeSpreader
|
||||||
|
id: Smoke
|
||||||
- type: SolutionContainerManager
|
- type: SolutionContainerManager
|
||||||
solutions:
|
solutions:
|
||||||
solutionArea:
|
solutionArea:
|
||||||
@@ -64,12 +61,9 @@
|
|||||||
layer:
|
layer:
|
||||||
- SlipLayer
|
- SlipLayer
|
||||||
- type: Smoke
|
- type: Smoke
|
||||||
- type: NodeContainer
|
- type: ActiveEdgeSpreader
|
||||||
nodes:
|
|
||||||
smoke:
|
|
||||||
!type:SpreaderNode
|
|
||||||
nodeGroupID: Spreader
|
|
||||||
- type: EdgeSpreader
|
- type: EdgeSpreader
|
||||||
|
id: Smoke
|
||||||
- type: SolutionContainerManager
|
- type: SolutionContainerManager
|
||||||
solutions:
|
solutions:
|
||||||
solutionArea:
|
solutionArea:
|
||||||
|
|||||||
@@ -144,13 +144,10 @@
|
|||||||
puddle: { maxVol: 1000 }
|
puddle: { maxVol: 1000 }
|
||||||
- type: Puddle
|
- type: Puddle
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
|
- type: ActiveEdgeSpreader
|
||||||
- type: EdgeSpreader
|
- type: EdgeSpreader
|
||||||
|
id: Puddle
|
||||||
- type: StepTrigger
|
- type: StepTrigger
|
||||||
- type: NodeContainer
|
|
||||||
nodes:
|
|
||||||
puddle:
|
|
||||||
!type:SpreaderNode
|
|
||||||
nodeGroupID: Spreader
|
|
||||||
- type: Drink
|
- type: Drink
|
||||||
delay: 3
|
delay: 3
|
||||||
transferAmount: 1
|
transferAmount: 1
|
||||||
|
|||||||
@@ -79,12 +79,9 @@
|
|||||||
ignoreWhitelist:
|
ignoreWhitelist:
|
||||||
components:
|
components:
|
||||||
- IgnoreKudzu
|
- IgnoreKudzu
|
||||||
|
- type: ActiveEdgeSpreader
|
||||||
- type: EdgeSpreader
|
- type: EdgeSpreader
|
||||||
- type: NodeContainer
|
id: Kudzu
|
||||||
nodes:
|
|
||||||
kudzu:
|
|
||||||
!type:SpreaderNode
|
|
||||||
nodeGroupID: Spreader
|
|
||||||
- type: Food
|
- type: Food
|
||||||
requiredStomachs: 2 # ruminants have 4 stomachs but i dont care to give them literally 4 stomachs. 2 is good
|
requiredStomachs: 2 # ruminants have 4 stomachs but i dont care to give them literally 4 stomachs. 2 is good
|
||||||
delay: 0.5
|
delay: 0.5
|
||||||
@@ -186,12 +183,9 @@
|
|||||||
- type: GrowingKudzu
|
- type: GrowingKudzu
|
||||||
growthTickChance: 0.3
|
growthTickChance: 0.3
|
||||||
- type: AtmosExposed
|
- type: AtmosExposed
|
||||||
|
- type: ActiveEdgeSpreader
|
||||||
- type: EdgeSpreader
|
- type: EdgeSpreader
|
||||||
- type: NodeContainer
|
id: Kudzu
|
||||||
nodes:
|
|
||||||
kudzu:
|
|
||||||
!type:SpreaderNode
|
|
||||||
nodeGroupID: Spreader
|
|
||||||
- type: SlowContacts
|
- type: SlowContacts
|
||||||
walkSpeedModifier: 0.3
|
walkSpeedModifier: 0.3
|
||||||
sprintSpeedModifier: 0.3
|
sprintSpeedModifier: 0.3
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
- type: edgeSpreader
|
- type: edgeSpreader
|
||||||
id: kudzu
|
id: Kudzu
|
||||||
|
updatesPerSecond: 1
|
||||||
|
|
||||||
- type: edgeSpreader
|
- type: edgeSpreader
|
||||||
id: puddle
|
id: Puddle
|
||||||
|
updatesPerSecond: 16
|
||||||
|
|
||||||
- type: edgeSpreader
|
- type: edgeSpreader
|
||||||
id: smoke
|
id: Smoke
|
||||||
|
updatesPerSecond: 8
|
||||||
|
|||||||
Reference in New Issue
Block a user