From ede8a1d37732256aa211f9436f47513523db0f3a Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Mon, 9 Dec 2024 00:20:04 +0100 Subject: [PATCH] Fix gas pipe leaking when unanchoring or breaking them (#33774) * fix gas pipe unanchoring * remove unneeded update * revert popup change --- .../AtmosUnsafeUnanchorSystem.cs | 47 +++++++++---------- .../EntitySystems/NodeGroupSystem.cs | 7 +++ 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/Content.Server/Atmos/Piping/EntitySystems/AtmosUnsafeUnanchorSystem.cs b/Content.Server/Atmos/Piping/EntitySystems/AtmosUnsafeUnanchorSystem.cs index f594866fa23fec..bc925e433ca61a 100644 --- a/Content.Server/Atmos/Piping/EntitySystems/AtmosUnsafeUnanchorSystem.cs +++ b/Content.Server/Atmos/Piping/EntitySystems/AtmosUnsafeUnanchorSystem.cs @@ -1,6 +1,7 @@ using Content.Server.Atmos.EntitySystems; using Content.Server.Atmos.Piping.Components; using Content.Server.NodeContainer; +using Content.Server.NodeContainer.EntitySystems; using Content.Server.NodeContainer.Nodes; using Content.Server.Popups; using Content.Shared.Atmos; @@ -8,7 +9,6 @@ using Content.Shared.Destructible; using Content.Shared.Popups; using JetBrains.Annotations; -using Robust.Shared.Player; namespace Content.Server.Atmos.Piping.EntitySystems { @@ -16,11 +16,12 @@ namespace Content.Server.Atmos.Piping.EntitySystems public sealed class AtmosUnsafeUnanchorSystem : EntitySystem { [Dependency] private readonly AtmosphereSystem _atmosphere = default!; + [Dependency] private readonly NodeGroupSystem _group = default!; [Dependency] private readonly PopupSystem _popup = default!; public override void Initialize() { - SubscribeLocalEvent(OnBeforeUnanchored); + SubscribeLocalEvent(OnUserUnanchored); SubscribeLocalEvent(OnUnanchorAttempt); SubscribeLocalEvent(OnBreak); } @@ -48,15 +49,22 @@ private void OnUnanchorAttempt(EntityUid uid, AtmosUnsafeUnanchorComponent compo } } - private void OnBeforeUnanchored(EntityUid uid, AtmosUnsafeUnanchorComponent component, BeforeUnanchoredEvent args) + // When unanchoring a pipe, leak the gas that was inside the pipe element. + // At this point the pipe has been scheduled to be removed from the group, but that won't happen until the next Update() call in NodeGroupSystem, + // so we have to force an update. + // This way the gas inside other connected pipes stays unchanged, while the removed pipe is completely emptied. + private void OnUserUnanchored(EntityUid uid, AtmosUnsafeUnanchorComponent component, UserUnanchoredEvent args) { if (component.Enabled) + { + _group.ForceUpdate(); LeakGas(uid); + } } private void OnBreak(EntityUid uid, AtmosUnsafeUnanchorComponent component, BreakageEventArgs args) { - LeakGas(uid); + LeakGas(uid, false); // Can't use DoActsBehavior["Destruction"] in the same trigger because that would prevent us // from leaking. So we make up for this by queueing deletion here. QueueDel(uid); @@ -64,32 +72,17 @@ private void OnBreak(EntityUid uid, AtmosUnsafeUnanchorComponent component, Brea /// /// Leak gas from the uid's NodeContainer into the tile atmosphere. + /// Setting removeFromPipe to false will duplicate the gas inside the pipe intead of moving it. + /// This is needed to properly handle the gas in the pipe getting deleted with the pipe. /// - public void LeakGas(EntityUid uid) + public void LeakGas(EntityUid uid, bool removeFromPipe = true) { if (!EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodes)) return; - if (_atmosphere.GetContainingMixture(uid, true, true) is not {} environment) + if (_atmosphere.GetContainingMixture(uid, true, true) is not { } environment) environment = GasMixture.SpaceGas; - var lost = 0f; - var timesLost = 0; - - foreach (var node in nodes.Nodes.Values) - { - if (node is not PipeNode pipe) - continue; - - var difference = pipe.Air.Pressure - environment.Pressure; - lost += Math.Min( - pipe.Volume / pipe.Air.Volume * pipe.Air.TotalMoles, - difference * environment.Volume / (environment.Temperature * Atmospherics.R) - ); - timesLost++; - } - - var sharedLoss = lost / timesLost; var buffer = new GasMixture(); foreach (var node in nodes.Nodes.Values) @@ -97,7 +90,13 @@ public void LeakGas(EntityUid uid) if (node is not PipeNode pipe) continue; - _atmosphere.Merge(buffer, pipe.Air.Remove(sharedLoss)); + if (removeFromPipe) + _atmosphere.Merge(buffer, pipe.Air.RemoveVolume(pipe.Volume)); + else + { + var copy = new GasMixture(pipe.Air); //clone, then remove to keep the original untouched + _atmosphere.Merge(buffer, copy.RemoveVolume(pipe.Volume)); + } } _atmosphere.Merge(environment, buffer); diff --git a/Content.Server/NodeContainer/EntitySystems/NodeGroupSystem.cs b/Content.Server/NodeContainer/EntitySystems/NodeGroupSystem.cs index 2296de2eb6a3e3..62806fe84fb0b6 100644 --- a/Content.Server/NodeContainer/EntitySystems/NodeGroupSystem.cs +++ b/Content.Server/NodeContainer/EntitySystems/NodeGroupSystem.cs @@ -149,6 +149,13 @@ public override void Update(float frameTime) } } + // used to manually force an update for the groups + // the VisDoUpdate will be done with the next scheduled update + public void ForceUpdate() + { + DoGroupUpdates(); + } + private void DoGroupUpdates() { // "Why is there a separate queue for group remakes and node refloods when they both cause eachother"