]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Remove SpreaderNodeGroup (#20230)
authorLeon Friedrich <60421075+ElectroJr@users.noreply.github.com>
Sun, 1 Oct 2023 20:56:41 +0000 (07:56 +1100)
committerGitHub <noreply@github.com>
Sun, 1 Oct 2023 20:56:41 +0000 (16:56 -0400)
* Remove SpreaderNodeGroup

* Fix airtight updates

* more smoke stuff

* more smoke fixes

* wtf is smoke code

* Fix merge

* Fix divide by zero

18 files changed:
Content.Server/Atmos/EntitySystems/AirtightSystem.cs
Content.Server/Fluids/EntitySystems/PuddleSystem.cs
Content.Server/Fluids/EntitySystems/SmokeSystem.cs
Content.Server/NodeContainer/NodeGroups/NodeGroupFactory.cs
Content.Server/Spreader/ActiveEdgeSpreaderComponent.cs [new file with mode: 0644]
Content.Server/Spreader/EdgeSpreaderComponent.cs
Content.Server/Spreader/GrowingKudzuComponent.cs
Content.Server/Spreader/KudzuComponent.cs
Content.Server/Spreader/KudzuSystem.cs
Content.Server/Spreader/SpreadGroupUpdateRate.cs [deleted file]
Content.Server/Spreader/SpreaderNode.cs [deleted file]
Content.Server/Spreader/SpreaderNodeGroup.cs [deleted file]
Content.Server/Spreader/SpreaderSystem.cs
Content.Shared/Spreader/EdgeSpreaderPrototype.cs
Resources/Prototypes/Entities/Effects/chemistry_effects.yml
Resources/Prototypes/Entities/Effects/puddle.yml
Resources/Prototypes/Entities/Objects/Misc/kudzu.yml
Resources/Prototypes/edge_spreaders.yml

index 9a97c88035570a09182f5ab5124debdaa2561991..f899ffb2e82e03ce9930abc9842e70f7c2744f25 100644 (file)
@@ -21,7 +21,7 @@ namespace Content.Server.Atmos.EntitySystems
             SubscribeLocalEvent<AirtightComponent, ComponentShutdown>(OnAirtightShutdown);
             SubscribeLocalEvent<AirtightComponent, AnchorStateChangedEvent>(OnAirtightPositionChanged);
             SubscribeLocalEvent<AirtightComponent, ReAnchorEvent>(OnAirtightReAnchor);
-            SubscribeLocalEvent<AirtightComponent, MoveEvent>(OnAirtightRotated);
+            SubscribeLocalEvent<AirtightComponent, MoveEvent>(OnAirtightMoved);
         }
 
         private void OnAirtightInit(EntityUid uid, AirtightComponent airtight, ComponentInit args)
@@ -31,7 +31,7 @@ namespace Content.Server.Atmos.EntitySystems
             if (airtight.FixAirBlockedDirectionInitialize)
             {
                 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;
             }
 
@@ -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)
                 return false;
 
             airtight.CurrentAirBlockedDirection = (int) Rotate((AtmosDirection)airtight.InitialAirBlockedDirection, ev.NewRotation);
+            var pos = airtight.LastPosition;
             UpdatePosition(airtight, ev.Component);
-            var airtightEv = new AirtightChanged(uid, airtight);
+            var airtightEv = new AirtightChanged(uid, airtight, pos);
             RaiseLocalEvent(uid, ref airtightEv, true);
             return true;
         }
@@ -100,11 +101,13 @@ namespace Content.Server.Atmos.EntitySystems
             if (airtight.AirBlocked == airblocked)
                 return;
 
-            if (!Resolve(airtight.Owner, ref xform)) return;
+            if (!Resolve(uid, ref xform))
+                return;
 
+            var pos = airtight.LastPosition;
             airtight.AirBlocked = airblocked;
             UpdatePosition(airtight, xform);
-            var airtightEv = new AirtightChanged(uid, airtight);
+            var airtightEv = new AirtightChanged(uid, airtight, pos);
             RaiseLocalEvent(uid, ref airtightEv, true);
         }
 
@@ -154,5 +157,6 @@ namespace Content.Server.Atmos.EntitySystems
     }
 
     [ByRefEvent]
-    public readonly record struct AirtightChanged(EntityUid Entity, AirtightComponent Airtight);
+    public readonly record struct AirtightChanged(EntityUid Entity, AirtightComponent Airtight,
+        (EntityUid Grid, Vector2i Tile) Position);
 }
index 614e685456353923763209abb744d6333866c31a..1fb56a7aa1f1d99fb4932e76697d5b1fe092bab3 100644 (file)
@@ -103,7 +103,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
 
         if (overflow.Volume == FixedPoint2.Zero)
         {
-            RemCompDeferred<EdgeSpreaderComponent>(uid);
+            RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
             return;
         }
 
@@ -137,7 +137,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
                     continue;
 
                 args.Updates--;
-                EnsureComp<EdgeSpreaderComponent>(neighbor);
+                EnsureComp<ActiveEdgeSpreaderComponent>(neighbor);
 
                 if (args.Updates <= 0)
                     break;
@@ -145,7 +145,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
 
             if (overflow.Volume == FixedPoint2.Zero)
             {
-                RemCompDeferred<EdgeSpreaderComponent>(uid);
+                RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
                 return;
             }
         }
@@ -168,7 +168,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
                     break;
             }
 
-            RemCompDeferred<EdgeSpreaderComponent>(uid);
+            RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
             return;
         }
 
@@ -192,7 +192,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
                 if (!_solutionContainerSystem.TryAddSolution(neighbor, neighborSolution, split))
                     continue;
 
-                EnsureComp<EdgeSpreaderComponent>(neighbor);
+                EnsureComp<ActiveEdgeSpreaderComponent>(neighbor);
                 args.Updates--;
 
                 if (args.Updates <= 0)
@@ -438,7 +438,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
 
         if (checkForOverflow && IsOverflowing(puddleUid, puddleComponent))
         {
-            EnsureComp<EdgeSpreaderComponent>(puddleUid);
+            EnsureComp<ActiveEdgeSpreaderComponent>(puddleUid);
         }
 
         if (!sound)
@@ -638,7 +638,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
 
             if (TryAddSolution(ent.Value, solution, sound, puddleComponent: puddle))
             {
-                EnsureComp<EdgeSpreaderComponent>(ent.Value);
+                EnsureComp<ActiveEdgeSpreaderComponent>(ent.Value);
             }
 
             puddleUid = ent.Value;
@@ -650,7 +650,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
         EnsureComp<PuddleComponent>(puddleUid);
         if (TryAddSolution(puddleUid, solution, sound))
         {
-            EnsureComp<EdgeSpreaderComponent>(puddleUid);
+            EnsureComp<ActiveEdgeSpreaderComponent>(puddleUid);
         }
         return true;
     }
index a192b39e560cd7855c8a460522ccff7f4e096531..b3590fec40206ac86c8e344c51556e336063f42e 100644 (file)
@@ -1,23 +1,16 @@
 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.EntitySystems;
 using Content.Server.Chemistry.ReactionEffects;
 using Content.Server.Spreader;
-using Content.Shared.Chemistry;
 using Content.Shared.Chemistry.Components;
 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.Smoking;
-using Robust.Shared.Spawners;
 using Robust.Server.GameObjects;
 using Robust.Shared.Map;
 using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
 using Robust.Shared.Spawners;
 using Robust.Shared.Timing;
 using TimedDespawnComponent = Robust.Shared.Spawners.TimedDespawnComponent;
@@ -36,6 +29,7 @@ public sealed class SmokeSystem : EntitySystem
     [Dependency] private readonly AppearanceSystem _appearance = default!;
     [Dependency] private readonly EntityLookupSystem _lookup = default!;
     [Dependency] private readonly SolutionContainerSystem _solutionSystem = default!;
+    [Dependency] private readonly IRobustRandom _random = default!;
 
     /// <inheritdoc/>
     public override void Initialize()
@@ -45,15 +39,6 @@ public sealed class SmokeSystem : EntitySystem
         SubscribeLocalEvent<SmokeComponent, ReactionAttemptEvent>(OnReactionAttempt);
         SubscribeLocalEvent<SmokeComponent, SpreadNeighborsEvent>(OnSmokeSpread);
         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)
@@ -68,11 +53,10 @@ public sealed class SmokeSystem : EntitySystem
 
     private void OnSmokeSpread(EntityUid uid, SmokeComponent component, ref SpreadNeighborsEvent args)
     {
-        if (component.SpreadAmount == 0 ||
-            !_solutionSystem.TryGetSolution(uid, SmokeComponent.SolutionName, out var solution) ||
-            args.NeighborFreeTiles.Count == 0)
+        if (component.SpreadAmount == 0
+            || !_solutionSystem.TryGetSolution(uid, SmokeComponent.SolutionName, out var solution))
         {
-            RemCompDeferred<EdgeSpreaderComponent>(uid);
+            RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
             return;
         }
 
@@ -80,68 +64,62 @@ public sealed class SmokeSystem : EntitySystem
 
         if (prototype == null)
         {
-            RemCompDeferred<EdgeSpreaderComponent>(uid);
+            RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
             return;
         }
 
         TryComp<TimedDespawnComponent>(uid, out var timer);
+        _appearance.TryGetData(uid, SmokeVisuals.Color, out var color);
 
-        var smokePerSpread = component.SpreadAmount / args.NeighborFreeTiles.Count;
-        component.SpreadAmount -= smokePerSpread;
-
+        // wtf is the logic behind any of this.
+        var smokePerSpread = 1 + component.SpreadAmount / Math.Max(1, args.NeighborFreeTiles.Count);
         foreach (var neighbor in args.NeighborFreeTiles)
         {
             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);
-            neighborSmoke.SpreadAmount = Math.Max(0, smokePerSpread - 1);
+            neighborSmoke.SpreadAmount = Math.Max(0, smokePerSpread - 2); // why - 2? who the fuck knows.
+            component.SpreadAmount--;
             args.Updates--;
 
             // Listen this is the old behaviour iunno
             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);
-            }
 
-            // Only 1 spread then ig?
-            if (smokePerSpread == 0)
+            if (component.SpreadAmount == 0)
             {
-                component.SpreadAmount--;
-
-                if (component.SpreadAmount == 0)
-                {
-                    RemCompDeferred<EdgeSpreaderComponent>(uid);
-                    break;
-                }
+                RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
+                break;
             }
 
             if (args.Updates <= 0)
                 break;
         }
 
-        // Give our spread to neighbor tiles.
-        if (args.NeighborFreeTiles.Count == 0 && args.Neighbors.Count > 0 && component.SpreadAmount > 0)
-        {
-            var smokeQuery = GetEntityQuery<SmokeComponent>();
+        if (args.NeighborFreeTiles.Count > 0 || args.Neighbors.Count == 0 || component.SpreadAmount < 1)
+            return;
 
-            foreach (var neighbor in args.Neighbors)
-            {
-                if (!smokeQuery.TryGetComponent(neighbor, out var smoke))
-                    continue;
+        // We have no more neighbours to spread to. So instead we will randomly distribute our volume to neighbouring smoke tiles.
+
+        var smokeQuery = GetEntityQuery<SmokeComponent>();
 
-                smoke.SpreadAmount++;
-                args.Updates--;
+        _random.Shuffle(args.Neighbors);
+        foreach (var neighbor in args.Neighbors)
+        {
+            if (!smokeQuery.TryGetComponent(neighbor, out var smoke))
+                continue;
 
-                if (component.SpreadAmount == 0)
-                {
-                    RemCompDeferred<EdgeSpreaderComponent>(uid);
-                    break;
-                }
+            smoke.SpreadAmount++;
+            args.Updates--;
+            component.SpreadAmount--;
+            EnsureComp<ActiveEdgeSpreaderComponent>(neighbor);
 
-                if (args.Updates <= 0)
-                    break;
+            if (component.SpreadAmount == 0)
+            {
+                RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
+                break;
             }
         }
     }
@@ -248,7 +226,7 @@ public sealed class SmokeSystem : EntitySystem
     public void Start(EntityUid uid, SmokeComponent component, Solution solution, float duration)
     {
         TryAddSolution(uid, component, solution);
-        EnsureComp<EdgeSpreaderComponent>(uid);
+        EnsureComp<ActiveEdgeSpreaderComponent>(uid);
         var timer = EnsureComp<TimedDespawnComponent>(uid);
         timer.Lifetime = duration;
     }
index 1af938da83634e5bcd2c6587bbcb5ffcb4288fc9..abebfd1a90fb5dbdb0473f6829f49be3e300d79a 100644 (file)
@@ -61,7 +61,6 @@ namespace Content.Server.NodeContainer.NodeGroups
         AMEngine,
         Pipe,
         WireNet,
-        Spreader,
 
         /// <summary>
         /// Group used by the TEG.
diff --git a/Content.Server/Spreader/ActiveEdgeSpreaderComponent.cs b/Content.Server/Spreader/ActiveEdgeSpreaderComponent.cs
new file mode 100644 (file)
index 0000000..86d59e7
--- /dev/null
@@ -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
+{
+}
index d0e18fccc298584baf80ebed806c5f1deeefc9d0..aa1bf47f7a68b385c689c7814a1e1cee8df7f265 100644 (file)
@@ -1,10 +1,14 @@
+using Content.Shared.Spreader;
+using Robust.Shared.Prototypes;
+
 namespace Content.Server.Spreader;
 
 /// <summary>
-/// Added to entities being considered for spreading via <see cref="SpreaderSystem"/>.
-/// This needs to be manually added and removed.
+/// Entity capable of becoming cloning and replicating itself to adjacent edges. See <see cref="SpreaderSystem"/>
 /// </summary>
 [RegisterComponent, Access(typeof(SpreaderSystem))]
 public sealed partial class EdgeSpreaderComponent : Component
 {
+    [DataField(required:true)]
+    public ProtoId<EdgeSpreaderPrototype> Id;
 }
index 98d34593d632cb1ed01501cba9bc821e16ab9e2f..d2cd6d640490d2586ef2c3a1e8e5a66909a894ae 100644 (file)
@@ -5,12 +5,6 @@ namespace Content.Server.Spreader;
 [RegisterComponent, Access(typeof(KudzuSystem))]
 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>
     /// The next time kudzu will try to tick its growth level.
     /// </summary>
index afdf510f05c64cd03366d1d2289cbd709abf2863..36b1796b83338eef7adfe7c7cc1b8a293fcd6e4c 100644 (file)
@@ -8,6 +8,12 @@ namespace Content.Server.Spreader;
 [RegisterComponent]
 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>
     /// Chance to spread whenever an edge spread is possible.
     /// </summary>
index db88226d799ea2a589e48ed88c4e0f795025a8fa..b59569b4e15d994e4079d3c6cdb09bb37c575c08 100644 (file)
@@ -2,6 +2,7 @@ using Content.Shared.Damage;
 using Content.Shared.Spreader;
 using Robust.Shared.Random;
 using Robust.Shared.Timing;
+using Robust.Shared.Utility;
 
 namespace Content.Server.Spreader;
 
@@ -13,7 +14,7 @@ public sealed class KudzuSystem : EntitySystem
     [Dependency] private readonly DamageableSystem _damageable = default!;
 
     [ValidatePrototypeId<EdgeSpreaderPrototype>]
-    private const string KudzuGroup = "kudzu";
+    private const string KudzuGroup = "Kudzu";
 
     /// <inheritdoc/>
     public override void Initialize()
@@ -21,7 +22,6 @@ public sealed class KudzuSystem : EntitySystem
         SubscribeLocalEvent<KudzuComponent, ComponentStartup>(SetupKudzu);
         SubscribeLocalEvent<KudzuComponent, SpreadNeighborsEvent>(OnKudzuSpread);
         SubscribeLocalEvent<GrowingKudzuComponent, EntityUnpausedEvent>(OnKudzuUnpaused);
-        SubscribeLocalEvent<SpreadGroupUpdateRate>(OnKudzuUpdateRate);
         SubscribeLocalEvent<KudzuComponent, DamageChangedEvent>(OnDamageChanged);
     }
 
@@ -36,59 +36,50 @@ public sealed class KudzuSystem : EntitySystem
             if (!TryComp(uid, out growing))
             {
                 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))
             {
-                _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)
     {
-        if (TryComp<GrowingKudzuComponent>(uid, out var growing) && growing.GrowthLevel < 3)
-        {
+        if (component.GrowthLevel < 3)
             return;
-        }
 
         if (args.NeighborFreeTiles.Count == 0)
         {
-            RemCompDeferred<EdgeSpreaderComponent>(uid);
+            RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
             return;
         }
 
+        if (!_robustRandom.Prob(component.SpreadChance))
+            return;
+
         var prototype = MetaData(uid).EntityPrototype?.ID;
 
         if (prototype == null)
         {
-            RemCompDeferred<EdgeSpreaderComponent>(uid);
+            RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
             return;
         }
 
-        if (!_robustRandom.Prob(component.SpreadChance))
-            return;
-
         foreach (var neighbor in args.NeighborFreeTiles)
         {
             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--;
-
             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;
@@ -109,24 +100,30 @@ public sealed class KudzuSystem : EntitySystem
     public override void Update(float frameTime)
     {
         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;
 
-        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)
-            {
                 continue;
-            }
 
             grow.NextTick = curTime + TimeSpan.FromSeconds(0.5);
 
+            if (!kudzuQuery.TryGetComponent(uid, out var kudzu))
+            {
+                RemCompDeferred(uid, grow);
+                continue;
+            }
+
             if (!_robustRandom.Prob(kudzu.GrowthTickChance))
             {
                 continue;
             }
 
-            if (TryComp<DamageableComponent>(uid, out var damage))
+            if (damageableQuery.TryGetComponent(uid, out var damage))
             {
                 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.
-                RemCompDeferred<GrowingKudzuComponent>(uid);
+                RemCompDeferred(uid, grow);
             }
 
             if (appearanceQuery.TryGetComponent(uid, out var appearance))
             {
-                _appearance.SetData(uid, KudzuVisuals.GrowthLevel, grow.GrowthLevel, appearance);
+                _appearance.SetData(uid, KudzuVisuals.GrowthLevel, kudzu.GrowthLevel, appearance);
             }
         }
     }
diff --git a/Content.Server/Spreader/SpreadGroupUpdateRate.cs b/Content.Server/Spreader/SpreadGroupUpdateRate.cs
deleted file mode 100644 (file)
index 091c6e5..0000000
+++ /dev/null
@@ -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);
diff --git a/Content.Server/Spreader/SpreaderNode.cs b/Content.Server/Spreader/SpreaderNode.cs
deleted file mode 100644 (file)
index 0c8a5c8..0000000
+++ /dev/null
@@ -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;
-        }
-    }
-}
diff --git a/Content.Server/Spreader/SpreaderNodeGroup.cs b/Content.Server/Spreader/SpreaderNodeGroup.cs
deleted file mode 100644 (file)
index a94ad83..0000000
+++ /dev/null
@@ -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);
-        }
-    }
-}
index e73fb1150745334303bdaf45b9e7f740ba4c3895..b6ebaf739be8171f207d9a1eb9708c462d29f40f 100644 (file)
@@ -1,8 +1,5 @@
 using Content.Server.Atmos.Components;
 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.Shared.Atmos;
 using Content.Shared.Spreader;
@@ -13,6 +10,7 @@ using Robust.Shared.Map.Components;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Random;
 using Robust.Shared.Timing;
+using Robust.Shared.Utility;
 
 namespace Content.Server.Spreader;
 
@@ -25,11 +23,20 @@ public sealed class SpreaderSystem : EntitySystem
     [Dependency] private readonly IMapManager _mapManager = default!;
     [Dependency] private readonly IPrototypeManager _prototype = 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>]
     private const string IgnoredTag = "SpreaderIgnore";
@@ -42,6 +49,7 @@ public sealed class SpreaderSystem : EntitySystem
 
         SubscribeLocalEvent<SpreaderGridComponent, EntityUnpausedEvent>(OnGridUnpaused);
 
+        SubscribeLocalEvent<EdgeSpreaderComponent, EntityTerminatingEvent>(OnTerminating);
         SetupPrototypes();
         _prototype.PrototypesReloaded += OnPrototypeReload;
     }
@@ -62,21 +70,20 @@ public sealed class SpreaderSystem : EntitySystem
 
     private void SetupPrototypes()
     {
-        _spreaderGroups.Clear();
-
-        foreach (var id in _prototype.EnumeratePrototypes<EdgeSpreaderPrototype>())
+        _prototypeUpdates = new Dictionary<string, int>();
+        foreach (var proto in _prototype.EnumeratePrototypes<EdgeSpreaderPrototype>())
         {
-            _spreaderGroups.Add(id.ID);
+            _prototypeUpdates.Add(proto.ID, proto.UpdatesPerSecond);
         }
     }
 
     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)
         {
-            EnsureComp<EdgeSpreaderComponent>(neighbor);
+            EnsureComp<ActiveEdgeSpreaderComponent>(neighbor);
         }
     }
 
@@ -87,7 +94,17 @@ public sealed class SpreaderSystem : EntitySystem
 
     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/>
@@ -96,31 +113,26 @@ public sealed class SpreaderSystem : EntitySystem
         var curTime = _timing.CurTime;
 
         // Check which grids are valid for spreading
-        var spreadable = new ValueList<EntityUid>();
         var spreadGrids = EntityQueryEnumerator<SpreaderGridComponent>();
 
+        _gridUpdates.Clear();
         while (spreadGrids.MoveNext(out var uid, out var grid))
         {
             if (grid.NextUpdate > curTime)
                 continue;
 
-            spreadable.Add(uid);
+            _gridUpdates[uid] = _prototypeUpdates.ShallowClone();
             grid.NextUpdate += SpreadCooldown;
         }
 
-        if (spreadable.Count == 0)
+        if (_gridUpdates.Count == 0)
             return;
 
-        var query = EntityQueryEnumerator<EdgeSpreaderComponent>();
-        var nodeQuery = GetEntityQuery<NodeContainerComponent>();
-        var xformQuery = GetEntityQuery<TransformComponent>();
-        var gridQuery = GetEntityQuery<SpreaderGridComponent>();
-
-        // Each INode group has a certain number of updates
-        // allowed per SpreadCooldown
-        var groupUpdates = new Dictionary<INodeGroup, int>();
+        var query = EntityQueryEnumerator<ActiveEdgeSpreaderComponent>();
+        var xforms = GetEntityQuery<TransformComponent>();
+        var spreaderQuery = GetEntityQuery<EdgeSpreaderComponent>();
 
-        var spreaders = new List<(EntityUid Uid, EdgeSpreaderComponent Comp)>(Count<EdgeSpreaderComponent>());
+        var spreaders = new List<(EntityUid Uid, ActiveEdgeSpreaderComponent Comp)>(Count<ActiveEdgeSpreaderComponent>());
 
         // Build a list of all existing Edgespreaders, shuffle them
         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
         foreach (var (uid, comp) in spreaders)
         {
-            if (!xformQuery.TryGetComponent(uid, out var xform) ||
-                xform.GridUid == null ||
-                !gridQuery.HasComponent(xform.GridUid.Value))
-            {
-                RemCompDeferred<EdgeSpreaderComponent>(uid);
+            // Get xform first, as entity may have been deleted due to interactions triggered by other spreaders.
+            if (!xforms.TryGetComponent(uid, out var xform))
                 continue;
-            }
 
-            foreach (var sGroup in _spreaderGroups)
+            if (xform.GridUid == null)
             {
-                // Get the NodeContainer and Node from every EdgeSpreader entity found
-                if (!nodeQuery.TryGetComponent(uid, out var nodeContainer))
-                {
-                    RemCompDeferred<EdgeSpreaderComponent>(uid);
-                    continue;
-                }
-
-                if (!_nodeContainer.TryGetNode<SpreaderNode>(nodeContainer, sGroup, out var node))
-                {
-                    continue;
-                }
+                RemComp(uid, comp);
+                continue;
+            }
 
-                // Not allowed this tick?
-                if (node.NodeGroup == null ||
-                    !spreadable.Contains(xform.GridUid.Value))
-                {
-                    continue;
-                }
+            if (!_gridUpdates.TryGetValue(xform.GridUid.Value, out var groupUpdates))
+                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));
-                }
+            if (!spreaderQuery.TryGetComponent(uid, out var spreader))
+            {
+                RemComp(uid, comp);
+                continue;
+            }
 
-                // "updates" integer dictates the amount of nodes that
-                // are to be spawned around a NodeGroup
-                if (updates <= 0)
-                {
-                    continue;
-                }
+            if (!groupUpdates.TryGetValue(spreader.Id, out var updates) || updates < 1)
+                continue;
 
-                // Edge detection logic is to be handled
-                // by the subscribing system, see KudzuSystem
-                // for a simple example
+            // Edge detection logic is to be handled
+            // by the subscribing system, see KudzuSystem
+            // for a simple example
+            Spread(uid, xform, spreader.Id, ref updates);
 
-                Spread(uid, node, node.NodeGroup, ref updates);
-                groupUpdates[node.NodeGroup] = updates;
-            }
+            if (updates < 1)
+                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()
         {
@@ -207,20 +198,19 @@ public sealed class SpreaderSystem : EntitySystem
     /// <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<(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)>();
         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 spreaderQuery = GetEntityQuery<EdgeSpreaderComponent>();
         var airtightQuery = GetEntityQuery<AirtightComponent>();
         var dockQuery = GetEntityQuery<DockingComponent>();
         var xformQuery = GetEntityQuery<TransformComponent>();
@@ -309,10 +299,10 @@ public sealed class SpreaderSystem : EntitySystem
 
             while (directionEnumerator.MoveNext(out var ent))
             {
-                if (!nodeQuery.TryGetComponent(ent, out var nodeContainer))
+                if (!spreaderQuery.TryGetComponent(ent, out var spreader))
                     continue;
 
-                if (!nodeContainer.Nodes.ContainsKey(groupName))
+                if (spreader.Id != prototype)
                     continue;
 
                 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>();
 
-        if (!EntityManager.TryGetComponent<TransformComponent>(uid, out var transform))
-            return neighbors; // how did we get here?
+        Vector2i tile;
+        MapGridComponent? grid;
 
-        if (!_mapManager.TryGetGrid(transform.GridUid, out var grid))
-            return neighbors;
+        if (position == null)
+        {
+            var transform = Transform(uid);
+            if (!_mapManager.TryGetGrid(transform.GridUid, out grid))
+                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 nodeQuery = GetEntityQuery<NodeContainerComponent>();
+        var spreaderQuery = GetEntityQuery<EdgeSpreaderComponent>();
 
         for (var i = 0; i < Atmospherics.Directions; i++)
         {
             var direction = (AtmosDirection) (1 << i);
-            if (!comp.AirBlockedDirection.IsFlagSet(direction))
+            if (comp != null && !comp.AirBlockedDirection.IsFlagSet(direction))
                 continue;
 
             var directionEnumerator =
@@ -349,17 +354,9 @@ public sealed class SpreaderSystem : EntitySystem
 
             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;
-
+                DebugTools.Assert(Transform(ent.Value).Anchored);
+                if (spreaderQuery.HasComponent(ent))
                     neighbors.Add(ent.Value);
-                    break;
-                }
             }
         }
 
index 2fab110fdbd94dc2db3fdcbfbb8d85ed7133611f..a1e31da3caa67202f19c560ecb76e18ee6358e8d 100644 (file)
@@ -9,4 +9,5 @@ namespace Content.Shared.Spreader;
 public sealed class EdgeSpreaderPrototype : IPrototype
 {
     [IdDataField] public string ID { get; } = string.Empty;
+    [DataField(required:true)] public int UpdatesPerSecond;
 }
index def26ec8265ae02cbf467ba9d7fae78a56b4590c..10e2f1f7db759cdc44ce2eb6545e47a0b7ce1b86 100644 (file)
   - type: Transform
     anchored: true
   - type: Smoke
-  - type: NodeContainer
-    nodes:
-      smoke:
-        !type:SpreaderNode
-        nodeGroupID: Spreader
+  - type: ActiveEdgeSpreader
   - type: EdgeSpreader
+    id: Smoke
   - type: SolutionContainerManager
     solutions:
       solutionArea:
         layer:
         - SlipLayer
   - type: Smoke
-  - type: NodeContainer
-    nodes:
-      smoke:
-        !type:SpreaderNode
-        nodeGroupID: Spreader
+  - type: ActiveEdgeSpreader
   - type: EdgeSpreader
+    id: Smoke
   - type: SolutionContainerManager
     solutions:
       solutionArea:
index 09e10a688bcb34a89ff7a8604efce142ab39d41b..090533acb80d33ca2141c8c86de16a574ffdaa90 100644 (file)
       puddle: { maxVol: 1000 }
   - type: Puddle
   - type: Appearance
+  - type: ActiveEdgeSpreader
   - type: EdgeSpreader
+    id: Puddle
   - type: StepTrigger
-  - type: NodeContainer
-    nodes:
-      puddle:
-        !type:SpreaderNode
-        nodeGroupID: Spreader
   - type: Drink
     delay: 3
     transferAmount: 1
index 1ff3ee0fc376995114de3c0829229ffa1b1c9292..48b0068d9419ba1749a36210b5fecd34cc0b1d08 100644 (file)
       ignoreWhitelist:
         components:
         - IgnoreKudzu
+    - type: ActiveEdgeSpreader
     - type: EdgeSpreader
-    - type: NodeContainer
-      nodes:
-        kudzu:
-          !type:SpreaderNode
-          nodeGroupID: Spreader
+      id: Kudzu
     - type: Food
       requiredStomachs: 2 # ruminants have 4 stomachs but i dont care to give them literally 4 stomachs. 2 is good
       delay: 0.5
     - type: GrowingKudzu
       growthTickChance: 0.3
     - type: AtmosExposed
+    - type: ActiveEdgeSpreader
     - type: EdgeSpreader
-    - type: NodeContainer
-      nodes:
-        kudzu:
-          !type:SpreaderNode
-          nodeGroupID: Spreader
+      id: Kudzu
     - type: SlowContacts
       walkSpeedModifier: 0.3
       sprintSpeedModifier: 0.3
index 4cd1ada1c1a9e97d80b723405b4f9aba972aae84..061932c706db3cf38bebbd9f0053b915cf8a6004 100644 (file)
@@ -1,8 +1,11 @@
 - type: edgeSpreader
-  id: kudzu
+  id: Kudzu
+  updatesPerSecond: 1
 
 - type: edgeSpreader
-  id: puddle
+  id: Puddle
+  updatesPerSecond: 16
 
 - type: edgeSpreader
-  id: smoke
\ No newline at end of file
+  id: Smoke
+  updatesPerSecond: 8