diff --git a/Content.Client/Administration/UI/Tabs/AtmosTab/AddGasWindow.xaml.cs b/Content.Client/Administration/UI/Tabs/AtmosTab/AddGasWindow.xaml.cs
index 4587b419d3..273d194196 100644
--- a/Content.Client/Administration/UI/Tabs/AtmosTab/AddGasWindow.xaml.cs
+++ b/Content.Client/Administration/UI/Tabs/AtmosTab/AddGasWindow.xaml.cs
@@ -1,8 +1,9 @@
#nullable enable
using System.Collections.Generic;
using System.Linq;
-using Content.Client.GameObjects.EntitySystems;
+using Content.Client.Atmos.EntitySystems;
using Content.Shared.Atmos;
+using Content.Shared.Atmos.Prototypes;
using JetBrains.Annotations;
using Robust.Client.AutoGenerated;
using Robust.Client.Console;
diff --git a/Content.Client/Administration/UI/Tabs/AtmosTab/FillGasWindow.xaml.cs b/Content.Client/Administration/UI/Tabs/AtmosTab/FillGasWindow.xaml.cs
index 0acd97e52b..2465d8c61d 100644
--- a/Content.Client/Administration/UI/Tabs/AtmosTab/FillGasWindow.xaml.cs
+++ b/Content.Client/Administration/UI/Tabs/AtmosTab/FillGasWindow.xaml.cs
@@ -1,8 +1,9 @@
#nullable enable
using System.Collections.Generic;
using System.Linq;
-using Content.Client.GameObjects.EntitySystems;
+using Content.Client.Atmos.EntitySystems;
using Content.Shared.Atmos;
+using Content.Shared.Atmos.Prototypes;
using JetBrains.Annotations;
using Robust.Client.AutoGenerated;
using Robust.Client.Console;
diff --git a/Content.Client/GameObjects/Components/Atmos/GasAnalyzerComponent.cs b/Content.Client/Atmos/Components/GasAnalyzerComponent.cs
similarity index 95%
rename from Content.Client/GameObjects/Components/Atmos/GasAnalyzerComponent.cs
rename to Content.Client/Atmos/Components/GasAnalyzerComponent.cs
index 41720a8408..bb5ee4e7bd 100644
--- a/Content.Client/GameObjects/Components/Atmos/GasAnalyzerComponent.cs
+++ b/Content.Client/Atmos/Components/GasAnalyzerComponent.cs
@@ -1,7 +1,7 @@
using Content.Client.Items.Components;
using Content.Client.Message;
using Content.Client.Stylesheets;
-using Content.Shared.GameObjects.Components;
+using Content.Shared.Atmos.Components;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.GameObjects;
@@ -9,7 +9,7 @@ using Robust.Shared.Localization;
using Robust.Shared.Timing;
using Robust.Shared.ViewVariables;
-namespace Content.Client.GameObjects.Components.Atmos
+namespace Content.Client.Atmos.Components
{
[RegisterComponent]
internal class GasAnalyzerComponent : SharedGasAnalyzerComponent, IItemStatus
diff --git a/Content.Client/GameObjects/EntitySystems/AtmosDebugOverlaySystem.cs b/Content.Client/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs
similarity index 95%
rename from Content.Client/GameObjects/EntitySystems/AtmosDebugOverlaySystem.cs
rename to Content.Client/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs
index 880475471e..fe18e1fc5f 100644
--- a/Content.Client/GameObjects/EntitySystems/AtmosDebugOverlaySystem.cs
+++ b/Content.Client/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs
@@ -1,9 +1,8 @@
#nullable enable
-using System;
using System.Collections.Generic;
-using Content.Client.Atmos;
-using Content.Shared.GameObjects.EntitySystems.Atmos;
+using Content.Client.Atmos.Overlays;
using Content.Shared.Atmos;
+using Content.Shared.Atmos.EntitySystems;
using Content.Shared.GameTicking;
using JetBrains.Annotations;
using Robust.Client.Graphics;
@@ -11,7 +10,7 @@ using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
-namespace Content.Client.GameObjects.EntitySystems
+namespace Content.Client.Atmos.EntitySystems
{
[UsedImplicitly]
internal sealed class AtmosDebugOverlaySystem : SharedAtmosDebugOverlaySystem, IResettingEntitySystem
diff --git a/Content.Client/GameObjects/EntitySystems/AtmosphereSystem.cs b/Content.Client/Atmos/EntitySystems/AtmosphereSystem.cs
similarity index 53%
rename from Content.Client/GameObjects/EntitySystems/AtmosphereSystem.cs
rename to Content.Client/Atmos/EntitySystems/AtmosphereSystem.cs
index 9b6f57f06d..ee67361146 100644
--- a/Content.Client/GameObjects/EntitySystems/AtmosphereSystem.cs
+++ b/Content.Client/Atmos/EntitySystems/AtmosphereSystem.cs
@@ -1,7 +1,7 @@
-using Content.Shared.GameObjects.EntitySystems.Atmos;
+using Content.Shared.Atmos.EntitySystems;
using JetBrains.Annotations;
-namespace Content.Client.GameObjects.EntitySystems
+namespace Content.Client.Atmos.EntitySystems
{
[UsedImplicitly]
public class AtmosphereSystem : SharedAtmosphereSystem
diff --git a/Content.Client/GameObjects/EntitySystems/GasTileOverlaySystem.cs b/Content.Client/Atmos/EntitySystems/GasTileOverlaySystem.cs
similarity index 97%
rename from Content.Client/GameObjects/EntitySystems/GasTileOverlaySystem.cs
rename to Content.Client/Atmos/EntitySystems/GasTileOverlaySystem.cs
index 2efe25f0e9..470c4cae0c 100644
--- a/Content.Client/GameObjects/EntitySystems/GasTileOverlaySystem.cs
+++ b/Content.Client/Atmos/EntitySystems/GasTileOverlaySystem.cs
@@ -1,20 +1,19 @@
#nullable enable
using System;
using System.Collections.Generic;
-using Content.Client.Atmos;
+using Content.Client.Atmos.Overlays;
using Content.Shared.Atmos;
-using Content.Shared.GameObjects.EntitySystems.Atmos;
+using Content.Shared.Atmos.EntitySystems;
using JetBrains.Annotations;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.Utility;
using Robust.Shared.IoC;
-using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
-namespace Content.Client.GameObjects.EntitySystems
+namespace Content.Client.Atmos.EntitySystems
{
[UsedImplicitly]
internal sealed class GasTileOverlaySystem : SharedGasTileOverlaySystem
diff --git a/Content.Client/Atmos/AtmosDebugOverlay.cs b/Content.Client/Atmos/Overlays/AtmosDebugOverlay.cs
similarity index 98%
rename from Content.Client/Atmos/AtmosDebugOverlay.cs
rename to Content.Client/Atmos/Overlays/AtmosDebugOverlay.cs
index c0987545c1..cf6cd4b424 100644
--- a/Content.Client/Atmos/AtmosDebugOverlay.cs
+++ b/Content.Client/Atmos/Overlays/AtmosDebugOverlay.cs
@@ -1,15 +1,14 @@
-using Content.Client.GameObjects.EntitySystems;
-using Content.Shared.GameObjects.EntitySystems.Atmos;
+using Content.Client.Atmos.EntitySystems;
using Content.Shared.Atmos;
+using Content.Shared.Atmos.EntitySystems;
using Robust.Client.Graphics;
+using Robust.Shared.Enums;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
-using Robust.Shared.Enums;
-using System;
-namespace Content.Client.Atmos
+namespace Content.Client.Atmos.Overlays
{
public class AtmosDebugOverlay : Overlay
{
diff --git a/Content.Client/Atmos/GasTileOverlay.cs b/Content.Client/Atmos/Overlays/GasTileOverlay.cs
similarity index 95%
rename from Content.Client/Atmos/GasTileOverlay.cs
rename to Content.Client/Atmos/Overlays/GasTileOverlay.cs
index 30e31ef0c2..06b5c3bc4f 100644
--- a/Content.Client/Atmos/GasTileOverlay.cs
+++ b/Content.Client/Atmos/Overlays/GasTileOverlay.cs
@@ -1,12 +1,12 @@
-using Content.Client.GameObjects.EntitySystems;
-using Robust.Shared.Enums;
+using Content.Client.Atmos.EntitySystems;
using Robust.Client.Graphics;
+using Robust.Shared.Enums;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
-namespace Content.Client.Atmos
+namespace Content.Client.Atmos.Overlays
{
public class GasTileOverlay : Overlay
{
diff --git a/Content.Client/Atmos/Piping/EnabledAtmosDeviceVisualizer.cs b/Content.Client/Atmos/Piping/EnabledAtmosDeviceVisualizer.cs
new file mode 100644
index 0000000000..93b2913567
--- /dev/null
+++ b/Content.Client/Atmos/Piping/EnabledAtmosDeviceVisualizer.cs
@@ -0,0 +1,39 @@
+using System;
+using JetBrains.Annotations;
+using Robust.Client.GameObjects;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization.Manager.Attributes;
+
+namespace Content.Client.Atmos.Piping
+{
+ [UsedImplicitly]
+ public abstract class EnabledAtmosDeviceVisualizer : AppearanceVisualizer
+ {
+ [DataField("enabledState")]
+ private string _enabledState = string.Empty;
+ protected abstract object LayerMap { get; }
+ protected abstract Enum DataKey { get; }
+
+ public override void InitializeEntity(IEntity entity)
+ {
+ base.InitializeEntity(entity);
+
+ if (!entity.TryGetComponent(out ISpriteComponent? sprite))
+ return;
+
+ sprite.LayerMapSet(LayerMap, sprite.AddLayerState(_enabledState));
+ sprite.LayerSetVisible(LayerMap, false);
+ }
+
+ public override void OnChangeData(AppearanceComponent component)
+ {
+ base.OnChangeData(component);
+
+ if (!component.Owner.TryGetComponent(out ISpriteComponent? sprite))
+ return;
+
+ if(component.TryGetData(DataKey, out bool enabled))
+ sprite.LayerSetVisible(LayerMap, enabled);
+ }
+ }
+}
diff --git a/Content.Client/Atmos/Piping/OutletInjectorVisualizer.cs b/Content.Client/Atmos/Piping/OutletInjectorVisualizer.cs
new file mode 100644
index 0000000000..2d4cad5cf6
--- /dev/null
+++ b/Content.Client/Atmos/Piping/OutletInjectorVisualizer.cs
@@ -0,0 +1,18 @@
+using System;
+using Content.Shared.Atmos.Piping;
+using JetBrains.Annotations;
+
+namespace Content.Client.Atmos.Piping
+{
+ [UsedImplicitly]
+ public class OutletInjectorVisualizer : EnabledAtmosDeviceVisualizer
+ {
+ protected override object LayerMap => Layers.Enabled;
+ protected override Enum DataKey => OutletInjectorVisuals.Enabled;
+
+ enum Layers
+ {
+ Enabled,
+ }
+ }
+}
diff --git a/Content.Client/Atmos/Piping/PassiveVentVisualizer.cs b/Content.Client/Atmos/Piping/PassiveVentVisualizer.cs
new file mode 100644
index 0000000000..a932eb055a
--- /dev/null
+++ b/Content.Client/Atmos/Piping/PassiveVentVisualizer.cs
@@ -0,0 +1,18 @@
+using System;
+using Content.Shared.Atmos.Piping;
+using JetBrains.Annotations;
+
+namespace Content.Client.Atmos.Piping
+{
+ [UsedImplicitly]
+ public class PassiveVentVisualizer : EnabledAtmosDeviceVisualizer
+ {
+ protected override object LayerMap => Layers.Enabled;
+ protected override Enum DataKey => PassiveVentVisuals.Enabled;
+
+ enum Layers
+ {
+ Enabled,
+ }
+ }
+}
diff --git a/Content.Client/GameObjects/Components/Atmos/Piping/PipeConnectorVisualizer.cs b/Content.Client/Atmos/Piping/PipeConnectorVisualizer.cs
similarity index 91%
rename from Content.Client/GameObjects/Components/Atmos/Piping/PipeConnectorVisualizer.cs
rename to Content.Client/Atmos/Piping/PipeConnectorVisualizer.cs
index dbdc1df5e9..93e70bf8d3 100644
--- a/Content.Client/GameObjects/Components/Atmos/Piping/PipeConnectorVisualizer.cs
+++ b/Content.Client/Atmos/Piping/PipeConnectorVisualizer.cs
@@ -1,6 +1,6 @@
#nullable enable
using System;
-using Content.Shared.GameObjects.Components.Atmos;
+using Content.Shared.Atmos;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
@@ -10,9 +10,8 @@ using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
-using YamlDotNet.RepresentationModel;
-namespace Content.Client.GameObjects.Components.Atmos.Piping
+namespace Content.Client.Atmos.Piping
{
[UsedImplicitly]
public class PipeConnectorVisualizer : AppearanceVisualizer, ISerializationHooks
@@ -33,7 +32,7 @@ namespace Content.Client.GameObjects.Components.Atmos.Piping
if (resourceCache.TryGetResource(rsiString, out RSIResource? rsi))
_connectorRsi = rsi.RSI;
else
- Logger.Error($"{nameof(PipeVisualizer)} could not load to load RSI {rsiString}.");
+ Logger.Error($"{nameof(PipeConnectorVisualizer)} could not load to load RSI {rsiString}.");
}
public override void InitializeEntity(IEntity entity)
diff --git a/Content.Client/Atmos/Piping/PressurePumpVisualizer.cs b/Content.Client/Atmos/Piping/PressurePumpVisualizer.cs
new file mode 100644
index 0000000000..acdf4350d0
--- /dev/null
+++ b/Content.Client/Atmos/Piping/PressurePumpVisualizer.cs
@@ -0,0 +1,18 @@
+using System;
+using Content.Shared.Atmos.Piping;
+using JetBrains.Annotations;
+
+namespace Content.Client.Atmos.Piping
+{
+ [UsedImplicitly]
+ public class PressurePumpVisualizer : EnabledAtmosDeviceVisualizer
+ {
+ protected override object LayerMap => Layers.Enabled;
+ protected override Enum DataKey => PressurePumpVisuals.Enabled;
+
+ enum Layers
+ {
+ Enabled,
+ }
+ }
+}
diff --git a/Content.Client/Atmos/Piping/ScrubberVisualizer.cs b/Content.Client/Atmos/Piping/ScrubberVisualizer.cs
new file mode 100644
index 0000000000..b4add93bcd
--- /dev/null
+++ b/Content.Client/Atmos/Piping/ScrubberVisualizer.cs
@@ -0,0 +1,52 @@
+using Content.Shared.Atmos.Piping.Unary.Visuals;
+using Content.Shared.Atmos.Visuals;
+using JetBrains.Annotations;
+using Robust.Client.GameObjects;
+
+namespace Content.Client.Atmos.Piping
+{
+ [UsedImplicitly]
+ public class ScrubberVisualizer : AppearanceVisualizer
+ {
+ private string _offState = "scrub_off";
+ private string _scrubState = "scrub_on";
+ private string _siphonState = "scrub_purge";
+ private string _weldedState = "scrub_welded";
+ private string _wideState = "scrub_wide";
+
+ public override void OnChangeData(AppearanceComponent component)
+ {
+ base.OnChangeData(component);
+
+ if (!component.Owner.TryGetComponent(out ISpriteComponent? sprite))
+ return;
+
+ if (!component.TryGetData(ScrubberVisuals.State, out ScrubberState state))
+ return;
+
+ switch (state)
+ {
+ case ScrubberState.Off:
+ sprite.LayerSetState(ScrubberVisualLayers.Scrubber, _offState);
+ break;
+ case ScrubberState.Scrub:
+ sprite.LayerSetState(ScrubberVisualLayers.Scrubber, _scrubState);
+ break;
+ case ScrubberState.Siphon:
+ sprite.LayerSetState(ScrubberVisualLayers.Scrubber, _siphonState);
+ break;
+ case ScrubberState.Welded:
+ sprite.LayerSetState(ScrubberVisualLayers.Scrubber, _weldedState);
+ break;
+ case ScrubberState.WideScrub:
+ sprite.LayerSetState(ScrubberVisualLayers.Scrubber, _wideState);
+ break;
+ }
+ }
+ }
+
+ public enum ScrubberVisualLayers
+ {
+ Scrubber,
+ }
+}
diff --git a/Content.Client/Atmos/Piping/ThermoMachineVisualizer.cs b/Content.Client/Atmos/Piping/ThermoMachineVisualizer.cs
new file mode 100644
index 0000000000..2a1136a951
--- /dev/null
+++ b/Content.Client/Atmos/Piping/ThermoMachineVisualizer.cs
@@ -0,0 +1,18 @@
+using System;
+using Content.Shared.Atmos.Piping;
+using JetBrains.Annotations;
+
+namespace Content.Client.Atmos.Piping
+{
+ [UsedImplicitly]
+ public class ThermoMachineVisualizer : EnabledAtmosDeviceVisualizer
+ {
+ protected override object LayerMap => Layers.Enabled;
+ protected override Enum DataKey => ThermoMachineVisuals.Enabled;
+
+ enum Layers
+ {
+ Enabled,
+ }
+ }
+}
diff --git a/Content.Client/Atmos/Piping/VentPumpVisualizer.cs b/Content.Client/Atmos/Piping/VentPumpVisualizer.cs
new file mode 100644
index 0000000000..d31dad27a8
--- /dev/null
+++ b/Content.Client/Atmos/Piping/VentPumpVisualizer.cs
@@ -0,0 +1,47 @@
+using Content.Shared.Atmos.Visuals;
+using JetBrains.Annotations;
+using Robust.Client.GameObjects;
+
+namespace Content.Client.Atmos.Piping
+{
+ [UsedImplicitly]
+ public class VentPumpVisualizer : AppearanceVisualizer
+ {
+ private string _offState = "vent_off";
+ private string _inState = "vent_in";
+ private string _outState = "vent_out";
+ private string _weldedState = "vent_welded";
+
+ public override void OnChangeData(AppearanceComponent component)
+ {
+ base.OnChangeData(component);
+
+ if (!component.Owner.TryGetComponent(out ISpriteComponent? sprite))
+ return;
+
+ if (!component.TryGetData(VentPumpVisuals.State, out VentPumpState state))
+ return;
+
+ switch (state)
+ {
+ case VentPumpState.Off:
+ sprite.LayerSetState(VentVisualLayers.Vent, _offState);
+ break;
+ case VentPumpState.In:
+ sprite.LayerSetState(VentVisualLayers.Vent, _inState);
+ break;
+ case VentPumpState.Out:
+ sprite.LayerSetState(VentVisualLayers.Vent, _outState);
+ break;
+ case VentPumpState.Welded:
+ sprite.LayerSetState(VentVisualLayers.Vent, _weldedState);
+ break;
+ }
+ }
+ }
+
+ public enum VentVisualLayers
+ {
+ Vent,
+ }
+}
diff --git a/Content.Client/GameObjects/Components/Atmos/GasAnalyzerBoundUserInterface.cs b/Content.Client/Atmos/UI/GasAnalyzerBoundUserInterface.cs
similarity index 88%
rename from Content.Client/GameObjects/Components/Atmos/GasAnalyzerBoundUserInterface.cs
rename to Content.Client/Atmos/UI/GasAnalyzerBoundUserInterface.cs
index 98d07f1ef9..ad25648633 100644
--- a/Content.Client/GameObjects/Components/Atmos/GasAnalyzerBoundUserInterface.cs
+++ b/Content.Client/Atmos/UI/GasAnalyzerBoundUserInterface.cs
@@ -1,8 +1,8 @@
using Robust.Client.GameObjects;
using Robust.Shared.GameObjects;
-using static Content.Shared.GameObjects.Components.SharedGasAnalyzerComponent;
+using static Content.Shared.Atmos.Components.SharedGasAnalyzerComponent;
-namespace Content.Client.GameObjects.Components.Atmos
+namespace Content.Client.Atmos.UI
{
public class GasAnalyzerBoundUserInterface : BoundUserInterface
{
diff --git a/Content.Client/GameObjects/Components/Atmos/GasAnalyzerMenu.cs b/Content.Client/Atmos/UI/GasAnalyzerMenu.cs
similarity index 98%
rename from Content.Client/GameObjects/Components/Atmos/GasAnalyzerMenu.cs
rename to Content.Client/Atmos/UI/GasAnalyzerMenu.cs
index 15adc5890a..d05c454e38 100644
--- a/Content.Client/GameObjects/Components/Atmos/GasAnalyzerMenu.cs
+++ b/Content.Client/Atmos/UI/GasAnalyzerMenu.cs
@@ -9,9 +9,9 @@ using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
-using static Content.Shared.GameObjects.Components.SharedGasAnalyzerComponent;
+using static Content.Shared.Atmos.Components.SharedGasAnalyzerComponent;
-namespace Content.Client.GameObjects.Components.Atmos
+namespace Content.Client.Atmos.UI
{
public class GasAnalyzerWindow : BaseWindow
{
diff --git a/Content.Client/Atmos/UI/GasCanisterBoundUserInterface.cs b/Content.Client/Atmos/UI/GasCanisterBoundUserInterface.cs
new file mode 100644
index 0000000000..0f21ef4b1d
--- /dev/null
+++ b/Content.Client/Atmos/UI/GasCanisterBoundUserInterface.cs
@@ -0,0 +1,86 @@
+using Content.Shared.Atmos.Piping.Binary.Components;
+using JetBrains.Annotations;
+using Robust.Client.GameObjects;
+using Robust.Shared.GameObjects;
+
+namespace Content.Client.Atmos.UI
+{
+ ///
+ /// Initializes a and updates it when new server messages are received.
+ ///
+ [UsedImplicitly]
+ public class GasCanisterBoundUserInterface : BoundUserInterface
+ {
+
+ private GasCanisterWindow? _window;
+
+ public GasCanisterBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
+ {
+ }
+
+ protected override void Open()
+ {
+ base.Open();
+
+ _window = new GasCanisterWindow();
+
+ if(State != null)
+ UpdateState(State);
+
+ _window.OpenCentered();
+
+ _window.OnClose += Close;
+ _window.ReleaseValveCloseButtonPressed += OnReleaseValveClosePressed;
+ _window.ReleaseValveOpenButtonPressed += OnReleaseValveOpenPressed;
+ _window.ReleasePressureSliderChanged += OnReleasePressurePressed;
+ _window.TankEjectButtonPressed += OnTankEjectPressed;
+ }
+
+ private void OnTankEjectPressed()
+ {
+ SendMessage(new GasCanisterHoldingTankEjectMessage());
+ }
+
+ private void OnReleasePressurePressed(float value)
+ {
+ SendMessage(new GasCanisterChangeReleasePressureMessage(value));
+ }
+
+ private void OnReleaseValveOpenPressed()
+ {
+ SendMessage(new GasCanisterChangeReleaseValveMessage(true));
+ }
+
+ private void OnReleaseValveClosePressed()
+ {
+ SendMessage(new GasCanisterChangeReleaseValveMessage(false));
+ }
+
+ ///
+ /// Update the UI state based on server-sent info
+ ///
+ ///
+ protected override void UpdateState(BoundUserInterfaceState state)
+ {
+ base.UpdateState(state);
+ if (_window == null || state is not GasCanisterBoundUserInterfaceState cast)
+ return;
+
+ _window.SetCanisterLabel(cast.CanisterLabel);
+ _window.SetCanisterPressure(cast.CanisterPressure);
+ _window.SetPortStatus(cast.PortStatus);
+ _window.SetTankLabel(cast.TankLabel);
+ _window.SetTankPressure(cast.TankPressure);
+ _window.SetReleasePressureRange(cast.ReleasePressureMin, cast.ReleasePressureMax);
+ _window.SetReleasePressure(cast.ReleasePressure);
+ _window.SetReleaseValve(cast.ReleaseValve);
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+ if (!disposing) return;
+ _window?.Dispose();
+ }
+ }
+}
diff --git a/Content.Client/Atmos/UI/GasCanisterWindow.xaml b/Content.Client/Atmos/UI/GasCanisterWindow.xaml
new file mode 100644
index 0000000000..6bddc2ced3
--- /dev/null
+++ b/Content.Client/Atmos/UI/GasCanisterWindow.xaml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/Atmos/UI/GasCanisterWindow.xaml.cs b/Content.Client/Atmos/UI/GasCanisterWindow.xaml.cs
new file mode 100644
index 0000000000..7720007044
--- /dev/null
+++ b/Content.Client/Atmos/UI/GasCanisterWindow.xaml.cs
@@ -0,0 +1,98 @@
+using System;
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.CustomControls;
+using Robust.Client.UserInterface.XAML;
+using Robust.Shared.Localization;
+
+namespace Content.Client.Atmos.UI
+{
+ ///
+ /// Client-side UI used to control a canister.
+ ///
+ [GenerateTypedNameReferences]
+ public partial class GasCanisterWindow : SS14Window
+ {
+ private readonly ButtonGroup _buttonGroup = new();
+
+ public event Action? TankEjectButtonPressed;
+ public event Action? ReleasePressureSliderChanged;
+ public event Action? ReleaseValveCloseButtonPressed;
+ public event Action? ReleaseValveOpenButtonPressed;
+
+ public GasCanisterWindow()
+ {
+ RobustXamlLoader.Load(this);
+
+ ReleaseValveCloseButton.Group = _buttonGroup;
+ ReleaseValveOpenButton.Group = _buttonGroup;
+
+ ReleaseValveCloseButton.OnPressed += _ => ReleaseValveCloseButtonPressed?.Invoke();
+ ReleaseValveOpenButton.OnPressed += _ => ReleaseValveOpenButtonPressed?.Invoke();
+
+ TankEjectButton.OnPressed += _ => TankEjectButtonPressed?.Invoke();
+ ReleasePressureSlider.OnValueChanged += r => ReleasePressureSliderChanged?.Invoke(r.Value);
+ }
+
+ public void SetCanisterLabel(string label)
+ {
+ Title = label;
+ }
+
+ public void SetCanisterPressure(float pressure)
+ {
+ CanisterPressureLabel.Text = Loc.GetString("comp-gas-canister-ui-pressure", ("pressure", Math.Round(pressure)));
+ }
+
+ public void SetPortStatus(bool status)
+ {
+ if (status)
+ {
+ PortStatusLabel.Text = Loc.GetString("comp-gas-canister-ui-port-connected");
+ }
+ else
+ {
+ PortStatusLabel.Text = Loc.GetString("comp-gas-canister-ui-port-disconnected");
+ }
+ }
+
+ public void SetTankLabel(string? label)
+ {
+ if (label == null)
+ {
+ TankEjectButton.Disabled = true;
+ TankLabelLabel.Text = Loc.GetString("comp-gas-canister-ui-holding-tank-label-empty");
+ return;
+ }
+
+ TankEjectButton.Disabled = false;
+ TankLabelLabel.Text = label;
+ }
+
+ public void SetTankPressure(float pressure)
+ {
+ TankPressureLabel.Text = Loc.GetString("comp-gas-canister-ui-pressure", ("pressure", Math.Round(pressure)));
+ }
+
+ public void SetReleasePressureRange(float min, float max)
+ {
+ ReleasePressureSlider.MinValue = min;
+ ReleasePressureSlider.MaxValue = max;
+ }
+
+ public void SetReleasePressure(float pressure)
+ {
+ if(!ReleasePressureSlider.Grabbed)
+ ReleasePressureSlider.SetValueWithoutEvent(pressure);
+ ReleasePressureLabel.Text = Loc.GetString("comp-gas-canister-ui-pressure", ("pressure", Math.Round(pressure)));
+ }
+
+ public void SetReleaseValve(bool valve)
+ {
+ if (valve)
+ ReleaseValveOpenButton.Pressed = true;
+ else
+ ReleaseValveCloseButton.Pressed = true;
+ }
+ }
+}
diff --git a/Content.Client/GameObjects/Components/Atmos/AtmosPlaqueVisualizer.cs b/Content.Client/Atmos/Visualizers/AtmosPlaqueVisualizer.cs
similarity index 89%
rename from Content.Client/GameObjects/Components/Atmos/AtmosPlaqueVisualizer.cs
rename to Content.Client/Atmos/Visualizers/AtmosPlaqueVisualizer.cs
index 3f33dda9e0..cd843e3266 100644
--- a/Content.Client/GameObjects/Components/Atmos/AtmosPlaqueVisualizer.cs
+++ b/Content.Client/Atmos/Visualizers/AtmosPlaqueVisualizer.cs
@@ -1,10 +1,10 @@
-using Content.Shared.GameObjects.Components.Atmos;
+using Content.Shared.Atmos.Visuals;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
-namespace Content.Client.GameObjects.Components.Atmos
+namespace Content.Client.Atmos.Visualizers
{
[UsedImplicitly]
public class AtmosPlaqueVisualizer : AppearanceVisualizer
diff --git a/Content.Client/GameObjects/Components/Atmos/FireVisualizer.cs b/Content.Client/Atmos/Visualizers/FireVisualizer.cs
similarity index 95%
rename from Content.Client/GameObjects/Components/Atmos/FireVisualizer.cs
rename to Content.Client/Atmos/Visualizers/FireVisualizer.cs
index 9a190686ba..ca0905f046 100644
--- a/Content.Client/GameObjects/Components/Atmos/FireVisualizer.cs
+++ b/Content.Client/Atmos/Visualizers/FireVisualizer.cs
@@ -1,10 +1,10 @@
-using Content.Shared.GameObjects.Components.Atmos;
+using Content.Shared.Atmos.Components;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
-namespace Content.Client.GameObjects.Components.Atmos
+namespace Content.Client.Atmos.Visualizers
{
[UsedImplicitly]
public class FireVisualizer : AppearanceVisualizer
diff --git a/Content.Client/GameObjects/Components/Atmos/GasAnalyzerVisualizer.cs b/Content.Client/Atmos/Visualizers/GasAnalyzerVisualizer.cs
similarity index 91%
rename from Content.Client/GameObjects/Components/Atmos/GasAnalyzerVisualizer.cs
rename to Content.Client/Atmos/Visualizers/GasAnalyzerVisualizer.cs
index 61e5e55426..5f0f382bfe 100644
--- a/Content.Client/GameObjects/Components/Atmos/GasAnalyzerVisualizer.cs
+++ b/Content.Client/Atmos/Visualizers/GasAnalyzerVisualizer.cs
@@ -1,9 +1,9 @@
-using Content.Shared.GameObjects.Components.Atmos;
+using Content.Shared.Atmos.Components;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
-namespace Content.Client.GameObjects.Components.Atmos
+namespace Content.Client.Atmos.Visualizers
{
[UsedImplicitly]
public class GasAnalyzerVisualizer : AppearanceVisualizer
diff --git a/Content.Client/Atmos/Visualizers/GasCanisterVisualizer.cs b/Content.Client/Atmos/Visualizers/GasCanisterVisualizer.cs
new file mode 100644
index 0000000000..916a8b8abf
--- /dev/null
+++ b/Content.Client/Atmos/Visualizers/GasCanisterVisualizer.cs
@@ -0,0 +1,54 @@
+using Content.Shared.Atmos.Piping.Binary.Components;
+using JetBrains.Annotations;
+using Robust.Client.GameObjects;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization.Manager.Attributes;
+
+namespace Content.Client.Atmos.Visualizers
+{
+ [UsedImplicitly]
+ public class GasCanisterVisualizer : AppearanceVisualizer
+ {
+ [DataField("pressureStates")]
+ private readonly string[] _statePressure = {"", "", "", ""};
+
+ [DataField("insertedTankState")]
+ private readonly string _insertedTankState = string.Empty;
+
+ public override void InitializeEntity(IEntity entity)
+ {
+ base.InitializeEntity(entity);
+
+ var sprite = entity.GetComponent();
+
+ sprite.LayerMapSet(Layers.PressureLight, sprite.AddLayerState(_statePressure[0]));
+ sprite.LayerSetShader(Layers.PressureLight, "unshaded");
+ sprite.LayerMapSet(Layers.TankInserted, sprite.AddLayerState(_insertedTankState));
+ sprite.LayerSetVisible(Layers.TankInserted, false);
+ }
+
+ public override void OnChangeData(AppearanceComponent component)
+ {
+ base.OnChangeData(component);
+
+ if (!component.Owner.TryGetComponent(out ISpriteComponent? sprite))
+ {
+ return;
+ }
+
+ // Update the canister lights
+ if (component.TryGetData(GasCanisterVisuals.PressureState, out int pressureState))
+ if ((pressureState >= 0) && (pressureState < _statePressure.Length))
+ sprite.LayerSetState(Layers.PressureLight, _statePressure[pressureState]);
+
+ if(component.TryGetData(GasCanisterVisuals.TankInserted, out bool inserted))
+ sprite.LayerSetVisible(Layers.TankInserted, inserted);
+ }
+
+ private enum Layers
+ {
+ PressureLight,
+ TankInserted,
+ }
+ }
+}
diff --git a/Content.Client/GameObjects/Components/Atmos/GasCanisterVisualizer.cs b/Content.Client/Atmos/Visualizers/GasPortableVisualizer.cs
similarity index 58%
rename from Content.Client/GameObjects/Components/Atmos/GasCanisterVisualizer.cs
rename to Content.Client/Atmos/Visualizers/GasPortableVisualizer.cs
index 2fc18cd9b9..07e62b5d59 100644
--- a/Content.Client/GameObjects/Components/Atmos/GasCanisterVisualizer.cs
+++ b/Content.Client/Atmos/Visualizers/GasPortableVisualizer.cs
@@ -1,18 +1,17 @@
-using Content.Shared.GameObjects.Components.Atmos;
+using Content.Shared.Atmos.Piping.Unary.Components;
+using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
-namespace Content.Client.GameObjects.Components.Atmos
+namespace Content.Client.Atmos.Visualizers
{
- public class GasCanisterVisualizer : AppearanceVisualizer
+ [UsedImplicitly]
+ public class GasPortableVisualizer : AppearanceVisualizer
{
[DataField("stateConnected")]
private string? _stateConnected;
- [DataField("pressureStates")]
- private string[] _statePressure = new string[] {"", "", "", ""};
-
public override void InitializeEntity(IEntity entity)
{
base.InitializeEntity(entity);
@@ -23,9 +22,6 @@ namespace Content.Client.GameObjects.Components.Atmos
{
sprite.LayerMapSet(Layers.ConnectedToPort, sprite.AddLayerState(_stateConnected));
sprite.LayerSetVisible(Layers.ConnectedToPort, false);
-
- sprite.LayerMapSet(Layers.PressureLight, sprite.AddLayerState(_stateConnected));
- sprite.LayerSetShader(Layers.PressureLight, "unshaded");
}
}
@@ -44,21 +40,15 @@ namespace Content.Client.GameObjects.Components.Atmos
}
// Update the visuals : Is the canister connected to a port or not
- if (component.TryGetData(GasCanisterVisuals.ConnectedState, out bool isConnected))
+ if (component.TryGetData(GasPortableVisuals.ConnectedState, out bool isConnected))
{
sprite.LayerSetVisible(Layers.ConnectedToPort, isConnected);
}
-
- // Update the visuals : Canister lights
- if (component.TryGetData(GasCanisterVisuals.PressureState, out int pressureState))
- if ((pressureState >= 0) && (pressureState < _statePressure.Length))
- sprite.LayerSetState(Layers.PressureLight, _statePressure[pressureState]);
}
- enum Layers
+ private enum Layers
{
ConnectedToPort,
- PressureLight
}
}
}
diff --git a/Content.Client/GameObjects/Components/Atmos/VaporVisualizer.cs b/Content.Client/Chemistry/Visualizers/VaporVisualizer.cs
similarity index 96%
rename from Content.Client/GameObjects/Components/Atmos/VaporVisualizer.cs
rename to Content.Client/Chemistry/Visualizers/VaporVisualizer.cs
index b7387ddbc0..e41a4c40e2 100644
--- a/Content.Client/GameObjects/Components/Atmos/VaporVisualizer.cs
+++ b/Content.Client/Chemistry/Visualizers/VaporVisualizer.cs
@@ -1,5 +1,4 @@
using System;
-using Content.Shared.GameObjects.Components;
using Content.Shared.Vapor;
using JetBrains.Annotations;
using Robust.Client.Animations;
@@ -8,7 +7,7 @@ using Robust.Shared.Maths;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
-namespace Content.Client.GameObjects.Components.Atmos
+namespace Content.Client.Chemistry.Visualizers
{
[UsedImplicitly]
public class VaporVisualizer : AppearanceVisualizer, ISerializationHooks
diff --git a/Content.Client/Commands/AtmosDebugCommands.cs b/Content.Client/Commands/AtmosDebugCommands.cs
index 90627f37bb..ba95e74287 100644
--- a/Content.Client/Commands/AtmosDebugCommands.cs
+++ b/Content.Client/Commands/AtmosDebugCommands.cs
@@ -1,7 +1,7 @@
using JetBrains.Annotations;
-using Content.Client.GameObjects.EntitySystems;
using Content.Shared.Atmos;
using System;
+using Content.Client.Atmos.EntitySystems;
using Robust.Shared.Console;
using Robust.Shared.GameObjects;
diff --git a/Content.Client/Commands/DebugCommands.cs b/Content.Client/Commands/DebugCommands.cs
index 091d6532f5..0d4eb5e048 100644
--- a/Content.Client/Commands/DebugCommands.cs
+++ b/Content.Client/Commands/DebugCommands.cs
@@ -1,12 +1,6 @@
-// ReSharper disable once RedundantUsingDirective
-// Used to warn the player in big red letters in debug mode
using System;
-using Content.Client.GameObjects.Components;
-using Content.Client.GameObjects.EntitySystems;
using Content.Client.Markers;
using Content.Client.Notifications.Managers;
-using Content.Shared.GameObjects.Components;
-using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.SubFloor;
using Robust.Client.GameObjects;
using Robust.Shared.Console;
diff --git a/Content.Client/Commands/GroupingContextMenuCommand.cs b/Content.Client/Commands/GroupingContextMenuCommand.cs
index 58d162a8ba..e306c7da11 100644
--- a/Content.Client/Commands/GroupingContextMenuCommand.cs
+++ b/Content.Client/Commands/GroupingContextMenuCommand.cs
@@ -1,5 +1,4 @@
#nullable enable
-using Content.Client.GameObjects.EntitySystems;
using Content.Shared;
using Content.Shared.CCVar;
using Robust.Shared.Configuration;
diff --git a/Content.Client/GameObjects/Components/ComputerBoundUserInterface.cs b/Content.Client/ComputerBoundUserInterface.cs
similarity index 100%
rename from Content.Client/GameObjects/Components/ComputerBoundUserInterface.cs
rename to Content.Client/ComputerBoundUserInterface.cs
diff --git a/Content.Client/Construction/ConstructionPlacementHijack.cs b/Content.Client/Construction/ConstructionPlacementHijack.cs
index 153b307672..93eaed99c1 100644
--- a/Content.Client/Construction/ConstructionPlacementHijack.cs
+++ b/Content.Client/Construction/ConstructionPlacementHijack.cs
@@ -1,5 +1,4 @@
using System.Collections.Generic;
-using Content.Client.GameObjects.EntitySystems;
using Content.Shared.Construction;
using Content.Shared.Construction.Prototypes;
using Robust.Client.Graphics;
diff --git a/Content.Client/Entry/IgnoredComponents.cs b/Content.Client/Entry/IgnoredComponents.cs
index 9ba634072a..9b19afe561 100644
--- a/Content.Client/Entry/IgnoredComponents.cs
+++ b/Content.Client/Entry/IgnoredComponents.cs
@@ -143,6 +143,16 @@ namespace Content.Client.Entry
"Barotrauma",
"GasSprayer",
"GasVapor",
+ "GasVentPump",
+ "GasPassiveVent",
+ "GasVentScrubber",
+ "GasOutletInjector",
+ "GasMiner",
+ "GasPressurePump",
+ "GasVolumePump",
+ "GasPassiveGate",
+ "GasValve",
+ "GasThermoMachine",
"Metabolism",
"AiFactionTag",
"PressureProtection",
@@ -154,7 +164,7 @@ namespace Content.Client.Entry
"VolumePump",
"PressureSiphon",
"PipeHeater",
- "PipeNetDevice",
+ "AtmosDevice",
"SignalReceiver",
"SignalSwitch",
"SignalTransmitter",
@@ -179,6 +189,10 @@ namespace Content.Client.Entry
"ComputerBoard",
"GasCanister",
"GasCanisterPort",
+ "GasPort",
+ "GasPortable",
+ "AtmosUnsafeUnanchor",
+ "GasMixer",
"Cleanable",
"Configuration",
"PlantHolder",
diff --git a/Content.Client/GameObjects/Components/Atmos/GasCanisterBoundUserInterface.cs b/Content.Client/GameObjects/Components/Atmos/GasCanisterBoundUserInterface.cs
deleted file mode 100644
index ef612c0342..0000000000
--- a/Content.Client/GameObjects/Components/Atmos/GasCanisterBoundUserInterface.cs
+++ /dev/null
@@ -1,118 +0,0 @@
-using Content.Shared.GameObjects.Components.Atmos;
-using JetBrains.Annotations;
-using Robust.Client.GameObjects;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Localization;
-
-namespace Content.Client.GameObjects.Components.Atmos
-{
- ///
- /// Initializes a and updates it when new server messages are received.
- ///
- [UsedImplicitly]
- public class GasCanisterBoundUserInterface : BoundUserInterface
- {
-
- private GasCanisterWindow? _window;
-
- public GasCanisterBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
- {
-
- }
-
-
- ///
- /// When a button is pressed, send a network message to the server
- ///
- /// Which button has been pressed, as an enum item
- private void ButtonPressed(UiButton button)
- {
- SendMessage(new UiButtonPressedMessage(button));
- }
-
-
- ///
- /// When the release pressure is changed
- ///
- /// The pressure value
- private void ReleasePressureButtonPressed(float value)
- {
- SendMessage(new ReleasePressureButtonPressedMessage(value));
- }
-
-
- protected override void Open()
- {
- base.Open();
-
- _window = new GasCanisterWindow();
- _window.Title = Loc.GetString("Gas Canister");
-
- _window.OpenCentered();
- _window.OnClose += Close;
-
- // Bind buttons OnPressed event
- foreach (ReleasePressureButton btn in _window.ReleasePressureButtons)
- {
- btn.OnPressed += _ => ReleasePressureButtonPressed(btn.PressureChange);
- }
-
- // Bind events
- _window.EditLabelBtn.OnPressed += _ => EditLabel();
- _window.ToggleValve.OnPressed += _ => ToggleValve();
- }
-
-
- ///
- /// Called when the edit label button is pressed
- ///
- private void EditLabel()
- {
- // Obligatory check because bool isn't nullable
- if (_window == null) return;
-
- if (_window.LabelInputEditable)
- {
- if (_window.LabelInput.Text != _window.OldLabel)
- SendMessage(new CanisterLabelChangedMessage(_window.LabelInput.Text));
-
- _window.LabelInputEditable = false;
- }
- else
- {
- _window.LabelInputEditable = true;
- _window.LabelInput.HasKeyboardFocus();
- }
- }
-
-
- private void ToggleValve()
- {
- SendMessage(new UiButtonPressedMessage(UiButton.ValveToggle));
- }
-
-
- ///
- /// Update the UI state based on server-sent info
- ///
- ///
- protected override void UpdateState(BoundUserInterfaceState state)
- {
- base.UpdateState(state);
-
- if (!(state is GasCanisterBoundUserInterfaceState cast))
- {
- return;
- }
-
- _window?.UpdateState(cast);
- }
-
- protected override void Dispose(bool disposing)
- {
- base.Dispose(disposing);
- if (!disposing) return;
- _window?.Dispose();
- }
- }
-}
diff --git a/Content.Client/GameObjects/Components/Atmos/GasCanisterWindow.cs b/Content.Client/GameObjects/Components/Atmos/GasCanisterWindow.cs
deleted file mode 100644
index c75d4d2d33..0000000000
--- a/Content.Client/GameObjects/Components/Atmos/GasCanisterWindow.cs
+++ /dev/null
@@ -1,167 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using Content.Shared.GameObjects.Components.Atmos;
-using Robust.Client.UserInterface.Controls;
-using Robust.Client.UserInterface.CustomControls;
-using Robust.Shared.Localization;
-using Robust.Shared.Maths;
-
-namespace Content.Client.GameObjects.Components.Atmos
-{
- ///
- /// Client-side UI used to control a
- ///
- public class GasCanisterWindow : SS14Window
- {
- private readonly Label _pressure;
- private readonly Label _releasePressure;
-
- public readonly CheckButton ToggleValve;
- public readonly LineEdit LabelInput;
- public readonly Button EditLabelBtn;
- public string OldLabel { get; set; } = "";
-
- public bool LabelInputEditable {
- get => LabelInput.Editable;
- set {
- LabelInput.Editable = value;
- EditLabelBtn.Text = value ? Loc.GetString("OK") : Loc.GetString("Edit");
- }
- }
-
- public List ReleasePressureButtons { get; private set; }
-
- public GasCanisterWindow()
- {
- SetSize = MinSize = (450, 200);
- HBoxContainer releasePressureButtons;
-
- Contents.AddChild(new VBoxContainer
- {
- Children =
- {
- new VBoxContainer
- {
- Children =
- {
- new HBoxContainer()
- {
- Children =
- {
- new Label(){ Text = Loc.GetString("Label: ") },
- (LabelInput = new LineEdit() { Text = Name ?? "", Editable = false,
- MinSize = new Vector2(200, 30)}),
- (EditLabelBtn = new Button()),
- }
- },
- new HBoxContainer
- {
- Children =
- {
- new Label {Text = Loc.GetString("Pressure: ")},
- (_pressure = new Label())
- }
- },
- new VBoxContainer()
- {
- Children =
- {
- new HBoxContainer()
- {
- Children =
- {
- new Label() {Text = Loc.GetString("Release pressure: ")},
- (_releasePressure = new Label())
- }
- },
- (releasePressureButtons = new HBoxContainer()
- {
- Children =
- {
- new ReleasePressureButton() {PressureChange = -50},
- new ReleasePressureButton() {PressureChange = -10},
- new ReleasePressureButton() {PressureChange = -1},
- new ReleasePressureButton() {PressureChange = -0.1f},
- new ReleasePressureButton() {PressureChange = 0.1f},
- new ReleasePressureButton() {PressureChange = 1},
- new ReleasePressureButton() {PressureChange = 10},
- new ReleasePressureButton() {PressureChange = 50}
- }
- })
- }
- },
- new HBoxContainer()
- {
- Children =
- {
- new Label { Text = Loc.GetString("Valve: ") },
- (ToggleValve = new CheckButton() { Text = Loc.GetString("Closed") })
- }
- }
- },
- }
- }
- });
-
- // Create the release pressure buttons list
- ReleasePressureButtons = new List();
- foreach (var control in releasePressureButtons.Children.ToList())
- {
- var btn = (ReleasePressureButton) control;
- ReleasePressureButtons.Add(btn);
- }
-
- // Reset the editable label
- LabelInputEditable = false;
- }
-
- ///
- /// Update the UI based on
- ///
- /// The state the UI should reflect
- public void UpdateState(GasCanisterBoundUserInterfaceState state)
- {
- _pressure.Text = Loc.GetString("{0}kPa", state.Volume);
- _releasePressure.Text = Loc.GetString("{0}kPa", state.ReleasePressure);
-
- // Update the canister label
- OldLabel = LabelInput.Text;
- LabelInput.Text = state.Label;
- Title = state.Label;
-
- // Reset the editable label
- LabelInputEditable = false;
-
- ToggleValve.Pressed = state.ValveOpened;
- if (ToggleValve.Pressed)
- {
- ToggleValve.Text = Loc.GetString("Open");
- }
- else
- {
- ToggleValve.Text = Loc.GetString("Closed");
- }
- }
- }
-
-
- ///
- /// Special button class which stores a numerical value and has it as a label
- ///
- public class ReleasePressureButton : Button
- {
- public float PressureChange
- {
- get { return _pressureChange; }
- set
- {
- _pressureChange = value;
- Text = (value >= 0) ? ("+" + value) : value.ToString();
- }
- }
-
- private float _pressureChange;
-
- public ReleasePressureButton() : base() {}
- }
-}
diff --git a/Content.Client/GameObjects/Components/Atmos/Piping/GasFilterVisualizer.cs b/Content.Client/GameObjects/Components/Atmos/Piping/GasFilterVisualizer.cs
deleted file mode 100644
index b6cee19c6c..0000000000
--- a/Content.Client/GameObjects/Components/Atmos/Piping/GasFilterVisualizer.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using Content.Shared.GameObjects.Components.Atmos;
-using JetBrains.Annotations;
-using Robust.Client.GameObjects;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Serialization.Manager.Attributes;
-
-namespace Content.Client.GameObjects.Components.Atmos.Piping
-{
- [UsedImplicitly]
- [DataDefinition]
- public class GasFilterVisualizer : AppearanceVisualizer
- {
- [DataField("filterEnabledState")] private string _filterEnabledState = "gasFilterOn";
-
- public override void InitializeEntity(IEntity entity)
- {
- base.InitializeEntity(entity);
-
- if (!entity.TryGetComponent(out var sprite)) return;
-
- sprite.LayerMapReserveBlank(Layer.FilterEnabled);
- var filterEnabledLayer = sprite.LayerMapGet(Layer.FilterEnabled);
- sprite.LayerSetState(filterEnabledLayer, _filterEnabledState);
- }
-
- public override void OnChangeData(AppearanceComponent component)
- {
- base.OnChangeData(component);
-
- if (!component.Owner.TryGetComponent(out var sprite)) return;
- if (!component.TryGetData(FilterVisuals.VisualState, out FilterVisualState filterVisualState)) return;
-
- var filterEnabledLayer = sprite.LayerMapGet(Layer.FilterEnabled);
- sprite.LayerSetVisible(filterEnabledLayer, filterVisualState.Enabled);
- }
-
- public enum Layer : byte
- {
- FilterEnabled,
- }
- }
-}
diff --git a/Content.Client/GameObjects/Components/Atmos/Piping/PipeVisualizer.cs b/Content.Client/GameObjects/Components/Atmos/Piping/PipeVisualizer.cs
deleted file mode 100644
index bc5879eb67..0000000000
--- a/Content.Client/GameObjects/Components/Atmos/Piping/PipeVisualizer.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-#nullable enable
-using System;
-using Content.Shared.GameObjects.Components.Atmos;
-using JetBrains.Annotations;
-using Robust.Client.GameObjects;
-using Robust.Client.Graphics;
-using Robust.Client.ResourceManagement;
-using Robust.Shared.GameObjects;
-using Robust.Shared.IoC;
-using Robust.Shared.Log;
-using Robust.Shared.Serialization;
-using Robust.Shared.Serialization.Manager.Attributes;
-
-namespace Content.Client.GameObjects.Components.Atmos.Piping
-{
- ///
- /// Sets the state of the sprite based on what shape of pipe it is.
- ///
- [UsedImplicitly]
- [DataDefinition]
- public class PipeVisualizer : AppearanceVisualizer, ISerializationHooks
- {
- [DataField("rsi")] private string _rsiString = "Constructible/Atmos/pipe.rsi";
- private RSI? _pipeRSI;
-
- void ISerializationHooks.AfterDeserialization()
- {
- var rsiPath = SharedSpriteComponent.TextureRoot / _rsiString;
- var resourceCache = IoCManager.Resolve();
-
- if (resourceCache.TryGetResource(rsiPath, out RSIResource? rsi))
- {
- _pipeRSI = rsi.RSI;
- }
- }
-
- public override void InitializeEntity(IEntity entity)
- {
- base.InitializeEntity(entity);
- if (!entity.TryGetComponent(out var sprite)) return;
- sprite.LayerMapReserveBlank(Layer.PipeBase);
- var pipeBaseLayer = sprite.LayerMapGet(Layer.PipeBase);
-
- if (_pipeRSI != null)
- sprite.LayerSetRSI(pipeBaseLayer, _pipeRSI);
-
- sprite.LayerSetVisible(pipeBaseLayer, true);
- }
-
- public override void OnChangeData(AppearanceComponent component)
- {
- base.OnChangeData(component);
- if (!component.Owner.TryGetComponent(out var sprite)) return;
- if (!component.TryGetData(PipeVisuals.VisualState, out PipeVisualState pipeVisualState)) return;
- var pipeBase = sprite.LayerMapGet(Layer.PipeBase);
- var pipeBaseStateId = GetPipeBaseStateId(pipeVisualState);
- sprite.LayerSetState(pipeBase, pipeBaseStateId);
- }
-
- private string GetPipeBaseStateId(PipeVisualState pipeVisualState)
- {
- var stateId = "pipe";
- stateId += pipeVisualState.PipeShape.ToString();
- return stateId;
- }
-
- private enum Layer : byte
- {
- PipeBase,
- }
- }
-}
diff --git a/Content.Client/GameObjects/Components/Atmos/Piping/PumpVisualizer.cs b/Content.Client/GameObjects/Components/Atmos/Piping/PumpVisualizer.cs
deleted file mode 100644
index e57ebf5ca4..0000000000
--- a/Content.Client/GameObjects/Components/Atmos/Piping/PumpVisualizer.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using Content.Shared.GameObjects.Components.Atmos;
-using JetBrains.Annotations;
-using Robust.Client.GameObjects;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Serialization.Manager.Attributes;
-
-namespace Content.Client.GameObjects.Components.Atmos.Piping
-{
- [UsedImplicitly]
- [DataDefinition]
- public class PumpVisualizer : AppearanceVisualizer
- {
- [DataField("pumpEnabledState")] private string _pumpEnabledState = "pumpPressureOn";
-
- public override void InitializeEntity(IEntity entity)
- {
- base.InitializeEntity(entity);
-
- if (!entity.TryGetComponent(out ISpriteComponent? sprite)) return;
-
- sprite.LayerMapReserveBlank(Layer.PumpEnabled);
- var pumpEnabledLayer = sprite.LayerMapGet(Layer.PumpEnabled);
- sprite.LayerSetState(pumpEnabledLayer, _pumpEnabledState);
- }
-
- public override void OnChangeData(AppearanceComponent component)
- {
- base.OnChangeData(component);
-
- if (!component.Owner.TryGetComponent(out ISpriteComponent? sprite)) return;
- if (!component.TryGetData(PumpVisuals.VisualState, out PumpVisualState pumpVisualState)) return;
-
- var pumpEnabledLayer = sprite.LayerMapGet(Layer.PumpEnabled);
- sprite.LayerSetVisible(pumpEnabledLayer, pumpVisualState.PumpEnabled);
- }
-
- public enum Layer : byte
- {
- PumpEnabled,
- }
- }
-}
diff --git a/Content.Client/GameObjects/Components/Atmos/Piping/SiphonVisualizer.cs b/Content.Client/GameObjects/Components/Atmos/Piping/SiphonVisualizer.cs
deleted file mode 100644
index 815fd6cee5..0000000000
--- a/Content.Client/GameObjects/Components/Atmos/Piping/SiphonVisualizer.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using Content.Shared.GameObjects.Components.Atmos;
-using JetBrains.Annotations;
-using Robust.Client.GameObjects;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Serialization.Manager.Attributes;
-
-namespace Content.Client.GameObjects.Components.Atmos.Piping
-{
- [UsedImplicitly]
- [DataDefinition]
- public class SiphonVisualizer : AppearanceVisualizer
- {
- [DataField("siphonOnState")] private string _siphonOnState = "scrubOn";
-
- public override void InitializeEntity(IEntity entity)
- {
- base.InitializeEntity(entity);
-
- if (!entity.TryGetComponent(out ISpriteComponent? sprite)) return;
-
- sprite.LayerMapReserveBlank(Layer.SiphonEnabled);
- var layer = sprite.LayerMapGet(Layer.SiphonEnabled);
- sprite.LayerSetState(layer, _siphonOnState);
- }
-
- public override void OnChangeData(AppearanceComponent component)
- {
- base.OnChangeData(component);
-
- if (!component.Owner.TryGetComponent(out ISpriteComponent? sprite)) return;
- if (!component.TryGetData(SiphonVisuals.VisualState, out SiphonVisualState siphonVisualState)) return;
-
- var layer = sprite.LayerMapGet(Layer.SiphonEnabled);
- sprite.LayerSetVisible(layer, siphonVisualState.SiphonEnabled);
- }
-
- private enum Layer : byte
- {
- SiphonEnabled,
- }
- }
-}
diff --git a/Content.Client/GameObjects/Components/Atmos/Piping/VentVisualizer.cs b/Content.Client/GameObjects/Components/Atmos/Piping/VentVisualizer.cs
deleted file mode 100644
index 8603544152..0000000000
--- a/Content.Client/GameObjects/Components/Atmos/Piping/VentVisualizer.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using Content.Shared.GameObjects.Components.Atmos;
-using JetBrains.Annotations;
-using Robust.Client.GameObjects;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Serialization.Manager.Attributes;
-
-namespace Content.Client.GameObjects.Components.Atmos.Piping
-{
- [UsedImplicitly]
- [DataDefinition]
- public class VentVisualizer : AppearanceVisualizer
- {
- [DataField("ventOnState")] private string _ventOnState = "ventOn";
-
- public override void InitializeEntity(IEntity entity)
- {
- base.InitializeEntity(entity);
-
- if (!entity.TryGetComponent(out ISpriteComponent? sprite)) return;
-
- sprite.LayerMapReserveBlank(Layer.VentEnabled);
- var layer = sprite.LayerMapGet(Layer.VentEnabled);
- sprite.LayerSetState(layer, _ventOnState);
- }
-
- public override void OnChangeData(AppearanceComponent component)
- {
- base.OnChangeData(component);
-
- if (!component.Owner.TryGetComponent(out ISpriteComponent? sprite)) return;
- if (!component.TryGetData(VentVisuals.VisualState, out VentVisualState ventVisualState)) return;
-
- var layer = sprite.LayerMapGet(Layer.VentEnabled);
- sprite.LayerSetVisible(layer, ventVisualState.VentEnabled);
- }
-
- private enum Layer : byte
- {
- VentEnabled,
- }
- }
-}
diff --git a/Content.Client/Ghost/GhostGui.cs b/Content.Client/Ghost/GhostGui.cs
index 8cac3d2e08..36e0ce9336 100644
--- a/Content.Client/Ghost/GhostGui.cs
+++ b/Content.Client/Ghost/GhostGui.cs
@@ -1,6 +1,5 @@
#nullable enable
using System.Collections.Generic;
-using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Ghost;
using Robust.Client.Console;
using Robust.Client.UserInterface;
diff --git a/Content.Client/GameObjects/Components/Power/SolarControlWindow.xaml b/Content.Client/Power/SolarControlWindow.xaml
similarity index 100%
rename from Content.Client/GameObjects/Components/Power/SolarControlWindow.xaml
rename to Content.Client/Power/SolarControlWindow.xaml
diff --git a/Content.Client/GameObjects/Components/Power/SolarControlWindow.xaml.cs b/Content.Client/Power/SolarControlWindow.xaml.cs
similarity index 100%
rename from Content.Client/GameObjects/Components/Power/SolarControlWindow.xaml.cs
rename to Content.Client/Power/SolarControlWindow.xaml.cs
diff --git a/Content.Client/Sandbox/SandboxManager.cs b/Content.Client/Sandbox/SandboxManager.cs
index 1ac730025f..f383f06d66 100644
--- a/Content.Client/Sandbox/SandboxManager.cs
+++ b/Content.Client/Sandbox/SandboxManager.cs
@@ -1,9 +1,6 @@
using System;
-using Content.Client.GameObjects.EntitySystems;
using Content.Client.HUD;
using Content.Client.Markers;
-using Content.Client.UserInterface;
-using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Input;
using Content.Shared.Sandbox;
using Content.Shared.SubFloor;
diff --git a/Content.Client/UserInterface/Atmos/GasTank/GasTankBoundUserInterface.cs b/Content.Client/UserInterface/Atmos/GasTank/GasTankBoundUserInterface.cs
index 7968075018..dafc988484 100644
--- a/Content.Client/UserInterface/Atmos/GasTank/GasTankBoundUserInterface.cs
+++ b/Content.Client/UserInterface/Atmos/GasTank/GasTankBoundUserInterface.cs
@@ -1,4 +1,4 @@
-using Content.Shared.GameObjects.Components.Atmos.GasTank;
+using Content.Shared.Atmos.Components;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Shared.GameObjects;
diff --git a/Content.Client/UserInterface/Atmos/GasTank/GasTankWindow.cs b/Content.Client/UserInterface/Atmos/GasTank/GasTankWindow.cs
index 0b7d436924..c762df0630 100644
--- a/Content.Client/UserInterface/Atmos/GasTank/GasTankWindow.cs
+++ b/Content.Client/UserInterface/Atmos/GasTank/GasTankWindow.cs
@@ -1,7 +1,7 @@
using Content.Client.Message;
using Content.Client.Resources;
using Content.Client.Stylesheets;
-using Content.Shared.GameObjects.Components.Atmos.GasTank;
+using Content.Shared.Atmos.Components;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
diff --git a/Content.IntegrationTests/Tests/Atmos/ConstantsTest.cs b/Content.IntegrationTests/Tests/Atmos/ConstantsTest.cs
index df4e7dcdb3..5f9a2146e9 100644
--- a/Content.IntegrationTests/Tests/Atmos/ConstantsTest.cs
+++ b/Content.IntegrationTests/Tests/Atmos/ConstantsTest.cs
@@ -1,7 +1,7 @@
using System;
using System.Linq;
using System.Threading.Tasks;
-using Content.Server.GameObjects.EntitySystems;
+using Content.Server.Atmos.EntitySystems;
using Content.Shared.Atmos;
using NUnit.Framework;
using Robust.Shared.GameObjects;
diff --git a/Content.IntegrationTests/Tests/ClickableTest.cs b/Content.IntegrationTests/Tests/ClickableTest.cs
index 542952537e..ed29ec9d5b 100644
--- a/Content.IntegrationTests/Tests/ClickableTest.cs
+++ b/Content.IntegrationTests/Tests/ClickableTest.cs
@@ -1,7 +1,6 @@
using System;
using System.Threading.Tasks;
using Content.Client.Clickable;
-using Content.Client.GameObjects.Components;
using NUnit.Framework;
using Robust.Server.GameObjects;
using Robust.Shared.GameObjects;
diff --git a/Content.IntegrationTests/Tests/Gravity/WeightlessStatusTests.cs b/Content.IntegrationTests/Tests/Gravity/WeightlessStatusTests.cs
index 7569427fb2..8557d4c21b 100644
--- a/Content.IntegrationTests/Tests/Gravity/WeightlessStatusTests.cs
+++ b/Content.IntegrationTests/Tests/Gravity/WeightlessStatusTests.cs
@@ -1,11 +1,9 @@
using System.Threading.Tasks;
-using Content.Server.GameObjects.EntitySystems;
using Content.Server.Gravity;
using Content.Server.Gravity.EntitySystems;
using Content.Shared.Acts;
using Content.Shared.Alert;
using Content.Shared.Coordinates;
-using Content.Shared.GameObjects.EntitySystems;
using NUnit.Framework;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
diff --git a/Content.IntegrationTests/Tests/Interaction/InRangeUnobstructed.cs b/Content.IntegrationTests/Tests/Interaction/InRangeUnobstructed.cs
index 7975038fa7..ec1dda6240 100644
--- a/Content.IntegrationTests/Tests/Interaction/InRangeUnobstructed.cs
+++ b/Content.IntegrationTests/Tests/Interaction/InRangeUnobstructed.cs
@@ -1,6 +1,5 @@
using System.Threading.Tasks;
using Content.Client.Interactable;
-using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Helpers;
using NUnit.Framework;
diff --git a/Content.IntegrationTests/Tests/Networking/SimplePredictReconcileTest.cs b/Content.IntegrationTests/Tests/Networking/SimplePredictReconcileTest.cs
index 0b30b9601e..5b918488bb 100644
--- a/Content.IntegrationTests/Tests/Networking/SimplePredictReconcileTest.cs
+++ b/Content.IntegrationTests/Tests/Networking/SimplePredictReconcileTest.cs
@@ -3,7 +3,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
-using Content.Shared.GameObjects;
using Content.Shared.NetIDs;
using NUnit.Framework;
using Robust.Client.GameObjects;
diff --git a/Content.Server/AI/Utility/Considerations/Containers/TargetAccessibleCon.cs b/Content.Server/AI/Utility/Considerations/Containers/TargetAccessibleCon.cs
index 473c436164..234a98c612 100644
--- a/Content.Server/AI/Utility/Considerations/Containers/TargetAccessibleCon.cs
+++ b/Content.Server/AI/Utility/Considerations/Containers/TargetAccessibleCon.cs
@@ -2,7 +2,6 @@ using Content.Server.AI.Pathfinding.Accessible;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States;
using Content.Server.Storage.Components;
-using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Interaction;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
diff --git a/Content.Server/Alert/Click/ResistFire.cs b/Content.Server/Alert/Click/ResistFire.cs
index 7eab315dab..d8d157fac8 100644
--- a/Content.Server/Alert/Click/ResistFire.cs
+++ b/Content.Server/Alert/Click/ResistFire.cs
@@ -1,4 +1,4 @@
-using Content.Server.GameObjects.Components.Atmos;
+using Content.Server.Atmos.Components;
using Content.Shared.Alert;
using JetBrains.Annotations;
using Robust.Shared.Serialization.Manager.Attributes;
diff --git a/Content.Server/Alert/Click/StopPulling.cs b/Content.Server/Alert/Click/StopPulling.cs
index 4fd9ecb4de..dd880abeff 100644
--- a/Content.Server/Alert/Click/StopPulling.cs
+++ b/Content.Server/Alert/Click/StopPulling.cs
@@ -1,5 +1,4 @@
using Content.Shared.Alert;
-using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Pulling;
using Content.Shared.Pulling.Components;
using JetBrains.Annotations;
diff --git a/Content.Server/Atmos/AtmosHelpers.cs b/Content.Server/Atmos/AtmosHelpers.cs
index c29f712b54..a89bc200c7 100644
--- a/Content.Server/Atmos/AtmosHelpers.cs
+++ b/Content.Server/Atmos/AtmosHelpers.cs
@@ -1,6 +1,6 @@
#nullable enable
using System.Diagnostics.CodeAnalysis;
-using Content.Server.GameObjects.EntitySystems;
+using Content.Server.Atmos.EntitySystems;
using Content.Shared.Atmos;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
diff --git a/Content.Server/GameObjects/Components/Atmos/AirtightComponent.cs b/Content.Server/Atmos/Components/AirtightComponent.cs
similarity index 78%
rename from Content.Server/GameObjects/Components/Atmos/AirtightComponent.cs
rename to Content.Server/Atmos/Components/AirtightComponent.cs
index d0633202b5..81699eec10 100644
--- a/Content.Server/GameObjects/Components/Atmos/AirtightComponent.cs
+++ b/Content.Server/Atmos/Components/AirtightComponent.cs
@@ -1,16 +1,15 @@
#nullable enable
-using Content.Server.GameObjects.EntitySystems;
+using Content.Server.Atmos.EntitySystems;
using Content.Shared.Atmos;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
-using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
using Robust.Shared.ViewVariables;
-namespace Content.Server.GameObjects.Components.Atmos
+namespace Content.Server.Atmos.Components
{
[RegisterComponent]
public class AirtightComponent : Component, IMapInit
@@ -96,6 +95,7 @@ namespace Content.Server.GameObjects.Components.Atmos
return;
_currentAirBlockedDirection = (int) Rotate((AtmosDirection)_initialAirBlockedDirection, ev.NewRotation);
+ UpdatePosition();
}
private AtmosDirection Rotate(AtmosDirection myDirection, Angle myAngle)
@@ -118,26 +118,18 @@ namespace Content.Server.GameObjects.Components.Atmos
return newAirBlockedDirs;
}
- ///
public void MapInit()
{
- if (Owner.Transform.Anchored)
- {
- var grid = _mapManager.GetGrid(Owner.Transform.GridID);
- _lastPosition = (Owner.Transform.GridID, grid.TileIndicesFor(Owner.Transform.Coordinates));
- }
-
UpdatePosition();
}
- ///
protected override void Shutdown()
{
base.Shutdown();
_airBlocked = false;
- UpdatePosition(_lastPosition.Item1, _lastPosition.Item2);
+ InvalidatePosition(_lastPosition.Item1, _lastPosition.Item2);
if (_fixVacuum)
{
@@ -145,31 +137,31 @@ namespace Content.Server.GameObjects.Components.Atmos
}
}
- public void OnTransformMove()
+ public void OnSnapGridMove(SnapGridPositionChangedEvent ev)
{
- UpdatePosition(_lastPosition.Item1, _lastPosition.Item2);
- UpdatePosition();
+ // Invalidate old position.
+ InvalidatePosition(ev.OldGrid, ev.OldPosition);
- if (Owner.Transform.Anchored)
- {
- var grid = _mapManager.GetGrid(Owner.Transform.GridID);
- _lastPosition = (Owner.Transform.GridID, grid.TileIndicesFor(Owner.Transform.Coordinates));
- }
+ // Update and invalidate new position.
+ _lastPosition = (ev.NewGrid, ev.Position);
+ InvalidatePosition(ev.NewGrid, ev.Position);
}
private void UpdatePosition()
{
- if (Owner.Transform.Anchored)
- {
- if (!Owner.Transform.GridID.IsValid())
- return;
- var grid = _mapManager.GetGrid(Owner.Transform.GridID);
- UpdatePosition(Owner.Transform.GridID, grid.TileIndicesFor(Owner.Transform.Coordinates));
- }
+ if (!Owner.Transform.Anchored || !Owner.Transform.GridID.IsValid())
+ return;
+
+ var grid = _mapManager.GetGrid(Owner.Transform.GridID);
+ _lastPosition = (Owner.Transform.GridID, grid.TileIndicesFor(Owner.Transform.Coordinates));
+ InvalidatePosition(_lastPosition.Item1, _lastPosition.Item2);
}
- private void UpdatePosition(GridId gridId, Vector2i pos)
+ private void InvalidatePosition(GridId gridId, Vector2i pos)
{
+ if (!gridId.IsValid())
+ return;
+
var gridAtmos = _atmosphereSystem.GetGridAtmosphere(gridId);
gridAtmos?.UpdateAdjacentBits(pos);
diff --git a/Content.Server/GameObjects/Components/Atmos/AtmosExposedComponent.cs b/Content.Server/Atmos/Components/AtmosExposedComponent.cs
similarity index 94%
rename from Content.Server/GameObjects/Components/Atmos/AtmosExposedComponent.cs
rename to Content.Server/Atmos/Components/AtmosExposedComponent.cs
index 3790ac173a..1ed395cae0 100644
--- a/Content.Server/GameObjects/Components/Atmos/AtmosExposedComponent.cs
+++ b/Content.Server/Atmos/Components/AtmosExposedComponent.cs
@@ -1,10 +1,9 @@
#nullable enable
-using Content.Server.Atmos;
using Content.Server.Temperature.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.ViewVariables;
-namespace Content.Server.GameObjects.Components.Atmos
+namespace Content.Server.Atmos.Components
{
///
/// Represents that entity can be exposed to Atmos
diff --git a/Content.Server/GameObjects/Components/AtmosPlaqueComponent.cs b/Content.Server/Atmos/Components/AtmosPlaqueComponent.cs
similarity index 97%
rename from Content.Server/GameObjects/Components/AtmosPlaqueComponent.cs
rename to Content.Server/Atmos/Components/AtmosPlaqueComponent.cs
index abbdef74ee..1cd6090528 100644
--- a/Content.Server/GameObjects/Components/AtmosPlaqueComponent.cs
+++ b/Content.Server/Atmos/Components/AtmosPlaqueComponent.cs
@@ -1,4 +1,4 @@
-using Content.Shared.GameObjects.Components.Atmos;
+using Content.Shared.Atmos.Visuals;
using Robust.Server.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
@@ -6,7 +6,7 @@ using Robust.Shared.Random;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
-namespace Content.Server.GameObjects.Components
+namespace Content.Server.Atmos.Components
{
[RegisterComponent]
public sealed class AtmosPlaqueComponent : Component, IMapInit
diff --git a/Content.Server/GameObjects/Components/Atmos/BarotraumaComponent.cs b/Content.Server/Atmos/Components/BarotraumaComponent.cs
similarity index 98%
rename from Content.Server/GameObjects/Components/Atmos/BarotraumaComponent.cs
rename to Content.Server/Atmos/Components/BarotraumaComponent.cs
index 1a8459f2c3..06b98a835f 100644
--- a/Content.Server/GameObjects/Components/Atmos/BarotraumaComponent.cs
+++ b/Content.Server/Atmos/Components/BarotraumaComponent.cs
@@ -8,7 +8,7 @@ using Content.Shared.Damage;
using Content.Shared.Damage.Components;
using Robust.Shared.GameObjects;
-namespace Content.Server.GameObjects.Components.Atmos
+namespace Content.Server.Atmos.Components
{
///
/// Barotrauma: injury because of changes in air pressure.
diff --git a/Content.Server/GameObjects/Components/BaseComputerUserInterfaceComponent.cs b/Content.Server/Atmos/Components/BaseComputerUserInterfaceComponent.cs
similarity index 99%
rename from Content.Server/GameObjects/Components/BaseComputerUserInterfaceComponent.cs
rename to Content.Server/Atmos/Components/BaseComputerUserInterfaceComponent.cs
index a9a1d2e509..baa9a1a0e6 100644
--- a/Content.Server/GameObjects/Components/BaseComputerUserInterfaceComponent.cs
+++ b/Content.Server/Atmos/Components/BaseComputerUserInterfaceComponent.cs
@@ -2,7 +2,6 @@ using Content.Server.Power.Components;
using Content.Server.UserInterface;
using Content.Shared.ActionBlocker;
using Content.Shared.Interaction;
-using Content.Shared.Interaction.Events;
using Content.Shared.Notification.Managers;
using Robust.Server.GameObjects;
using Robust.Shared.GameObjects;
diff --git a/Content.Server/GameObjects/Components/Atmos/BreathToolComponent.cs b/Content.Server/Atmos/Components/BreathToolComponent.cs
similarity index 97%
rename from Content.Server/GameObjects/Components/Atmos/BreathToolComponent.cs
rename to Content.Server/Atmos/Components/BreathToolComponent.cs
index 33c6610677..2e715cf5f2 100644
--- a/Content.Server/GameObjects/Components/Atmos/BreathToolComponent.cs
+++ b/Content.Server/Atmos/Components/BreathToolComponent.cs
@@ -4,7 +4,7 @@ using Content.Shared.Inventory;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
-namespace Content.Server.GameObjects.Components.Atmos
+namespace Content.Server.Atmos.Components
{
///
/// Used in internals as breath tool.
diff --git a/Content.Server/GameObjects/Components/Atmos/FirelockComponent.cs b/Content.Server/Atmos/Components/FirelockComponent.cs
similarity index 95%
rename from Content.Server/GameObjects/Components/Atmos/FirelockComponent.cs
rename to Content.Server/Atmos/Components/FirelockComponent.cs
index fafe18aaaa..d9d28293b8 100644
--- a/Content.Server/GameObjects/Components/Atmos/FirelockComponent.cs
+++ b/Content.Server/Atmos/Components/FirelockComponent.cs
@@ -1,16 +1,14 @@
#nullable enable
-using Robust.Shared.GameObjects;
-using Content.Server.Atmos;
+using Content.Server.Atmos.EntitySystems;
using Content.Server.Doors;
using Content.Server.Doors.Components;
-using Content.Server.GameObjects.EntitySystems;
using Content.Shared.Doors;
using Content.Shared.Interaction;
-using Content.Shared.Notification;
using Content.Shared.Notification.Managers;
+using Robust.Shared.GameObjects;
using Robust.Shared.Localization;
-namespace Content.Server.GameObjects.Components.Atmos
+namespace Content.Server.Atmos.Components
{
///
/// Companion component to ServerDoorComponent that handles firelock-specific behavior -- primarily prying, and not being openable on open-hand click.
diff --git a/Content.Server/GameObjects/Components/Atmos/FlammableComponent.cs b/Content.Server/Atmos/Components/FlammableComponent.cs
similarity index 97%
rename from Content.Server/GameObjects/Components/Atmos/FlammableComponent.cs
rename to Content.Server/Atmos/Components/FlammableComponent.cs
index e2aaee838b..4f4d0feb6d 100644
--- a/Content.Server/GameObjects/Components/Atmos/FlammableComponent.cs
+++ b/Content.Server/Atmos/Components/FlammableComponent.cs
@@ -2,17 +2,15 @@ using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Content.Server.Alert;
-using Content.Server.Atmos;
using Content.Server.Stunnable.Components;
using Content.Server.Temperature.Components;
using Content.Shared.ActionBlocker;
using Content.Shared.Alert;
using Content.Shared.Atmos;
+using Content.Shared.Atmos.Components;
using Content.Shared.Damage;
using Content.Shared.Damage.Components;
-using Content.Shared.GameObjects.Components.Atmos;
using Content.Shared.Interaction;
-using Content.Shared.Interaction.Events;
using Content.Shared.Notification.Managers;
using Content.Shared.Temperature;
using Robust.Server.GameObjects;
@@ -24,7 +22,7 @@ using Robust.Shared.Physics.Dynamics;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
-namespace Content.Server.GameObjects.Components.Atmos
+namespace Content.Server.Atmos.Components
{
[RegisterComponent]
public class FlammableComponent : SharedFlammableComponent, IStartCollide, IFireAct, IInteractUsing
diff --git a/Content.Server/GameObjects/Components/Atmos/GasAnalyzerComponent.cs b/Content.Server/Atmos/Components/GasAnalyzerComponent.cs
similarity index 97%
rename from Content.Server/GameObjects/Components/Atmos/GasAnalyzerComponent.cs
rename to Content.Server/Atmos/Components/GasAnalyzerComponent.cs
index fbb4790a35..cde2b8e747 100644
--- a/Content.Server/GameObjects/Components/Atmos/GasAnalyzerComponent.cs
+++ b/Content.Server/Atmos/Components/GasAnalyzerComponent.cs
@@ -1,16 +1,13 @@
#nullable enable
using System.Collections.Generic;
using System.Threading.Tasks;
-using Content.Server.GameObjects.EntitySystems;
+using Content.Server.Atmos.EntitySystems;
using Content.Server.Hands.Components;
using Content.Server.UserInterface;
using Content.Shared.Atmos;
+using Content.Shared.Atmos.Components;
using Content.Shared.DragDrop;
-using Content.Shared.GameObjects.Components;
-using Content.Shared.GameObjects.Components.Atmos;
-using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Interaction;
-using Content.Shared.Notification;
using Content.Shared.Notification.Managers;
using Robust.Server.GameObjects;
using Robust.Server.Player;
@@ -20,7 +17,7 @@ using Robust.Shared.Map;
using Robust.Shared.Players;
using Robust.Shared.ViewVariables;
-namespace Content.Server.GameObjects.Components.Atmos
+namespace Content.Server.Atmos.Components
{
[RegisterComponent]
public class GasAnalyzerComponent : SharedGasAnalyzerComponent, IAfterInteract, IDropped, IUse
diff --git a/Content.Server/GameObjects/Components/Atmos/GasMixtureHolderComponent.cs b/Content.Server/Atmos/Components/GasMixtureHolderComponent.cs
similarity index 68%
rename from Content.Server/GameObjects/Components/Atmos/GasMixtureHolderComponent.cs
rename to Content.Server/Atmos/Components/GasMixtureHolderComponent.cs
index 48c01afe58..3293839aa8 100644
--- a/Content.Server/GameObjects/Components/Atmos/GasMixtureHolderComponent.cs
+++ b/Content.Server/Atmos/Components/GasMixtureHolderComponent.cs
@@ -1,12 +1,9 @@
-using Content.Server.Atmos;
-using Content.Server.Interfaces;
+using Content.Server.Interfaces;
using Robust.Shared.GameObjects;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
-namespace Content.Server.GameObjects.Components.Atmos
+namespace Content.Server.Atmos.Components
{
[RegisterComponent]
public class GasMixtureHolderComponent : Component, IGasMixtureHolder
diff --git a/Content.Server/GameObjects/Components/Atmos/GasTankComponent.cs b/Content.Server/Atmos/Components/GasTankComponent.cs
similarity index 87%
rename from Content.Server/GameObjects/Components/Atmos/GasTankComponent.cs
rename to Content.Server/Atmos/Components/GasTankComponent.cs
index 92dcc44691..8779aec7d5 100644
--- a/Content.Server/GameObjects/Components/Atmos/GasTankComponent.cs
+++ b/Content.Server/Atmos/Components/GasTankComponent.cs
@@ -1,22 +1,22 @@
#nullable enable
#nullable disable warnings
using System;
-using Content.Server.Atmos;
using Content.Server.Body.Respiratory;
using Content.Server.Explosion;
+using Content.Server.GameObjects.Components.NodeContainer.Nodes;
using Content.Server.Interfaces;
+using Content.Server.NodeContainer;
using Content.Server.UserInterface;
using Content.Shared.ActionBlocker;
using Content.Shared.Actions;
using Content.Shared.Actions.Behaviors.Item;
using Content.Shared.Actions.Components;
using Content.Shared.Atmos;
+using Content.Shared.Atmos.Components;
using Content.Shared.Audio;
using Content.Shared.DragDrop;
using Content.Shared.Examine;
-using Content.Shared.GameObjects.Components.Atmos.GasTank;
using Content.Shared.Interaction;
-using Content.Shared.Interaction.Events;
using Content.Shared.Verbs;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
@@ -30,12 +30,14 @@ using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
-namespace Content.Server.GameObjects.Components.Atmos
+namespace Content.Server.Atmos.Components
{
[RegisterComponent]
[ComponentReference(typeof(IActivate))]
- public class GasTankComponent : SharedGasTankComponent, IExamine, IGasMixtureHolder, IUse, IDropped, IActivate
+ public class GasTankComponent : Component, IExamine, IGasMixtureHolder, IUse, IDropped, IActivate
{
+ public override string Name => "GasTank";
+
private const float MaxExplosionRange = 14f;
private const float DefaultOutputPressure = Atmospherics.OneAtmosphere;
@@ -45,7 +47,35 @@ namespace Content.Server.GameObjects.Components.Atmos
[ViewVariables] private BoundUserInterface? _userInterface;
- [DataField("air")] [ViewVariables] public GasMixture? Air { get; set; } = new();
+ [ViewVariables]
+ public GasMixture Air
+ {
+ // TODO ATMOS Kill it with fire.
+ get
+ {
+ if (!Owner.TryGetComponent(out NodeContainerComponent nodeContainer))
+ throw new InvalidOperationException("Can't get tank air without a node container!");
+
+ if (!nodeContainer.TryGetNode(TankName, out PipeNode? node))
+ throw new InvalidOperationException($"Node container doesn't have a pipenode called {TankName}!");
+
+ return node.Air;
+ }
+
+ set
+ {
+ // This will throw if the node container is not found.
+ var nodeContainer = Owner.GetComponent();
+
+ if (!nodeContainer.TryGetNode(TankName, out PipeNode? node))
+ throw new InvalidOperationException($"Node container doesn't have a pipenode called {TankName}!");
+
+ node.Air = value;
+ }
+ }
+
+ [DataField("air")] [ViewVariables]
+ public GasMixture InitialMixture { get; set; } = new();
///
/// Distributed pressure.
@@ -88,6 +118,12 @@ namespace Content.Server.GameObjects.Components.Atmos
[DataField("tankFragmentScale")]
public float TankFragmentScale { get; set; } = 10 * Atmospherics.OneAtmosphere;
+ ///
+ /// NodeContainer node.
+ ///
+ [DataField("tank")]
+ public string TankName { get; set; } = "tank";
+
public override void Initialize()
{
base.Initialize();
diff --git a/Content.Server/GameObjects/Components/Atmos/GridAtmosphereComponent.cs b/Content.Server/Atmos/Components/GridAtmosphereComponent.cs
similarity index 95%
rename from Content.Server/GameObjects/Components/Atmos/GridAtmosphereComponent.cs
rename to Content.Server/Atmos/Components/GridAtmosphereComponent.cs
index bf9a5a1d8f..082ce26ed4 100644
--- a/Content.Server/GameObjects/Components/Atmos/GridAtmosphereComponent.cs
+++ b/Content.Server/Atmos/Components/GridAtmosphereComponent.cs
@@ -5,10 +5,8 @@ using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
-using Content.Server.Atmos;
-using Content.Server.GameObjects.Components.Atmos.Piping;
-using Content.Server.GameObjects.EntitySystems;
-using Content.Server.GameObjects.EntitySystems.Atmos;
+using Content.Server.Atmos.EntitySystems;
+using Content.Server.Atmos.Piping.Components;
using Content.Server.NodeContainer.NodeGroups;
using Content.Shared.Atmos;
using Content.Shared.Maps;
@@ -24,7 +22,7 @@ using Robust.Shared.Timing;
using Robust.Shared.ViewVariables;
using Dependency = Robust.Shared.IoC.DependencyAttribute;
-namespace Content.Server.GameObjects.Components.Atmos
+namespace Content.Server.Atmos.Components
{
///
/// This is our SSAir equivalent.
@@ -36,6 +34,7 @@ namespace Content.Server.GameObjects.Components.Atmos
[Dependency] private IMapManager _mapManager = default!;
[Dependency] private ITileDefinitionManager _tileDefinitionManager = default!;
[Dependency] private IServerEntityManager _serverEntityManager = default!;
+ [Dependency] private IGameTiming _gameTiming = default!;
public GridTileLookupSystem GridTileLookupSystem { get; private set; } = default!;
internal GasTileOverlaySystem GasTileOverlaySystem { get; private set; } = default!;
@@ -55,6 +54,8 @@ namespace Content.Server.GameObjects.Components.Atmos
[ComponentDependency] private IMapGridComponent? _mapGridComponent;
+ public virtual bool Simulated => true;
+
[ViewVariables]
public int UpdateCounter { get; private set; } = 0;
@@ -128,10 +129,10 @@ namespace Content.Server.GameObjects.Components.Atmos
private double _pipeNetLastProcess;
[ViewVariables]
- private readonly HashSet _pipeNetDevices = new();
+ private readonly HashSet _atmosDevices = new();
[ViewVariables]
- private double _pipeNetDevicesLastProcess;
+ private double _atmosDevicesLastProcess;
[ViewVariables]
private Queue _currentRunTiles = new();
@@ -143,7 +144,7 @@ namespace Content.Server.GameObjects.Components.Atmos
private Queue _currentRunPipeNet = new();
[ViewVariables]
- private Queue _currentRunPipeNetDevice = new();
+ private Queue _currentRunAtmosDevices = new();
[ViewVariables]
private ProcessState _state = ProcessState.TileEqualize;
@@ -162,7 +163,7 @@ namespace Content.Server.GameObjects.Components.Atmos
Hotspots,
Superconductivity,
PipeNet,
- PipeNetDevices,
+ AtmosDevices,
}
///
@@ -455,14 +456,14 @@ namespace Content.Server.GameObjects.Components.Atmos
_pipeNets.Remove(pipeNet);
}
- public virtual void AddPipeNetDevice(PipeNetDeviceComponent pipeNetDevice)
+ public virtual void AddAtmosDevice(AtmosDeviceComponent atmosDevice)
{
- _pipeNetDevices.Add(pipeNetDevice);
+ _atmosDevices.Add(atmosDevice);
}
- public virtual void RemovePipeNetDevice(PipeNetDeviceComponent pipeNetDevice)
+ public virtual void RemoveAtmosDevice(AtmosDeviceComponent atmosDevice)
{
- _pipeNetDevices.Remove(pipeNetDevice);
+ _atmosDevices.Remove(atmosDevice);
}
///
@@ -634,10 +635,10 @@ namespace Content.Server.GameObjects.Components.Atmos
}
_paused = false;
- _state = ProcessState.PipeNetDevices;
+ _state = ProcessState.AtmosDevices;
break;
- case ProcessState.PipeNetDevices:
- if (!ProcessPipeNetDevices(_paused, maxProcessTime))
+ case ProcessState.AtmosDevices:
+ if (!ProcessAtmosDevices(_paused, maxProcessTime))
{
_paused = true;
return;
@@ -857,30 +858,33 @@ namespace Content.Server.GameObjects.Components.Atmos
return true;
}
- protected virtual bool ProcessPipeNetDevices(bool resumed = false, float lagCheck = 5f)
+ protected virtual bool ProcessAtmosDevices(bool resumed = false, float lagCheck = 5f)
{
_stopwatch.Restart();
if(!resumed)
- _currentRunPipeNetDevice = new Queue(_pipeNetDevices);
+ _currentRunAtmosDevices = new Queue(_atmosDevices);
+ var time = _gameTiming.CurTime;
+ var updateEvent = new AtmosDeviceUpdateEvent(this);
var number = 0;
- while (_currentRunPipeNetDevice.Count > 0)
+ while (_currentRunAtmosDevices.Count > 0)
{
- var device = _currentRunPipeNetDevice.Dequeue();
- device.Update();
+ var device = _currentRunAtmosDevices.Dequeue();
+ Owner.EntityManager.EventBus.RaiseLocalEvent(device.Owner.Uid, updateEvent, false);
+ device.LastProcess = time;
if (number++ < LagCheckIterations) continue;
number = 0;
// Process the rest next time.
if (_stopwatch.Elapsed.TotalMilliseconds >= lagCheck)
{
- _pipeNetDevicesLastProcess = _stopwatch.Elapsed.TotalMilliseconds;
+ _atmosDevicesLastProcess = _stopwatch.Elapsed.TotalMilliseconds;
return false;
}
}
- _pipeNetDevicesLastProcess = _stopwatch.Elapsed.TotalMilliseconds;
+ _atmosDevicesLastProcess = _stopwatch.Elapsed.TotalMilliseconds;
return true;
}
diff --git a/Content.Server/Atmos/IGridAtmosphereComponent.cs b/Content.Server/Atmos/Components/IGridAtmosphereComponent.cs
similarity index 94%
rename from Content.Server/Atmos/IGridAtmosphereComponent.cs
rename to Content.Server/Atmos/Components/IGridAtmosphereComponent.cs
index 8111cdb8c1..6e6735475e 100644
--- a/Content.Server/Atmos/IGridAtmosphereComponent.cs
+++ b/Content.Server/Atmos/Components/IGridAtmosphereComponent.cs
@@ -1,17 +1,21 @@
#nullable enable
using System.Collections.Generic;
-using Content.Server.GameObjects.Components.Atmos;
-using Content.Server.GameObjects.Components.Atmos.Piping;
+using Content.Server.Atmos.Piping.Components;
using Content.Server.NodeContainer.NodeGroups;
using Content.Shared.Atmos;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Maths;
-namespace Content.Server.Atmos
+namespace Content.Server.Atmos.Components
{
public interface IGridAtmosphereComponent : IComponent, IEnumerable
{
+ ///
+ /// Whether this atmosphere is simulated or not.
+ ///
+ bool Simulated { get; }
+
///
/// Number of times has been called.
///
@@ -173,8 +177,8 @@ namespace Content.Server.Atmos
void RemovePipeNet(IPipeNet pipeNet);
- void AddPipeNetDevice(PipeNetDeviceComponent pipeNetDevice);
+ void AddAtmosDevice(AtmosDeviceComponent atmosDevice);
- void RemovePipeNetDevice(PipeNetDeviceComponent pipeNetDevice);
+ void RemoveAtmosDevice(AtmosDeviceComponent atmosDevice);
}
}
diff --git a/Content.Server/GameObjects/Components/Atmos/MovedByPressureComponent.cs b/Content.Server/Atmos/Components/MovedByPressureComponent.cs
similarity index 98%
rename from Content.Server/GameObjects/Components/Atmos/MovedByPressureComponent.cs
rename to Content.Server/Atmos/Components/MovedByPressureComponent.cs
index 2169a2f1d5..3c7c2e7c09 100644
--- a/Content.Server/GameObjects/Components/Atmos/MovedByPressureComponent.cs
+++ b/Content.Server/Atmos/Components/MovedByPressureComponent.cs
@@ -13,7 +13,7 @@ using Robust.Shared.Random;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
-namespace Content.Server.GameObjects.Components.Atmos
+namespace Content.Server.Atmos.Components
{
[RegisterComponent]
public class MovedByPressureComponent : Component
diff --git a/Content.Server/GameObjects/Components/Atmos/PressureProtectionComponent.cs b/Content.Server/Atmos/Components/PressureProtectionComponent.cs
similarity index 83%
rename from Content.Server/GameObjects/Components/Atmos/PressureProtectionComponent.cs
rename to Content.Server/Atmos/Components/PressureProtectionComponent.cs
index 8b43e1ae01..9ee628e98a 100644
--- a/Content.Server/GameObjects/Components/Atmos/PressureProtectionComponent.cs
+++ b/Content.Server/Atmos/Components/PressureProtectionComponent.cs
@@ -1,11 +1,9 @@
using Content.Server.Pressure;
using Robust.Shared.GameObjects;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
-namespace Content.Server.GameObjects.Components.Atmos
+namespace Content.Server.Atmos.Components
{
[RegisterComponent]
public class PressureProtectionComponent : Component, IPressureProtection
diff --git a/Content.Server/GameObjects/Components/Atmos/SpaceGridAtmosphereComponent.cs b/Content.Server/Atmos/Components/SpaceGridAtmosphereComponent.cs
similarity index 92%
rename from Content.Server/GameObjects/Components/Atmos/SpaceGridAtmosphereComponent.cs
rename to Content.Server/Atmos/Components/SpaceGridAtmosphereComponent.cs
index 60a8f6ec95..fd1df0e654 100644
--- a/Content.Server/GameObjects/Components/Atmos/SpaceGridAtmosphereComponent.cs
+++ b/Content.Server/Atmos/Components/SpaceGridAtmosphereComponent.cs
@@ -1,12 +1,11 @@
#nullable enable
using System.Collections.Generic;
using System.Linq;
-using Content.Server.Atmos;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Maths;
-namespace Content.Server.GameObjects.Components.Atmos
+namespace Content.Server.Atmos.Components
{
[RegisterComponent]
[ComponentReference(typeof(IGridAtmosphereComponent))]
diff --git a/Content.Server/GameObjects/Components/Atmos/UnsimulatedGridAtmosphereComponent.cs b/Content.Server/Atmos/Components/UnsimulatedGridAtmosphereComponent.cs
similarity index 88%
rename from Content.Server/GameObjects/Components/Atmos/UnsimulatedGridAtmosphereComponent.cs
rename to Content.Server/Atmos/Components/UnsimulatedGridAtmosphereComponent.cs
index 09add70c15..c59ffa486c 100644
--- a/Content.Server/GameObjects/Components/Atmos/UnsimulatedGridAtmosphereComponent.cs
+++ b/Content.Server/Atmos/Components/UnsimulatedGridAtmosphereComponent.cs
@@ -1,13 +1,12 @@
#nullable enable
using System;
-using Content.Server.Atmos;
-using Content.Server.GameObjects.Components.Atmos.Piping;
+using Content.Server.Atmos.Piping.Components;
using Content.Server.NodeContainer.NodeGroups;
using Content.Shared.Atmos;
using Robust.Shared.GameObjects;
using Robust.Shared.Maths;
-namespace Content.Server.GameObjects.Components.Atmos
+namespace Content.Server.Atmos.Components
{
[RegisterComponent]
[ComponentReference(typeof(IGridAtmosphereComponent))]
@@ -17,6 +16,8 @@ namespace Content.Server.GameObjects.Components.Atmos
{
public override string Name => "UnsimulatedGridAtmosphere";
+ public override bool Simulated => false;
+
public override void PryTile(Vector2i indices) { }
public override void RepopulateTiles()
@@ -63,9 +64,9 @@ namespace Content.Server.GameObjects.Components.Atmos
public override void RemovePipeNet(IPipeNet pipeNet) { }
- public override void AddPipeNetDevice(PipeNetDeviceComponent pipeNetDevice) { }
+ public override void AddAtmosDevice(AtmosDeviceComponent atmosDevice) { }
- public override void RemovePipeNetDevice(PipeNetDeviceComponent pipeNetDevice) { }
+ public override void RemoveAtmosDevice(AtmosDeviceComponent atmosDevice) { }
public override void Update(float frameTime) { }
@@ -104,7 +105,7 @@ namespace Content.Server.GameObjects.Components.Atmos
return false;
}
- protected override bool ProcessPipeNetDevices(bool resumed = false, float lagCheck = 5f)
+ protected override bool ProcessAtmosDevices(bool resumed = false, float lagCheck = 5f)
{
return false;
}
diff --git a/Content.Server/Atmos/EntitySystems/AirtightSystem.cs b/Content.Server/Atmos/EntitySystems/AirtightSystem.cs
new file mode 100644
index 0000000000..6657bb9cc9
--- /dev/null
+++ b/Content.Server/Atmos/EntitySystems/AirtightSystem.cs
@@ -0,0 +1,26 @@
+using Content.Server.Atmos.Components;
+using JetBrains.Annotations;
+using Robust.Shared.GameObjects;
+
+namespace Content.Server.Atmos.EntitySystems
+{
+ [UsedImplicitly]
+ public class AirtightSystem : EntitySystem
+ {
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnAirtightPositionChanged);
+ SubscribeLocalEvent(OnAirtightRotated);
+ }
+
+ private void OnAirtightPositionChanged(EntityUid uid, AirtightComponent component, SnapGridPositionChangedEvent args)
+ {
+ component.OnSnapGridMove(args);
+ }
+
+ private void OnAirtightRotated(EntityUid uid, AirtightComponent airtight, RotateEvent ev)
+ {
+ airtight.RotateEvent(ev);
+ }
+ }
+}
diff --git a/Content.Server/GameObjects/EntitySystems/Atmos/AtmosDebugOverlaySystem.cs b/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs
similarity index 96%
rename from Content.Server/GameObjects/EntitySystems/Atmos/AtmosDebugOverlaySystem.cs
rename to Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs
index e5dcd19ed1..d7e66d5045 100644
--- a/Content.Server/GameObjects/EntitySystems/Atmos/AtmosDebugOverlaySystem.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs
@@ -1,11 +1,9 @@
#nullable enable
using System.Collections.Generic;
-using Content.Server.GameObjects.Components.Atmos;
-using Content.Server.Atmos;
-using Content.Shared;
+using Content.Server.Atmos.Components;
using Content.Shared.Atmos;
+using Content.Shared.Atmos.EntitySystems;
using Content.Shared.CCVar;
-using Content.Shared.GameObjects.EntitySystems.Atmos;
using JetBrains.Annotations;
using Robust.Server.Player;
using Robust.Shared.Configuration;
@@ -15,7 +13,7 @@ using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
-namespace Content.Server.GameObjects.EntitySystems.Atmos
+namespace Content.Server.Atmos.EntitySystems
{
[UsedImplicitly]
public sealed class AtmosDebugOverlaySystem : SharedAtmosDebugOverlaySystem
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs
new file mode 100644
index 0000000000..2c8e0de6ac
--- /dev/null
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs
@@ -0,0 +1,24 @@
+using Content.Shared.CCVar;
+
+namespace Content.Server.Atmos.EntitySystems
+{
+ public partial class AtmosphereSystem
+ {
+ public bool SpaceWind { get; private set; }
+ public bool MonstermosEqualization { get; private set; }
+ public bool Superconduction { get; private set; }
+ public bool ExcitedGroupsSpaceIsAllConsuming { get; private set; }
+ public float AtmosMaxProcessTime { get; private set; }
+ public float AtmosTickRate { get; private set; }
+
+ private void InitializeCVars()
+ {
+ _cfg.OnValueChanged(CCVars.SpaceWind, value => SpaceWind = value, true);
+ _cfg.OnValueChanged(CCVars.MonstermosEqualization, value => MonstermosEqualization = value, true);
+ _cfg.OnValueChanged(CCVars.Superconduction, value => Superconduction = value, true);
+ _cfg.OnValueChanged(CCVars.AtmosMaxProcessTime, value => AtmosMaxProcessTime = value, true);
+ _cfg.OnValueChanged(CCVars.AtmosTickRate, value => AtmosTickRate = value, true);
+ _cfg.OnValueChanged(CCVars.ExcitedGroupsSpaceIsAllConsuming, value => ExcitedGroupsSpaceIsAllConsuming = value, true);
+ }
+ }
+}
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs
new file mode 100644
index 0000000000..282d3f97be
--- /dev/null
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Content.Server.Atmos.Reactions;
+using Content.Shared.Atmos;
+using Robust.Shared.Maths;
+
+namespace Content.Server.Atmos.EntitySystems
+{
+ public partial class AtmosphereSystem
+ {
+ private GasReactionPrototype[] _gasReactions = Array.Empty();
+ private float[] _gasSpecificHeats = new float[Atmospherics.TotalNumberOfGases];
+
+ ///
+ /// List of gas reactions ordered by priority.
+ ///
+ public IEnumerable GasReactions => _gasReactions!;
+ public float[] GasSpecificHeats => _gasSpecificHeats;
+
+ private void InitializeGases()
+ {
+ _gasReactions = _protoMan.EnumeratePrototypes().ToArray();
+ Array.Sort(_gasReactions, (a, b) => b.Priority.CompareTo(a.Priority));
+
+ Array.Resize(ref _gasSpecificHeats, MathHelper.NextMultipleOf(Atmospherics.TotalNumberOfGases, 4));
+
+ for (var i = 0; i < GasPrototypes.Length; i++)
+ {
+ _gasSpecificHeats[i] = GasPrototypes[i].SpecificHeat;
+ }
+ }
+ }
+}
diff --git a/Content.Server/GameObjects/EntitySystems/AtmosphereSystem.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs
similarity index 51%
rename from Content.Server/GameObjects/EntitySystems/AtmosphereSystem.cs
rename to Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs
index d71f75d8cc..cb0f5d3234 100644
--- a/Content.Server/GameObjects/EntitySystems/AtmosphereSystem.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs
@@ -1,14 +1,7 @@
-#nullable enable
using System;
-using System.Collections.Generic;
-using System.Linq;
-using Content.Server.Atmos;
-using Content.Server.Atmos.Reactions;
-using Content.Server.GameObjects.Components.Atmos;
-using Content.Shared;
-using Content.Shared.Atmos;
-using Content.Shared.CCVar;
-using Content.Shared.GameObjects.EntitySystems.Atmos;
+using System.Diagnostics.CodeAnalysis;
+using Content.Server.Atmos.Components;
+using Content.Shared.Atmos.EntitySystems;
using Content.Shared.Maps;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
@@ -16,31 +9,23 @@ using Robust.Shared.Configuration;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
-using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
-namespace Content.Server.GameObjects.EntitySystems
+namespace Content.Server.Atmos.EntitySystems
{
[UsedImplicitly]
- public class AtmosphereSystem : SharedAtmosphereSystem
+ public partial class AtmosphereSystem : SharedAtmosphereSystem
{
[Dependency] private readonly IPrototypeManager _protoMan = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IPauseManager _pauseManager = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
- private GasReactionPrototype[] _gasReactions = Array.Empty();
-
private GridTileLookupSystem? _gridTileLookup = null;
- ///
- /// List of gas reactions ordered by priority.
- ///
- public IEnumerable GasReactions => _gasReactions!;
-
- private float[] _gasSpecificHeats = new float[Atmospherics.TotalNumberOfGases];
- public float[] GasSpecificHeats => _gasSpecificHeats;
+ private const float ExposedUpdateDelay = 1f;
+ private float _exposedTimer = 0f;
public GridTileLookupSystem GridTileLookupSystem => _gridTileLookup ??= Get();
@@ -48,71 +33,16 @@ namespace Content.Server.GameObjects.EntitySystems
{
base.Initialize();
- _gasReactions = _protoMan.EnumeratePrototypes().ToArray();
- Array.Sort(_gasReactions, (a, b) => b.Priority.CompareTo(a.Priority));
+ InitializeGases();
+ InitializeCVars();
+ #region Events
+
+ // Map events.
_mapManager.MapCreated += OnMapCreated;
_mapManager.TileChanged += OnTileChanged;
- Array.Resize(ref _gasSpecificHeats, MathHelper.NextMultipleOf(Atmospherics.TotalNumberOfGases, 4));
-
- for (var i = 0; i < GasPrototypes.Length; i++)
- {
- _gasSpecificHeats[i] = GasPrototypes[i].SpecificHeat;
- }
-
- // Required for airtight components.
- SubscribeLocalEvent(RotateEvent);
- SubscribeLocalEvent(HandleSnapGridMove);
-
- _cfg.OnValueChanged(CCVars.SpaceWind, OnSpaceWindChanged, true);
- _cfg.OnValueChanged(CCVars.MonstermosEqualization, OnMonstermosEqualizationChanged, true);
- _cfg.OnValueChanged(CCVars.Superconduction, OnSuperconductionChanged, true);
- _cfg.OnValueChanged(CCVars.AtmosMaxProcessTime, OnAtmosMaxProcessTimeChanged, true);
- _cfg.OnValueChanged(CCVars.AtmosTickRate, OnAtmosTickRateChanged, true);
- _cfg.OnValueChanged(CCVars.ExcitedGroupsSpaceIsAllConsuming, OnExcitedGroupsSpaceIsAllConsumingChanged, true);
- }
-
- private static void HandleSnapGridMove(EntityUid uid, AirtightComponent component, SnapGridPositionChangedEvent args)
- {
- component.OnTransformMove();
- }
-
- public bool SpaceWind { get; private set; }
- public bool MonstermosEqualization { get; private set; }
- public bool Superconduction { get; private set; }
- public bool ExcitedGroupsSpaceIsAllConsuming { get; private set; }
- public float AtmosMaxProcessTime { get; private set; }
- public float AtmosTickRate { get; private set; }
-
- private void OnExcitedGroupsSpaceIsAllConsumingChanged(bool obj)
- {
- ExcitedGroupsSpaceIsAllConsuming = obj;
- }
-
- private void OnAtmosTickRateChanged(float obj)
- {
- AtmosTickRate = obj;
- }
-
- private void OnAtmosMaxProcessTimeChanged(float obj)
- {
- AtmosMaxProcessTime = obj;
- }
-
- private void OnMonstermosEqualizationChanged(bool obj)
- {
- MonstermosEqualization = obj;
- }
-
- private void OnSuperconductionChanged(bool obj)
- {
- Superconduction = obj;
- }
-
- private void OnSpaceWindChanged(bool obj)
- {
- SpaceWind = obj;
+ #endregion
}
public override void Shutdown()
@@ -120,16 +50,35 @@ namespace Content.Server.GameObjects.EntitySystems
base.Shutdown();
_mapManager.MapCreated -= OnMapCreated;
+ _mapManager.TileChanged -= OnTileChanged;
}
- private void RotateEvent(RotateEvent ev)
+ private void OnTileChanged(object? sender, TileChangedEventArgs eventArgs)
{
- if (ev.Sender.TryGetComponent(out AirtightComponent? airtight))
+ // When a tile changes, we want to update it only if it's gone from
+ // space -> not space or vice versa. So if the old tile is the
+ // same as the new tile in terms of space-ness, ignore the change
+
+ if (eventArgs.NewTile.IsSpace() == eventArgs.OldTile.IsSpace())
{
- airtight.RotateEvent(ev);
+ return;
}
+
+ GetGridAtmosphere(eventArgs.NewTile.GridIndex)?.Invalidate(eventArgs.NewTile.GridIndices);
}
+ private void OnMapCreated(object? sender, MapEventArgs e)
+ {
+ if (e.Map == MapId.Nullspace)
+ return;
+
+ var map = _mapManager.GetMapEntity(e.Map);
+
+ if (!map.HasComponent())
+ map.AddComponent();
+ }
+
+ #region Helper Methods
public IGridAtmosphereComponent? GetGridAtmosphere(GridId gridId)
{
if (!gridId.IsValid())
@@ -165,41 +114,61 @@ namespace Content.Server.GameObjects.EntitySystems
return _mapManager.GetMapEntity(coordinates.MapId).GetComponent();
}
+ ///
+ /// Unlike , this doesn't return space grid when not found.
+ ///
+ public bool TryGetSimulatedGridAtmosphere(MapCoordinates coordinates, [NotNullWhen(true)] out IGridAtmosphereComponent? atmosphere)
+ {
+ if (coordinates.MapId == MapId.Nullspace)
+ {
+ atmosphere = null;
+ return false;
+ }
+
+ if (_mapManager.TryFindGridAt(coordinates, out var mapGrid)
+ && ComponentManager.TryGetComponent(mapGrid.GridEntityId, out IGridAtmosphereComponent? atmosGrid)
+ && atmosGrid.Simulated)
+ {
+ atmosphere = atmosGrid;
+ return true;
+ }
+
+ if (_mapManager.GetMapEntity(coordinates.MapId).TryGetComponent(out IGridAtmosphereComponent? atmosMap)
+ && atmosMap.Simulated)
+ {
+ atmosphere = atmosMap;
+ return true;
+ }
+
+ atmosphere = null;
+ return false;
+ }
+ #endregion
+
public override void Update(float frameTime)
{
base.Update(frameTime);
+ _exposedTimer += frameTime;
+
foreach (var (mapGridComponent, gridAtmosphereComponent) in EntityManager.ComponentManager.EntityQuery(true))
{
if (_pauseManager.IsGridPaused(mapGridComponent.GridIndex)) continue;
gridAtmosphereComponent.Update(frameTime);
}
- }
- private void OnTileChanged(object? sender, TileChangedEventArgs eventArgs)
- {
- // When a tile changes, we want to update it only if it's gone from
- // space -> not space or vice versa. So if the old tile is the
- // same as the new tile in terms of space-ness, ignore the change
-
- if (eventArgs.NewTile.IsSpace() == eventArgs.OldTile.IsSpace())
+ if (_exposedTimer >= ExposedUpdateDelay)
{
- return;
+ foreach (var exposed in EntityManager.ComponentManager.EntityQuery(true))
+ {
+ var tile = exposed.Owner.Transform.Coordinates.GetTileAtmosphere();
+ if (tile == null) continue;
+ exposed.Update(tile, _exposedTimer);
+ }
+
+ _exposedTimer = 0;
}
-
- GetGridAtmosphere(eventArgs.NewTile.GridPosition(_mapManager))?.Invalidate(eventArgs.NewTile.GridIndices);
- }
-
- private void OnMapCreated(object? sender, MapEventArgs e)
- {
- if (e.Map == MapId.Nullspace)
- return;
-
- var map = _mapManager.GetMapEntity(e.Map);
-
- if (!map.HasComponent())
- map.AddComponent();
}
}
}
diff --git a/Content.Server/GameObjects/EntitySystems/ComputerUIActivatorSystem.cs b/Content.Server/Atmos/EntitySystems/ComputerUIActivatorSystem.cs
similarity index 82%
rename from Content.Server/GameObjects/EntitySystems/ComputerUIActivatorSystem.cs
rename to Content.Server/Atmos/EntitySystems/ComputerUIActivatorSystem.cs
index f0689cfcbf..65b800d65d 100644
--- a/Content.Server/GameObjects/EntitySystems/ComputerUIActivatorSystem.cs
+++ b/Content.Server/Atmos/EntitySystems/ComputerUIActivatorSystem.cs
@@ -1,11 +1,6 @@
-using System.Collections.Generic;
-using System.Linq;
using Content.Shared.Interaction;
using Content.Server.GameObjects.Components;
-using Content.Shared.GameTicking;
-using Robust.Server.GameObjects;
using Robust.Shared.GameObjects;
-using Robust.Shared.Maths;
using JetBrains.Annotations;
namespace Content.Server.GameObjects.EntitySystems
diff --git a/Content.Server/GameObjects/EntitySystems/GasAnalyzerSystem.cs b/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs
similarity index 78%
rename from Content.Server/GameObjects/EntitySystems/GasAnalyzerSystem.cs
rename to Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs
index e82322b8e7..7842816569 100644
--- a/Content.Server/GameObjects/EntitySystems/GasAnalyzerSystem.cs
+++ b/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs
@@ -1,8 +1,8 @@
-using Content.Server.GameObjects.Components.Atmos;
+using Content.Server.Atmos.Components;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
-namespace Content.Server.GameObjects.EntitySystems
+namespace Content.Server.Atmos.EntitySystems
{
[UsedImplicitly]
public class GasAnalyzerSystem : EntitySystem
diff --git a/Content.Server/GameObjects/EntitySystems/GasTankSystem.cs b/Content.Server/Atmos/EntitySystems/GasTankSystem.cs
similarity index 85%
rename from Content.Server/GameObjects/EntitySystems/GasTankSystem.cs
rename to Content.Server/Atmos/EntitySystems/GasTankSystem.cs
index 0633e3e632..c9a6fd9d62 100644
--- a/Content.Server/GameObjects/EntitySystems/GasTankSystem.cs
+++ b/Content.Server/Atmos/EntitySystems/GasTankSystem.cs
@@ -1,8 +1,8 @@
-using Content.Server.GameObjects.Components.Atmos;
+using Content.Server.Atmos.Components;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
-namespace Content.Server.GameObjects.EntitySystems
+namespace Content.Server.Atmos.EntitySystems
{
[UsedImplicitly]
public class GasTankSystem : EntitySystem
diff --git a/Content.Server/GameObjects/EntitySystems/Atmos/GasTileOverlaySystem.cs b/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs
similarity index 99%
rename from Content.Server/GameObjects/EntitySystems/Atmos/GasTileOverlaySystem.cs
rename to Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs
index 01b5d67c9a..1fdcf87bde 100644
--- a/Content.Server/GameObjects/EntitySystems/Atmos/GasTileOverlaySystem.cs
+++ b/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs
@@ -3,11 +3,10 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
-using Content.Server.GameObjects.Components.Atmos;
-using Content.Shared;
+using Content.Server.Atmos.Components;
using Content.Shared.Atmos;
+using Content.Shared.Atmos.EntitySystems;
using Content.Shared.CCVar;
-using Content.Shared.GameObjects.EntitySystems.Atmos;
using Content.Shared.GameTicking;
using JetBrains.Annotations;
using Robust.Server.Player;
@@ -15,14 +14,14 @@ using Robust.Shared;
using Robust.Shared.Configuration;
using Robust.Shared.Enums;
using Robust.Shared.GameObjects;
-// ReSharper disable once RedundantUsingDirective
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
+// ReSharper disable once RedundantUsingDirective
using Dependency = Robust.Shared.IoC.DependencyAttribute;
-namespace Content.Server.GameObjects.EntitySystems.Atmos
+namespace Content.Server.Atmos.EntitySystems
{
[UsedImplicitly]
internal sealed class GasTileOverlaySystem : SharedGasTileOverlaySystem, IResettingEntitySystem
diff --git a/Content.Server/Atmos/ExcitedGroup.cs b/Content.Server/Atmos/ExcitedGroup.cs
index a03e61de11..c32202db52 100644
--- a/Content.Server/Atmos/ExcitedGroup.cs
+++ b/Content.Server/Atmos/ExcitedGroup.cs
@@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
-using Content.Server.GameObjects.Components.Atmos;
+using Content.Server.Atmos.Components;
using Content.Shared.Atmos;
using Robust.Shared.ViewVariables;
diff --git a/Content.Server/Atmos/GasMixture.cs b/Content.Server/Atmos/GasMixture.cs
index 66ccde9db1..e8216f176d 100644
--- a/Content.Server/Atmos/GasMixture.cs
+++ b/Content.Server/Atmos/GasMixture.cs
@@ -3,8 +3,8 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
+using Content.Server.Atmos.EntitySystems;
using Content.Server.Atmos.Reactions;
-using Content.Server.GameObjects.EntitySystems;
using Content.Server.Interfaces;
using Content.Shared.Atmos;
using Robust.Shared.GameObjects;
@@ -154,8 +154,7 @@ namespace Content.Server.Atmos
var combinedHeatCapacity = HeatCapacity + giver.HeatCapacity;
if (combinedHeatCapacity > 0f)
{
- Temperature =
- (giver.Temperature * giver.HeatCapacity + Temperature * HeatCapacity) / combinedHeatCapacity;
+ Temperature = (giver.Temperature * giver.HeatCapacity + Temperature * HeatCapacity) / combinedHeatCapacity;
}
}
@@ -600,5 +599,18 @@ namespace Content.Server.Atmos
};
return newMixture;
}
+
+ public void ScrubInto(GasMixture destination, IReadOnlyCollection filterGases)
+ {
+ var buffer = new GasMixture(Volume){Temperature = Temperature};
+
+ foreach (var gas in filterGases)
+ {
+ buffer.AdjustMoles(gas, GetMoles(gas));
+ SetMoles(gas, 0f);
+ }
+
+ destination.Merge(buffer);
+ }
}
}
diff --git a/Content.Server/Atmos/Piping/Binary/Components/GasCanisterComponent.cs b/Content.Server/Atmos/Piping/Binary/Components/GasCanisterComponent.cs
new file mode 100644
index 0000000000..450dfd321a
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Binary/Components/GasCanisterComponent.cs
@@ -0,0 +1,52 @@
+using Content.Shared.Atmos;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization.Manager.Attributes;
+using Robust.Shared.ViewVariables;
+
+namespace Content.Server.Atmos.Piping.Binary.Components
+{
+ [RegisterComponent]
+ public class GasCanisterComponent : Component
+ {
+ public override string Name => "GasCanister";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("port")]
+ public string PortName { get; set; } = "port";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("tank")]
+ public string TankName { get; set; } = "tank";
+
+ ///
+ /// Container name for the gas tank holder.
+ ///
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("container")]
+ public string ContainerName { get; set; } = "GasCanisterTankHolder";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("gasMixture")]
+ public GasMixture InitialMixture { get; } = new();
+
+ ///
+ /// Stores the last pressure the tank had, for appearance-updating purposes.
+ ///
+ [ViewVariables]
+ public float LastPressure { get; set; } = 0f;
+
+ ///
+ /// Minimum release pressure possible for the release valve.
+ ///
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("minReleasePressure")]
+ public float MinReleasePressure { get; set; } = Atmospherics.OneAtmosphere / 10;
+
+ ///
+ /// Maximum release pressure possible for the release valve.
+ ///
+ [ViewVariables(VVAccess.ReadOnly)]
+ [DataField("maxReleasePressure")]
+ public float MaxReleasePressure { get; set; } = Atmospherics.OneAtmosphere * 10;
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Binary/Components/GasPassiveGateComponent.cs b/Content.Server/Atmos/Piping/Binary/Components/GasPassiveGateComponent.cs
new file mode 100644
index 0000000000..93366c67c5
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Binary/Components/GasPassiveGateComponent.cs
@@ -0,0 +1,35 @@
+using Content.Shared.Atmos;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization.Manager.Attributes;
+using Robust.Shared.ViewVariables;
+
+namespace Content.Server.Atmos.Piping.Binary.Components
+{
+ [RegisterComponent]
+ public class GasPassiveGateComponent : Component
+ {
+ public override string Name => "GasPassiveGate";
+
+ [DataField("enabled")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public bool Enabled { get; set; } = true;
+
+ ///
+ /// This is the minimum difference needed to overcome the friction in the mechanism.
+ ///
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("frictionDifference")]
+ public float FrictionPressureDifference { get; set; } = 10f;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("inlet")]
+ public string InletName { get; set; } = "inlet";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("outlet")]
+ public string OutletName { get; set; } = "outlet";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float TargetPressure { get; set; } = Atmospherics.OneAtmosphere;
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Binary/Components/GasPortComponent.cs b/Content.Server/Atmos/Piping/Binary/Components/GasPortComponent.cs
new file mode 100644
index 0000000000..454a27f98a
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Binary/Components/GasPortComponent.cs
@@ -0,0 +1,19 @@
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization.Manager.Attributes;
+using Robust.Shared.ViewVariables;
+
+namespace Content.Server.Atmos.Piping.Binary.Components
+{
+ [RegisterComponent]
+ public class GasPortComponent : Component
+ {
+ public override string Name => "GasPort";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("pipe")]
+ public string PipeName { get; set; } = "connected";
+
+ [ViewVariables(VVAccess.ReadOnly)]
+ public GasMixture Buffer { get; } = new();
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Binary/Components/GasPressurePumpComponent.cs b/Content.Server/Atmos/Piping/Binary/Components/GasPressurePumpComponent.cs
new file mode 100644
index 0000000000..330f23c9a8
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Binary/Components/GasPressurePumpComponent.cs
@@ -0,0 +1,27 @@
+using Content.Shared.Atmos;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization.Manager.Attributes;
+using Robust.Shared.ViewVariables;
+
+namespace Content.Server.Atmos.Piping.Binary.Components
+{
+ [RegisterComponent]
+ public class GasPressurePumpComponent : Component
+ {
+ public override string Name => "GasPressurePump";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public bool Enabled { get; set; } = true;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("inlet")]
+ public string InletName { get; set; } = "inlet";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("outlet")]
+ public string OutletName { get; set; } = "outlet";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float TargetPressure { get; set; } = Atmospherics.OneAtmosphere;
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Binary/Components/GasValveComponent.cs b/Content.Server/Atmos/Piping/Binary/Components/GasValveComponent.cs
new file mode 100644
index 0000000000..6a239c0700
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Binary/Components/GasValveComponent.cs
@@ -0,0 +1,55 @@
+using Content.Server.GameObjects.Components.NodeContainer.Nodes;
+using Content.Server.NodeContainer;
+using Content.Shared.ActionBlocker;
+using Content.Shared.Interaction;
+using Content.Shared.Interaction.Helpers;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization.Manager.Attributes;
+using Robust.Shared.ViewVariables;
+
+namespace Content.Server.Atmos.Piping.Binary.Components
+{
+ // TODO ATMOS: Make ECS.
+ [ComponentReference(typeof(IActivate))]
+ [RegisterComponent]
+ public class GasValveComponent : Component, IActivate
+ {
+ public override string Name => "GasValve";
+
+ [ViewVariables]
+ [DataField("open")]
+ private bool _open = true;
+
+ [DataField("pipe")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ private string _pipeName = "pipe";
+
+ protected override void Startup()
+ {
+ base.Startup();
+
+ Set();
+ }
+
+ private void Set()
+ {
+ if (Owner.TryGetComponent(out NodeContainerComponent? nodeContainer)
+ && nodeContainer.TryGetNode(_pipeName, out PipeNode? pipe))
+ {
+ pipe.ConnectionsEnabled = _open;
+ }
+ }
+
+ private void Toggle()
+ {
+ _open = !_open;
+ Set();
+ }
+
+ void IActivate.Activate(ActivateEventArgs eventArgs)
+ {
+ if(eventArgs.InRangeUnobstructed() && EntitySystem.Get().CanInteract(eventArgs.User))
+ Toggle();
+ }
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Binary/Components/GasVolumePumpComponent.cs b/Content.Server/Atmos/Piping/Binary/Components/GasVolumePumpComponent.cs
new file mode 100644
index 0000000000..45cac2a1e5
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Binary/Components/GasVolumePumpComponent.cs
@@ -0,0 +1,42 @@
+using Content.Shared.Atmos;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization.Manager.Attributes;
+using Robust.Shared.ViewVariables;
+
+namespace Content.Server.Atmos.Piping.Binary.Components
+{
+ [RegisterComponent]
+ public class GasVolumePumpComponent : Component
+ {
+ public override string Name => "GasVolumePump";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public bool Enabled { get; set; } = true;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public bool Overclocked { get; set; } = false;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("inlet")]
+ public string InletName { get; set; } = "inlet";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("outlet")]
+ public string OutletName { get; set; } = "outlet";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float TransferRate { get; set; } = Atmospherics.MaxTransferRate;
+
+ [DataField("leakRatio")]
+ public float LeakRatio { get; set; } = 0.1f;
+
+ [DataField("lowerThreshold")]
+ public float LowerThreshold { get; set; } = 0.01f;
+
+ [DataField("higherThreshold")]
+ public float HigherThreshold { get; set; } = 9000f;
+
+ [DataField("overclockThreshold")]
+ public float OverclockThreshold { get; set; } = 1000f;
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasCanisterSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasCanisterSystem.cs
new file mode 100644
index 0000000000..bd0cc9f397
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasCanisterSystem.cs
@@ -0,0 +1,247 @@
+using System;
+using Content.Server.Atmos.Components;
+using Content.Server.Atmos.Piping.Binary.Components;
+using Content.Server.Atmos.Piping.Components;
+using Content.Server.GameObjects.Components.NodeContainer.Nodes;
+using Content.Server.Hands.Components;
+using Content.Server.NodeContainer;
+using Content.Server.UserInterface;
+using Content.Shared.ActionBlocker;
+using Content.Shared.Atmos;
+using Content.Shared.Atmos.Piping.Binary.Components;
+using Content.Shared.Interaction;
+using Content.Shared.Interaction.Helpers;
+using JetBrains.Annotations;
+using Robust.Server.GameObjects;
+using Robust.Shared.Containers;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Maths;
+
+namespace Content.Server.Atmos.Piping.Binary.EntitySystems
+{
+ [UsedImplicitly]
+ public class GasCanisterSystem : EntitySystem
+ {
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnCanisterStartup);
+ SubscribeLocalEvent(OnCanisterUpdated);
+ SubscribeLocalEvent(OnCanisterActivate);
+ SubscribeLocalEvent(OnCanisterInteractHand);
+ SubscribeLocalEvent(OnCanisterInteractUsing);
+ SubscribeLocalEvent(OnCanisterContainerInserted);
+ SubscribeLocalEvent(OnCanisterContainerRemoved);
+ }
+
+ private void OnCanisterStartup(EntityUid uid, GasCanisterComponent canister, ComponentStartup args)
+ {
+ // TODO ATMOS: Don't use Owner to get the UI.
+ if(canister.Owner.GetUIOrNull(GasCanisterUiKey.Key) is {} ui)
+ ui.OnReceiveMessage += msg => OnCanisterUIMessage(uid, canister, msg);
+
+ if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
+ return;
+
+ if (!nodeContainer.TryGetNode(canister.PortName, out PipeNode? portNode))
+ return;
+
+ // Create a pipenet if we don't have one already.
+ portNode.TryAssignGroupIfNeeded();
+ portNode.Air.Merge(canister.InitialMixture);
+ portNode.Air.Temperature = canister.InitialMixture.Temperature;
+ portNode.Volume = canister.InitialMixture.Volume;
+ }
+
+ private void DirtyUI(EntityUid uid)
+ {
+ if (!ComponentManager.TryGetComponent(uid, out IMetaDataComponent? metadata)
+ || !ComponentManager.TryGetComponent(uid, out GasCanisterComponent? canister)
+ || !ComponentManager.TryGetComponent(uid, out GasPassiveGateComponent? passiveGate)
+ || !ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
+ || !nodeContainer.TryGetNode(canister.PortName, out PipeNode? portNode)
+ || !nodeContainer.TryGetNode(canister.TankName, out PipeNode? tankNode)
+ || !ComponentManager.TryGetComponent(uid, out ServerUserInterfaceComponent? userInterfaceComponent)
+ || !userInterfaceComponent.TryGetBoundUserInterface(GasCanisterUiKey.Key, out var ui))
+ return;
+
+ string? tankLabel = null;
+ var tankPressure = 0f;
+
+ if (ComponentManager.TryGetComponent(uid, out ContainerManagerComponent? containerManager) && containerManager.TryGetContainer(canister.ContainerName, out var tankContainer) && tankContainer.ContainedEntities.Count > 0)
+ {
+ var tank = tankContainer.ContainedEntities[0];
+ tankLabel = tank.Name;
+ tankPressure = tankNode.Air.Pressure;
+ }
+
+ ui.SetState(new GasCanisterBoundUserInterfaceState(metadata.EntityName, portNode.Air.Pressure,
+ portNode.NodeGroup.Nodes.Count > 1, tankLabel, tankPressure,
+ passiveGate.TargetPressure, passiveGate.Enabled,
+ canister.MinReleasePressure, canister.MaxReleasePressure));
+ }
+
+ private void OnCanisterUIMessage(EntityUid uid, GasCanisterComponent canister, ServerBoundUserInterfaceMessage msg)
+ {
+ if (msg.Session.AttachedEntity is not {} entity
+ || !Get().CanInteract(entity)
+ || !Get().CanUse(entity))
+ return;
+
+
+ if (!ComponentManager.TryGetComponent(uid, out GasPassiveGateComponent? passiveGate)
+ || !ComponentManager.TryGetComponent(uid, out ContainerManagerComponent? containerManager)
+ || !containerManager.TryGetContainer(canister.ContainerName, out var container))
+ return;
+
+ switch (msg.Message)
+ {
+ case GasCanisterHoldingTankEjectMessage:
+ if (container.ContainedEntities.Count == 0)
+ break;
+
+ container.Remove(container.ContainedEntities[0]);
+ break;
+
+ case GasCanisterChangeReleasePressureMessage changeReleasePressure:
+ var pressure = Math.Clamp(changeReleasePressure.Pressure, canister.MinReleasePressure, canister.MaxReleasePressure);
+
+ passiveGate.TargetPressure = pressure;
+ DirtyUI(uid);
+ break;
+
+ case GasCanisterChangeReleaseValveMessage changeReleaseValve:
+ passiveGate.Enabled = changeReleaseValve.Valve;
+ DirtyUI(uid);
+ break;
+ }
+ }
+
+ private void OnCanisterUpdated(EntityUid uid, GasCanisterComponent canister, AtmosDeviceUpdateEvent args)
+ {
+ if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
+ || !ComponentManager.TryGetComponent(uid, out AppearanceComponent? appearance))
+ return;
+
+ if (!nodeContainer.TryGetNode(canister.PortName, out PipeNode? portNode))
+ return;
+
+ DirtyUI(uid);
+
+ // Nothing to do here.
+ if (MathHelper.CloseTo(portNode.Air.Pressure, canister.LastPressure))
+ return;
+
+ canister.LastPressure = portNode.Air.Pressure;
+
+ if (portNode.Air.Pressure < 10)
+ {
+ appearance.SetData(GasCanisterVisuals.PressureState, 0);
+ }
+ else if (portNode.Air.Pressure < Atmospherics.OneAtmosphere)
+ {
+ appearance.SetData(GasCanisterVisuals.PressureState, 1);
+ }
+ else if (portNode.Air.Pressure < (15 * Atmospherics.OneAtmosphere))
+ {
+ appearance.SetData(GasCanisterVisuals.PressureState, 2);
+ }
+ else
+ {
+ appearance.SetData(GasCanisterVisuals.PressureState, 3);
+ }
+ }
+
+ private void OnCanisterActivate(EntityUid uid, GasCanisterComponent component, ActivateInWorldEvent args)
+ {
+ if (!args.User.TryGetComponent(out ActorComponent? actor))
+ return;
+
+ component.Owner.GetUIOrNull(GasCanisterUiKey.Key)?.Open(actor.PlayerSession);
+ args.Handled = true;
+ }
+
+
+ private void OnCanisterInteractHand(EntityUid uid, GasCanisterComponent component, InteractHandEvent args)
+ {
+ if (!args.User.TryGetComponent(out ActorComponent? actor))
+ return;
+
+ component.Owner.GetUIOrNull(GasCanisterUiKey.Key)?.Open(actor.PlayerSession);
+ args.Handled = true;
+ }
+
+ private void OnCanisterInteractUsing(EntityUid uid, GasCanisterComponent component, InteractUsingEvent args)
+ {
+ var canister = EntityManager.GetEntity(uid);
+ var container = canister.EnsureContainer(component.ContainerName);
+
+ // Container full.
+ if (container.ContainedEntity != null)
+ return;
+
+ // Check the used item is valid...
+ if (!args.Used.TryGetComponent(out GasTankComponent? _)
+ || !args.Used.TryGetComponent(out NodeContainerComponent? _))
+ return;
+
+ // Check the user has hands.
+ if (!args.User.TryGetComponent(out HandsComponent? hands))
+ return;
+
+ if (!args.User.InRangeUnobstructed(canister, SharedInteractionSystem.InteractionRange, popup: true))
+ return;
+
+ if (!hands.Drop(args.Used, canister.Transform.Coordinates))
+ return;
+
+ if (!container.Insert(args.Used))
+ return;
+
+ args.Handled = true;
+ }
+
+ private void OnCanisterContainerInserted(EntityUid uid, GasCanisterComponent component, EntInsertedIntoContainerMessage args)
+ {
+ if (args.Container.ID != component.ContainerName)
+ return;
+
+ DirtyUI(uid);
+
+ if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
+ || !nodeContainer.TryGetNode(component.TankName, out PipeNode? tankNode))
+ return;
+
+ tankNode.EnvironmentalAir = false;
+ tankNode.ConnectToContainedEntities = true;
+ tankNode.NodeGroup.RemakeGroup();
+
+ if (!ComponentManager.TryGetComponent(uid, out AppearanceComponent? appearance))
+ return;
+
+ appearance.SetData(GasCanisterVisuals.TankInserted, true);
+ }
+
+ private void OnCanisterContainerRemoved(EntityUid uid, GasCanisterComponent component, EntRemovedFromContainerMessage args)
+ {
+ if (args.Container.ID != component.ContainerName)
+ return;
+
+ DirtyUI(uid);
+
+ if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
+ || !nodeContainer.TryGetNode(component.TankName, out PipeNode? tankNode))
+ return;
+
+ tankNode.NodeGroup.RemakeGroup();
+ tankNode.ConnectToContainedEntities = false;
+ tankNode.EnvironmentalAir = true;
+
+ if (!ComponentManager.TryGetComponent(uid, out AppearanceComponent? appearance))
+ return;
+
+ appearance.SetData(GasCanisterVisuals.TankInserted, false);
+ }
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPassiveGateSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPassiveGateSystem.cs
new file mode 100644
index 0000000000..dc825a48d6
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPassiveGateSystem.cs
@@ -0,0 +1,53 @@
+using System;
+using Content.Server.Atmos.Piping.Binary.Components;
+using Content.Server.Atmos.Piping.Components;
+using Content.Server.GameObjects.Components.NodeContainer.Nodes;
+using Content.Server.NodeContainer;
+using Content.Shared.Atmos;
+using JetBrains.Annotations;
+using Robust.Shared.GameObjects;
+
+namespace Content.Server.Atmos.Piping.Binary.EntitySystems
+{
+ [UsedImplicitly]
+ public class GasPassiveGateSystem : EntitySystem
+ {
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnPassiveGateUpdated);
+ }
+
+ private void OnPassiveGateUpdated(EntityUid uid, GasPassiveGateComponent gate, AtmosDeviceUpdateEvent args)
+ {
+ if (!gate.Enabled)
+ return;
+
+ if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
+ return;
+
+ if (!nodeContainer.TryGetNode(gate.InletName, out PipeNode? inlet)
+ || !nodeContainer.TryGetNode(gate.OutletName, out PipeNode? outlet))
+ return;
+
+ var outputStartingPressure = outlet.Air.Pressure;
+ var inputStartingPressure = inlet.Air.Pressure;
+
+ if (outputStartingPressure >= MathF.Min(gate.TargetPressure, inputStartingPressure - gate.FrictionPressureDifference))
+ return; // No need to pump gas, target reached or input pressure too low.
+
+ if (inlet.Air.TotalMoles > 0 && inlet.Air.Temperature > 0)
+ {
+ // We calculate the necessary moles to transfer using our good ol' friend PV=nRT.
+ var pressureDelta = MathF.Min(gate.TargetPressure - outputStartingPressure, (inputStartingPressure - outputStartingPressure)/2);
+ // We can't have a pressure delta that would cause outlet pressure > inlet pressure.
+
+ var transferMoles = pressureDelta * outlet.Air.Volume / (inlet.Air.Temperature * Atmospherics.R);
+
+ // Actually transfer the gas.
+ outlet.AssumeAir(inlet.Air.Remove(transferMoles));
+ }
+ }
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs
new file mode 100644
index 0000000000..5e616ea68a
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs
@@ -0,0 +1,67 @@
+using Content.Server.Atmos.Piping.Binary.Components;
+using Content.Server.Atmos.Piping.Components;
+using Content.Server.GameObjects.Components.NodeContainer.Nodes;
+using Content.Server.NodeContainer;
+using Content.Shared.Atmos;
+using Content.Shared.Atmos.Piping;
+using JetBrains.Annotations;
+using Robust.Server.GameObjects;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Maths;
+
+namespace Content.Server.Atmos.Piping.Binary.EntitySystems
+{
+ [UsedImplicitly]
+ public class GasPressurePumpSystem : EntitySystem
+ {
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnPumpUpdated);
+ SubscribeLocalEvent(OnPumpLeaveAtmosphere);
+ }
+
+ private void OnPumpUpdated(EntityUid uid, GasPressurePumpComponent pump, AtmosDeviceUpdateEvent args)
+ {
+ var appearance = pump.Owner.GetComponentOrNull();
+ appearance?.SetData(PressurePumpVisuals.Enabled, false);
+
+ if (!pump.Enabled)
+ return;
+
+ if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
+ return;
+
+ if (!nodeContainer.TryGetNode(pump.InletName, out PipeNode? inlet)
+ || !nodeContainer.TryGetNode(pump.OutletName, out PipeNode? outlet))
+ return;
+
+ var outputStartingPressure = outlet.Air.Pressure;
+
+ if (MathHelper.CloseTo(pump.TargetPressure, outputStartingPressure))
+ return; // No need to pump gas if target has been reached.
+
+ if (inlet.Air.TotalMoles > 0 && inlet.Air.Temperature > 0)
+ {
+ appearance?.SetData(PressurePumpVisuals.Enabled, true);
+
+ // We calculate the necessary moles to transfer using our good ol' friend PV=nRT.
+ var pressureDelta = pump.TargetPressure - outputStartingPressure;
+ var transferMoles = pressureDelta * outlet.Air.Volume / inlet.Air.Temperature * Atmospherics.R;
+
+ var removed = inlet.Air.Remove(transferMoles);
+ outlet.AssumeAir(removed);
+ }
+ }
+
+ private void OnPumpLeaveAtmosphere(EntityUid uid, GasPressurePumpComponent component, AtmosDeviceDisabledEvent args)
+ {
+ if (ComponentManager.TryGetComponent(uid, out AppearanceComponent? appearance))
+ {
+ appearance.SetData(PressurePumpVisuals.Enabled, false);
+ }
+ }
+
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs
new file mode 100644
index 0000000000..a157094c88
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs
@@ -0,0 +1,70 @@
+using Content.Server.Atmos.Piping.Binary.Components;
+using Content.Server.Atmos.Piping.Components;
+using Content.Server.GameObjects.Components.NodeContainer.Nodes;
+using Content.Server.NodeContainer;
+using JetBrains.Annotations;
+using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
+using Robust.Shared.Timing;
+
+namespace Content.Server.Atmos.Piping.Binary.EntitySystems
+{
+ [UsedImplicitly]
+ public class GasVolumePumpSystem : EntitySystem
+ {
+ [Dependency] private IGameTiming _gameTiming = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnVolumePumpUpdated);
+ }
+
+ private void OnVolumePumpUpdated(EntityUid uid, GasVolumePumpComponent pump, AtmosDeviceUpdateEvent args)
+ {
+ if (!pump.Enabled)
+ return;
+
+ if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
+ return;
+
+ if (!ComponentManager.TryGetComponent(uid, out AtmosDeviceComponent? device))
+ return;
+
+ if (!nodeContainer.TryGetNode(pump.InletName, out PipeNode? inlet)
+ || !nodeContainer.TryGetNode(pump.OutletName, out PipeNode? outlet))
+ return;
+
+ var inputStartingPressure = inlet.Air.Pressure;
+ var outputStartingPressure = outlet.Air.Pressure;
+
+ // Pump mechanism won't do anything if the pressure is too high/too low unless you overclock it.
+ if ((inputStartingPressure < pump.LowerThreshold) || (outputStartingPressure > pump.HigherThreshold) && !pump.Overclocked)
+ return;
+
+ // Overclocked pumps can only force gas a certain amount.
+ if ((outputStartingPressure - inputStartingPressure > pump.OverclockThreshold) && pump.Overclocked)
+ return;
+
+ // We multiply the transfer rate in L/s by the seconds passed since the last process to get the liters.
+ var transferRatio = (float)(pump.TransferRate * (_gameTiming.CurTime - device.LastProcess).TotalSeconds) / inlet.Air.Volume;
+
+ var removed = inlet.Air.RemoveRatio(transferRatio);
+
+ // Some of the gas from the mixture leaks when overclocked.
+ if (pump.Overclocked)
+ {
+ var tile = args.Atmosphere.GetTile(pump.Owner.Transform.Coordinates);
+
+ if (tile != null)
+ {
+ var leaked = removed.RemoveRatio(pump.LeakRatio);
+ tile.AssumeAir(leaked);
+ }
+ }
+
+ outlet.AssumeAir(removed);
+ }
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Components/AtmosDeviceComponent.cs b/Content.Server/Atmos/Piping/Components/AtmosDeviceComponent.cs
new file mode 100644
index 0000000000..20637de79d
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Components/AtmosDeviceComponent.cs
@@ -0,0 +1,61 @@
+#nullable enable
+using System;
+using Content.Server.Atmos.Components;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization.Manager.Attributes;
+using Robust.Shared.ViewVariables;
+
+namespace Content.Server.Atmos.Piping.Components
+{
+ ///
+ /// Adds itself to a to be updated by.
+ ///
+ [RegisterComponent]
+ public class AtmosDeviceComponent : Component
+ {
+ public override string Name => "AtmosDevice";
+
+ ///
+ /// Whether this device requires being anchored to join an atmosphere.
+ ///
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("requireAnchored")]
+ public bool RequireAnchored { get; private set; } = true;
+
+ public IGridAtmosphereComponent? Atmosphere { get; set; }
+
+ [ViewVariables]
+ public TimeSpan LastProcess { get; set; } = TimeSpan.Zero;
+ }
+
+ public abstract class BaseAtmosDeviceEvent : EntityEventArgs
+ {
+ public IGridAtmosphereComponent Atmosphere { get; }
+
+ public BaseAtmosDeviceEvent(IGridAtmosphereComponent atmosphere)
+ {
+ Atmosphere = atmosphere;
+ }
+ }
+
+ public sealed class AtmosDeviceUpdateEvent : BaseAtmosDeviceEvent
+ {
+ public AtmosDeviceUpdateEvent(IGridAtmosphereComponent atmosphere) : base(atmosphere)
+ {
+ }
+ }
+
+ public sealed class AtmosDeviceEnabledEvent : BaseAtmosDeviceEvent
+ {
+ public AtmosDeviceEnabledEvent(IGridAtmosphereComponent atmosphere) : base(atmosphere)
+ {
+ }
+ }
+
+ public sealed class AtmosDeviceDisabledEvent : BaseAtmosDeviceEvent
+ {
+ public AtmosDeviceDisabledEvent(IGridAtmosphereComponent atmosphere) : base(atmosphere)
+ {
+ }
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Components/AtmosUnsafeUnanchorComponent.cs b/Content.Server/Atmos/Piping/Components/AtmosUnsafeUnanchorComponent.cs
new file mode 100644
index 0000000000..039ac104de
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Components/AtmosUnsafeUnanchorComponent.cs
@@ -0,0 +1,16 @@
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization.Manager.Attributes;
+using Robust.Shared.ViewVariables;
+
+namespace Content.Server.Atmos.Piping.Components
+{
+ [RegisterComponent]
+ public class AtmosUnsafeUnanchorComponent : Component
+ {
+ public override string Name => "AtmosUnsafeUnanchor";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("enabled")]
+ public bool Enabled { get; set; } = true;
+ }
+}
diff --git a/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs b/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs
new file mode 100644
index 0000000000..60f8fd3ead
--- /dev/null
+++ b/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs
@@ -0,0 +1,92 @@
+using System;
+using Content.Server.Atmos.EntitySystems;
+using Content.Server.Atmos.Piping.Components;
+using JetBrains.Annotations;
+using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
+using Robust.Shared.Physics;
+using Robust.Shared.Timing;
+
+namespace Content.Server.Atmos.Piping.EntitySystems
+{
+ [UsedImplicitly]
+ public class AtmosDeviceSystem : EntitySystem
+ {
+ [Dependency] private IGameTiming _gameTiming = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnDeviceInitialize);
+ SubscribeLocalEvent(OnDeviceShutdown);
+ SubscribeLocalEvent(OnDeviceBodyTypeChanged);
+ SubscribeLocalEvent(OnDeviceParentChanged);
+ }
+
+ private bool CanJoinAtmosphere(AtmosDeviceComponent component)
+ {
+ return !component.RequireAnchored || !component.Owner.TryGetComponent(out PhysicsComponent? physics) || physics.BodyType == BodyType.Static;
+ }
+
+ public void JoinAtmosphere(AtmosDeviceComponent component)
+ {
+ if (!CanJoinAtmosphere(component))
+ return;
+
+ // We try to get a valid, simulated atmosphere.
+ if (!Get().TryGetSimulatedGridAtmosphere(component.Owner.Transform.MapPosition, out var atmosphere))
+ return;
+
+ component.LastProcess = _gameTiming.CurTime;
+ component.Atmosphere = atmosphere;
+ atmosphere.AddAtmosDevice(component);
+
+ RaiseLocalEvent(component.Owner.Uid, new AtmosDeviceEnabledEvent(atmosphere), false);
+ }
+
+ public void LeaveAtmosphere(AtmosDeviceComponent component)
+ {
+ var atmosphere = component.Atmosphere;
+ atmosphere?.RemoveAtmosDevice(component);
+ component.Atmosphere = null;
+ component.LastProcess = TimeSpan.Zero;
+
+ if(atmosphere != null)
+ RaiseLocalEvent(component.Owner.Uid, new AtmosDeviceDisabledEvent(atmosphere), false);
+ }
+
+ public void RejoinAtmosphere(AtmosDeviceComponent component)
+ {
+ LeaveAtmosphere(component);
+ JoinAtmosphere(component);
+ }
+
+ private void OnDeviceInitialize(EntityUid uid, AtmosDeviceComponent component, ComponentInit args)
+ {
+ JoinAtmosphere(component);
+ }
+
+ private void OnDeviceShutdown(EntityUid uid, AtmosDeviceComponent component, ComponentShutdown args)
+ {
+ LeaveAtmosphere(component);
+ }
+
+ private void OnDeviceBodyTypeChanged(EntityUid uid, AtmosDeviceComponent component, PhysicsBodyTypeChangedEvent args)
+ {
+ // Do nothing if the component doesn't require being anchored to function.
+ if (!component.RequireAnchored)
+ return;
+
+ if (args.New == BodyType.Static)
+ JoinAtmosphere(component);
+ else
+ LeaveAtmosphere(component);
+ }
+
+ private void OnDeviceParentChanged(EntityUid uid, AtmosDeviceComponent component, EntParentChangedMessage args)
+ {
+ RejoinAtmosphere(component);
+ }
+ }
+}
diff --git a/Content.Server/Atmos/Piping/EntitySystems/AtmosUnsafeUnanchorSystem.cs b/Content.Server/Atmos/Piping/EntitySystems/AtmosUnsafeUnanchorSystem.cs
new file mode 100644
index 0000000000..28a59bf74e
--- /dev/null
+++ b/Content.Server/Atmos/Piping/EntitySystems/AtmosUnsafeUnanchorSystem.cs
@@ -0,0 +1,80 @@
+using Content.Server.Anchor;
+using Content.Server.Atmos.Piping.Components;
+using Content.Server.GameObjects.Components.NodeContainer.Nodes;
+using Content.Server.NodeContainer;
+using Content.Shared.Atmos;
+using Content.Shared.Notification.Managers;
+using JetBrains.Annotations;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Localization;
+
+namespace Content.Server.Atmos.Piping.EntitySystems
+{
+ [UsedImplicitly]
+ public class AtmosUnsafeUnanchorSystem : EntitySystem
+ {
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnBeforeUnanchored);
+ SubscribeLocalEvent(OnUnanchorAttempt);
+ }
+
+ private void OnUnanchorAttempt(EntityUid uid, AtmosUnsafeUnanchorComponent component, UnanchorAttemptEvent args)
+ {
+ if (!component.Enabled || !ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodes))
+ return;
+
+ if (!component.Owner.Transform.Coordinates.TryGetTileAir(out var environment, EntityManager))
+ return;
+
+ foreach (var node in nodes.Nodes.Values)
+ {
+ if (node is not PipeNode pipe) continue;
+
+ if ((pipe.Air.Pressure - environment.Pressure) > 2 * Atmospherics.OneAtmosphere)
+ {
+ args.Delay += 1.5f;
+ args.User?.PopupMessageCursor(Loc.GetString("comp-atmos-unsafe-unanchor-warning"));
+ return; // Show the warning only once.
+ }
+ }
+ }
+
+ private void OnBeforeUnanchored(EntityUid uid, AtmosUnsafeUnanchorComponent component, BeforeUnanchoredEvent args)
+ {
+ if (!component.Enabled || !ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodes))
+ return;
+
+ if (!component.Owner.Transform.Coordinates.TryGetTileAtmosphere(out var environment))
+ environment = null;
+
+ var environmentPressure = environment?.Air?.Pressure ?? 0f;
+ var environmentVolume = environment?.Air?.Volume ?? Atmospherics.CellVolume;
+ var environmentTemperature = environment?.Air?.Volume ?? Atmospherics.TCMB;
+
+ 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 - environmentPressure;
+ lost += difference * environmentVolume / (environmentTemperature * Atmospherics.R);
+ timesLost++;
+ }
+
+ var sharedLoss = lost / timesLost;
+ var buffer = new GasMixture();
+
+ foreach (var node in nodes.Nodes.Values)
+ {
+ if (node is not PipeNode pipe) continue;
+
+ buffer.Merge(pipe.Air.Remove(sharedLoss));
+ }
+
+ environment?.AssumeAir(buffer);
+ }
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Other/Components/GasMinerComponent.cs b/Content.Server/Atmos/Piping/Other/Components/GasMinerComponent.cs
new file mode 100644
index 0000000000..170337d6ff
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Other/Components/GasMinerComponent.cs
@@ -0,0 +1,37 @@
+using Content.Shared.Atmos;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization.Manager.Attributes;
+using Robust.Shared.ViewVariables;
+
+namespace Content.Server.Atmos.Piping.Other.Components
+{
+ [RegisterComponent]
+ public class GasMinerComponent : Component
+ {
+ public override string Name => "GasMiner";
+
+ public bool Enabled { get; set; } = true;
+
+ public bool Broken { get; set; } = false;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("maxExternalAmount")]
+ public float MaxExternalAmount { get; set; } = float.PositiveInfinity;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("maxExternalPressure")]
+ public float MaxExternalPressure { get; set; } = 6500f;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("spawnGas")]
+ public Gas SpawnGas { get; set; } = Gas.Invalid;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("spawnTemperature")]
+ public float SpawnTemperature { get; set; } = Atmospherics.T20C;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("spawnAmount")]
+ public float SpawnAmount { get; set; } = Atmospherics.MolesCellStandard * 20f;
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs b/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs
new file mode 100644
index 0000000000..4646827e54
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs
@@ -0,0 +1,71 @@
+using System.Diagnostics.CodeAnalysis;
+using Content.Server.Atmos.Components;
+using Content.Server.Atmos.Piping.Components;
+using Content.Server.Atmos.Piping.Other.Components;
+using Content.Shared.Atmos;
+using JetBrains.Annotations;
+using Robust.Shared.GameObjects;
+
+namespace Content.Server.Atmos.Piping.Other.EntitySystems
+{
+ [UsedImplicitly]
+ public class GasMinerSystem : EntitySystem
+ {
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnMinerUpdated);
+ }
+
+ private void OnMinerUpdated(EntityUid uid, GasMinerComponent miner, AtmosDeviceUpdateEvent args)
+ {
+ if (!CheckMinerOperation(args.Atmosphere, miner, out var tile) || !miner.Enabled || miner.SpawnGas <= Gas.Invalid || miner.SpawnAmount <= 0f)
+ return;
+
+ // Time to mine some gas.
+
+ var merger = new GasMixture(1) { Temperature = miner.SpawnTemperature };
+ merger.SetMoles(miner.SpawnGas, miner.SpawnAmount);
+
+ tile.AssumeAir(merger);
+ }
+
+ private bool CheckMinerOperation(IGridAtmosphereComponent atmosphere, GasMinerComponent miner, [NotNullWhen(true)] out TileAtmosphere? tile)
+ {
+ tile = atmosphere.GetTile(miner.Owner.Transform.Coordinates)!;
+
+ // Space.
+ if (atmosphere.IsSpace(tile.GridIndices))
+ {
+ miner.Broken = true;
+ return false;
+ }
+
+ // Airblocked location.
+ if (tile.Air == null)
+ {
+ miner.Broken = true;
+ return false;
+ }
+
+ // External pressure above threshold.
+ if (!float.IsInfinity(miner.MaxExternalPressure) &&
+ tile.Air.Pressure > miner.MaxExternalPressure - miner.SpawnAmount * miner.SpawnTemperature * Atmospherics.R / tile.Air.Volume)
+ {
+ miner.Broken = true;
+ return false;
+ }
+
+ // External gas amount above threshold.
+ if (!float.IsInfinity(miner.MaxExternalAmount) && tile.Air.TotalMoles > miner.MaxExternalAmount)
+ {
+ miner.Broken = true;
+ return false;
+ }
+
+ miner.Broken = false;
+ return true;
+ }
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Trinary/Components/GasFilterComponent.cs b/Content.Server/Atmos/Piping/Trinary/Components/GasFilterComponent.cs
new file mode 100644
index 0000000000..ab5a4cc264
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Trinary/Components/GasFilterComponent.cs
@@ -0,0 +1,35 @@
+#nullable enable
+using Content.Shared.Atmos;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization.Manager.Attributes;
+using Robust.Shared.ViewVariables;
+
+namespace Content.Server.Atmos.Piping.Trinary.Components
+{
+ [RegisterComponent]
+ public class GasFilterComponent : Component
+ {
+ public override string Name => "GasFilter";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public bool Enabled { get; set; } = true;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("inlet")]
+ public string InletName { get; set; } = "inlet";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("filter")]
+ public string FilterName { get; set; } = "filter";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("outlet")]
+ public string OutletName { get; set; } = "outlet";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float TransferRate { get; set; } = Atmospherics.MaxTransferRate;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public Gas? FilteredGas { get; set; }
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Trinary/Components/GasMixerComponent.cs b/Content.Server/Atmos/Piping/Trinary/Components/GasMixerComponent.cs
new file mode 100644
index 0000000000..d7aaf7f935
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Trinary/Components/GasMixerComponent.cs
@@ -0,0 +1,37 @@
+using Content.Shared.Atmos;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization.Manager.Attributes;
+using Robust.Shared.ViewVariables;
+
+namespace Content.Server.Atmos.Piping.Trinary.Components
+{
+ [RegisterComponent]
+ public class GasMixerComponent : Component
+ {
+ public override string Name => "GasMixer";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public bool Enabled = true;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("inletOne")]
+ public string InletOneName = "inletOne";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("inletTwo")]
+ public string InletTwoName = "inletTwo";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("outlet")]
+ public string OutletName = "outlet";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float TargetPressure = Atmospherics.OneAtmosphere;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float InletOneConcentration = 0.5f;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float InletTwoConcentration = 0.5f;
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Trinary/EntitySystems/GasFilterSystem.cs b/Content.Server/Atmos/Piping/Trinary/EntitySystems/GasFilterSystem.cs
new file mode 100644
index 0000000000..2b543a6a82
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Trinary/EntitySystems/GasFilterSystem.cs
@@ -0,0 +1,66 @@
+using Content.Server.Atmos.Piping.Components;
+using Content.Server.Atmos.Piping.Trinary.Components;
+using Content.Server.GameObjects.Components.NodeContainer.Nodes;
+using Content.Server.NodeContainer;
+using Content.Shared.Atmos;
+using JetBrains.Annotations;
+using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
+using Robust.Shared.Timing;
+
+namespace Content.Server.Atmos.Piping.Trinary.EntitySystems
+{
+ [UsedImplicitly]
+ public class GasFilterSystem : EntitySystem
+ {
+ [Dependency] private IGameTiming _gameTiming = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnFilterUpdated);
+ }
+
+ private void OnFilterUpdated(EntityUid uid, GasFilterComponent filter, AtmosDeviceUpdateEvent args)
+ {
+ if (!filter.Enabled)
+ return;
+
+ if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
+ return;
+
+ if (!ComponentManager.TryGetComponent(uid, out AtmosDeviceComponent? device))
+ return;
+
+ if (!nodeContainer.TryGetNode(filter.InletName, out PipeNode? inletNode)
+ || !nodeContainer.TryGetNode(filter.FilterName, out PipeNode? filterNode)
+ || !nodeContainer.TryGetNode(filter.OutletName, out PipeNode? outletNode))
+ return;
+
+ if (outletNode.Air.Pressure >= Atmospherics.MaxOutputPressure)
+ return; // No need to transfer if target is full.
+
+ // We multiply the transfer rate in L/s by the seconds passed since the last process to get the liters.
+ var transferRatio = (float)(filter.TransferRate * (_gameTiming.CurTime - device.LastProcess).TotalSeconds) / inletNode.Air.Volume;
+
+ if (transferRatio <= 0)
+ return;
+
+ var removed = inletNode.Air.RemoveRatio(transferRatio);
+
+ if (filter.FilteredGas.HasValue)
+ {
+ var filteredOut = new GasMixture() {Temperature = removed.Temperature};
+
+ filteredOut.SetMoles(filter.FilteredGas.Value, removed.GetMoles(filter.FilteredGas.Value));
+ removed.SetMoles(filter.FilteredGas.Value, 0f);
+
+ var target = filterNode.Air.Pressure < Atmospherics.MaxOutputPressure ? filterNode : inletNode;
+ target.AssumeAir(filteredOut);
+ }
+
+ outletNode.AssumeAir(removed);
+ }
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Trinary/EntitySystems/GasMixerSystem.cs b/Content.Server/Atmos/Piping/Trinary/EntitySystems/GasMixerSystem.cs
new file mode 100644
index 0000000000..f2b829854f
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Trinary/EntitySystems/GasMixerSystem.cs
@@ -0,0 +1,95 @@
+using System;
+using Content.Server.Atmos.Piping.Components;
+using Content.Server.Atmos.Piping.Trinary.Components;
+using Content.Server.GameObjects.Components.NodeContainer.Nodes;
+using Content.Server.NodeContainer;
+using Content.Shared.Atmos;
+using JetBrains.Annotations;
+using Robust.Shared.GameObjects;
+
+namespace Content.Server.Atmos.Piping.Trinary.EntitySystems
+{
+ [UsedImplicitly]
+ public class GasMixerSystem : EntitySystem
+ {
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnMixerUpdated);
+ }
+
+ private void OnMixerUpdated(EntityUid uid, GasMixerComponent mixer, AtmosDeviceUpdateEvent args)
+ {
+ // TODO ATMOS: Cache total moles since it's expensive.
+
+ if (!mixer.Enabled)
+ return;
+
+ if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
+ return;
+
+ if (!nodeContainer.TryGetNode(mixer.InletOneName, out PipeNode? inletOne)
+ || !nodeContainer.TryGetNode(mixer.InletTwoName, out PipeNode? inletTwo)
+ || !nodeContainer.TryGetNode(mixer.OutletName, out PipeNode? outlet))
+ return;
+
+ var outputStartingPressure = outlet.Air.Pressure;
+
+ if (outputStartingPressure >= mixer.TargetPressure)
+ return; // Target reached, no need to mix.
+
+ var generalTransfer = (mixer.TargetPressure - outputStartingPressure) * outlet.Air.Volume / Atmospherics.R;
+
+ var transferMolesOne = inletOne.Air.Temperature > 0 ? mixer.InletOneConcentration * generalTransfer / inletOne.Air.Temperature : 0f;
+ var transferMolesTwo = inletTwo.Air.Temperature > 0 ? mixer.InletTwoConcentration * generalTransfer / inletTwo.Air.Temperature : 0f;
+
+ if (mixer.InletTwoConcentration <= 0f)
+ {
+ if (inletOne.Air.Temperature <= 0f)
+ return;
+
+ transferMolesOne = MathF.Min(transferMolesOne, inletOne.Air.TotalMoles);
+ transferMolesTwo = 0f;
+ }
+
+ else if (mixer.InletOneConcentration <= 0)
+ {
+ if (inletTwo.Air.Temperature <= 0f)
+ return;
+
+ transferMolesOne = 0f;
+ transferMolesTwo = MathF.Min(transferMolesTwo, inletTwo.Air.TotalMoles);
+ }
+ else
+ {
+ if (inletOne.Air.Temperature <= 0f || inletTwo.Air.Temperature <= 0f)
+ return;
+
+ if (transferMolesOne <= 0 || transferMolesTwo <= 0)
+ return;
+
+ if (inletOne.Air.TotalMoles < transferMolesOne || inletTwo.Air.TotalMoles < transferMolesTwo)
+ {
+ var ratio = MathF.Min(inletOne.Air.TotalMoles / transferMolesOne, inletTwo.Air.TotalMoles / transferMolesTwo);
+ transferMolesOne *= ratio;
+ transferMolesTwo *= ratio;
+ }
+ }
+
+ // Actually transfer the gas now.
+
+ if (transferMolesOne > 0f)
+ {
+ var removed = inletOne.Air.Remove(transferMolesOne);
+ outlet.AssumeAir(removed);
+ }
+
+ if (transferMolesTwo > 0f)
+ {
+ var removed = inletTwo.Air.Remove(transferMolesTwo);
+ outlet.AssumeAir(removed);
+ }
+ }
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Unary/Components/GasOutletInjectorComponent.cs b/Content.Server/Atmos/Piping/Unary/Components/GasOutletInjectorComponent.cs
new file mode 100644
index 0000000000..752c71bd86
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Unary/Components/GasOutletInjectorComponent.cs
@@ -0,0 +1,26 @@
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization.Manager.Attributes;
+using Robust.Shared.ViewVariables;
+
+namespace Content.Server.Atmos.Piping.Unary.Components
+{
+ [RegisterComponent]
+ public class GasOutletInjectorComponent : Component
+ {
+ public override string Name => "GasOutletInjector";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public bool Enabled { get; set; } = true;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public bool Injecting { get; set; } = false;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float VolumeRate { get; set; } = 50f;
+
+ [DataField("inlet")]
+ public string InletName { get; set; } = "pipe";
+
+ // TODO ATMOS: Inject method.
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Unary/Components/GasPassiveVentComponent.cs b/Content.Server/Atmos/Piping/Unary/Components/GasPassiveVentComponent.cs
new file mode 100644
index 0000000000..924da3ae8f
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Unary/Components/GasPassiveVentComponent.cs
@@ -0,0 +1,14 @@
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization.Manager.Attributes;
+
+namespace Content.Server.Atmos.Piping.Unary.Components
+{
+ [RegisterComponent]
+ public class GasPassiveVentComponent : Component
+ {
+ public override string Name => "GasPassiveVent";
+
+ [DataField("inlet")]
+ public string InletName = "pipe";
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Unary/Components/GasPortableComponent.cs b/Content.Server/Atmos/Piping/Unary/Components/GasPortableComponent.cs
new file mode 100644
index 0000000000..0411ce1272
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Unary/Components/GasPortableComponent.cs
@@ -0,0 +1,16 @@
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization.Manager.Attributes;
+using Robust.Shared.ViewVariables;
+
+namespace Content.Server.Atmos.Piping.Unary.Components
+{
+ [RegisterComponent]
+ public class GasPortableComponent : Component
+ {
+ public override string Name => "GasPortable";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("port")]
+ public string PortName { get; set; } = "port";
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Unary/Components/GasThermoMachineComponent.cs b/Content.Server/Atmos/Piping/Unary/Components/GasThermoMachineComponent.cs
new file mode 100644
index 0000000000..b4507be65f
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Unary/Components/GasThermoMachineComponent.cs
@@ -0,0 +1,90 @@
+using System;
+using System.Collections.Generic;
+using Content.Server.Construction;
+using Content.Server.Construction.Components;
+using Content.Shared.Atmos;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization;
+using Robust.Shared.Serialization.Manager.Attributes;
+using Robust.Shared.ViewVariables;
+
+namespace Content.Server.Atmos.Piping.Unary.Components
+{
+ [RegisterComponent]
+ public class GasThermoMachineComponent : Component, IRefreshParts, ISerializationHooks
+ {
+ public override string Name => "GasThermoMachine";
+
+ [DataField("inlet")]
+ public string InletName { get; set; } = "pipe";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public bool Enabled { get; set; } = true;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float HeatCapacity { get; set; } = 0;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float TargetTemperature { get; set; } = Atmospherics.T20C;
+
+ [DataField("mode")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public ThermoMachineMode Mode { get; set; } = ThermoMachineMode.Freezer;
+
+ [DataField("minTemperature")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float MinTemperature { get; set; } = Atmospherics.T20C;
+
+ [DataField("maxTemperature")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float MaxTemperature { get; set; } = Atmospherics.T20C;
+
+ public float InitialMinTemperature { get; private set; }
+ public float InitialMaxTemperature { get; private set; }
+
+ void IRefreshParts.RefreshParts(IEnumerable parts)
+ {
+ var matterBinRating = 0;
+ var laserRating = 0;
+
+ foreach (var part in parts)
+ {
+ switch (part.PartType)
+ {
+ case MachinePart.MatterBin:
+ matterBinRating += part.Rating;
+ break;
+ case MachinePart.Laser:
+ laserRating += part.Rating;
+ break;
+ }
+ }
+
+ HeatCapacity = 5000 * MathF.Pow((matterBinRating - 1), 2);
+
+ switch (Mode)
+ {
+ // 573.15K with stock parts.
+ case ThermoMachineMode.Heater:
+ MaxTemperature = Atmospherics.T20C + (InitialMaxTemperature * laserRating);
+ break;
+ // 73.15K with stock parts.
+ case ThermoMachineMode.Freezer:
+ MinTemperature = MathF.Max(Atmospherics.T0C - InitialMinTemperature + laserRating * 15f, Atmospherics.TCMB);
+ break;
+ }
+ }
+
+ void ISerializationHooks.AfterDeserialization()
+ {
+ InitialMinTemperature = MinTemperature;
+ InitialMaxTemperature = MaxTemperature;
+ }
+ }
+
+ public enum ThermoMachineMode : byte
+ {
+ Freezer = 0,
+ Heater = 1,
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Unary/Components/GasVentPumpComponent.cs b/Content.Server/Atmos/Piping/Unary/Components/GasVentPumpComponent.cs
new file mode 100644
index 0000000000..21f04d632c
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Unary/Components/GasVentPumpComponent.cs
@@ -0,0 +1,50 @@
+using System;
+using Content.Shared.Atmos;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization.Manager.Attributes;
+using Robust.Shared.ViewVariables;
+
+namespace Content.Server.Atmos.Piping.Unary.Components
+{
+ [RegisterComponent]
+ public class GasVentPumpComponent : Component
+ {
+ public override string Name => "GasVentPump";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public bool Enabled { get; set; } = true;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public bool Welded { get; set; } = false;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("inlet")]
+ public string InletName { get; set; } = "pipe";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public VentPumpDirection PumpDirection { get; set; } = VentPumpDirection.Releasing;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public VentPressureBound PressureChecks { get; set; } = VentPressureBound.ExternalBound;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float ExternalPressureBound { get; set; } = Atmospherics.OneAtmosphere;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float InternalPressureBound { get; set; } = 0f;
+ }
+
+ public enum VentPumpDirection : sbyte
+ {
+ Siphoning = 0,
+ Releasing = 1,
+ }
+
+ [Flags]
+ public enum VentPressureBound : sbyte
+ {
+ NoBound = 0,
+ InternalBound = 1,
+ ExternalBound = 2,
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Unary/Components/GasVentScrubberComponent.cs b/Content.Server/Atmos/Piping/Unary/Components/GasVentScrubberComponent.cs
new file mode 100644
index 0000000000..7f5d3f270f
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Unary/Components/GasVentScrubberComponent.cs
@@ -0,0 +1,45 @@
+using System.Collections.Generic;
+using Content.Shared.Atmos;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization.Manager.Attributes;
+using Robust.Shared.ViewVariables;
+
+namespace Content.Server.Atmos.Piping.Unary.Components
+{
+ [RegisterComponent]
+ public class GasVentScrubberComponent : Component
+ {
+ public override string Name => "GasVentScrubber";
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public bool Enabled { get; set; } = true;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public bool Welded { get; set; } = false;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("outlet")]
+ public string OutletName { get; set; } = "pipe";
+
+ [ViewVariables]
+ public readonly HashSet FilterGases = new()
+ {
+ Gas.CarbonDioxide
+ };
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public ScrubberPumpDirection PumpDirection { get; set; } = ScrubberPumpDirection.Scrubbing;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float VolumeRate { get; set; } = 200f;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public bool WideNet { get; set; } = false;
+ }
+
+ public enum ScrubberPumpDirection : sbyte
+ {
+ Siphoning = 0,
+ Scrubbing = 1,
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasOutletInjectorSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasOutletInjectorSystem.cs
new file mode 100644
index 0000000000..187cee7b93
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasOutletInjectorSystem.cs
@@ -0,0 +1,50 @@
+using Content.Server.Atmos.Piping.Components;
+using Content.Server.Atmos.Piping.Unary.Components;
+using Content.Server.GameObjects.Components.NodeContainer.Nodes;
+using Content.Server.NodeContainer;
+using Content.Shared.Atmos;
+using JetBrains.Annotations;
+using Robust.Shared.GameObjects;
+
+namespace Content.Server.Atmos.Piping.Unary.EntitySystems
+{
+ [UsedImplicitly]
+ public class GasOutletInjectorSystem : EntitySystem
+ {
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnOutletInjectorUpdated);
+ }
+
+ private void OnOutletInjectorUpdated(EntityUid uid, GasOutletInjectorComponent injector, AtmosDeviceUpdateEvent args)
+ {
+ injector.Injecting = false;
+
+ if (!injector.Enabled)
+ return;
+
+ if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
+ return;
+
+ if (!nodeContainer.TryGetNode(injector.InletName, out PipeNode? inlet))
+ return;
+
+ var environment = args.Atmosphere.GetTile(injector.Owner.Transform.Coordinates)!;
+
+ if (environment.Air == null)
+ return;
+
+ if (inlet.Air.Temperature > 0)
+ {
+ var transferMoles = inlet.Air.Pressure * injector.VolumeRate / (inlet.Air.Temperature * Atmospherics.R);
+
+ var removed = inlet.Air.Remove(transferMoles);
+
+ environment.AssumeAir(removed);
+ environment.Invalidate();
+ }
+ }
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPassiveVentSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPassiveVentSystem.cs
new file mode 100644
index 0000000000..c04d3c44ad
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPassiveVentSystem.cs
@@ -0,0 +1,61 @@
+using System;
+using Content.Server.Atmos.Piping.Components;
+using Content.Server.Atmos.Piping.Unary.Components;
+using Content.Server.GameObjects.Components.NodeContainer.Nodes;
+using Content.Server.NodeContainer;
+using Content.Shared.Atmos;
+using JetBrains.Annotations;
+using Robust.Shared.GameObjects;
+
+namespace Content.Server.Atmos.Piping.Unary.EntitySystems
+{
+ [UsedImplicitly]
+ public class GasPassiveVentSystem : EntitySystem
+ {
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnPassiveVentUpdated);
+ }
+
+ private void OnPassiveVentUpdated(EntityUid uid, GasPassiveVentComponent vent, AtmosDeviceUpdateEvent args)
+ {
+ var environment = args.Atmosphere.GetTile(vent.Owner.Transform.Coordinates)!;
+
+ if (environment.Air == null)
+ return;
+
+ if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
+ return;
+
+ if (!nodeContainer.TryGetNode(vent.InletName, out PipeNode? inlet))
+ return;
+
+ var environmentPressure = environment.Air.Pressure;
+ var pressureDelta = MathF.Abs(environmentPressure - inlet.Air.Pressure);
+
+ if ((environment.Air.Temperature > 0 || inlet.Air.Temperature > 0) && pressureDelta > 0.5f)
+ {
+ if (environmentPressure < inlet.Air.Pressure)
+ {
+ var airTemperature = environment.Temperature > 0 ? environment.Temperature : inlet.Air.Temperature;
+ var transferMoles = pressureDelta * environment.Air.Volume / (airTemperature * Atmospherics.R);
+ var removed = inlet.Air.Remove(transferMoles);
+ environment.AssumeAir(removed);
+ }
+ else
+ {
+ var airTemperature = inlet.Air.Temperature > 0 ? inlet.Air.Temperature : environment.Temperature;
+ var outputVolume = inlet.Air.Volume;
+ var transferMoles = (pressureDelta * outputVolume) / (airTemperature * Atmospherics.R);
+ transferMoles = MathF.Min(transferMoles, environment.Air.TotalMoles * inlet.Air.Volume / environment.Air.Volume);
+ var removed = environment.Air.Remove(transferMoles);
+ inlet.AssumeAir(removed);
+ environment.Invalidate();
+ }
+ }
+
+ }
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPortableSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPortableSystem.cs
new file mode 100644
index 0000000000..937e3c8819
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPortableSystem.cs
@@ -0,0 +1,92 @@
+using System.Diagnostics.CodeAnalysis;
+using Content.Server.Anchor;
+using Content.Server.Atmos.Piping.Binary.Components;
+using Content.Server.Atmos.Piping.Unary.Components;
+using Content.Server.GameObjects.Components.NodeContainer.Nodes;
+using Content.Server.NodeContainer;
+using Content.Shared.Atmos.Piping.Unary.Components;
+using JetBrains.Annotations;
+using Robust.Server.GameObjects;
+using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
+using Robust.Shared.Map;
+
+namespace Content.Server.Atmos.Piping.Unary.EntitySystems
+{
+ [UsedImplicitly]
+ public class GasPortableSystem : EntitySystem
+ {
+ [Dependency] private readonly IMapManager _mapManager = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnPortableAnchorAttempt);
+ SubscribeLocalEvent(OnPortableAnchored);
+ SubscribeLocalEvent(OnPortableUnanchored);
+ }
+
+ private void OnPortableAnchorAttempt(EntityUid uid, GasPortableComponent component, AnchorAttemptEvent args)
+ {
+ if (!ComponentManager.TryGetComponent(uid, out ITransformComponent? transform))
+ return;
+
+ // If we can't find any ports, cancel the anchoring.
+ if(!FindGasPortIn(transform.GridID, transform.Coordinates, out _))
+ args.Cancel();
+ }
+
+ private void OnPortableAnchored(EntityUid uid, GasPortableComponent portable, AnchoredEvent args)
+ {
+ if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
+ return;
+
+ if (!nodeContainer.TryGetNode(portable.PortName, out PipeNode? portableNode))
+ return;
+
+ portableNode.ConnectionsEnabled = true;
+
+ if (ComponentManager.TryGetComponent(uid, out AppearanceComponent? appearance))
+ {
+ appearance.SetData(GasPortableVisuals.ConnectedState, true);
+ }
+ }
+
+ private void OnPortableUnanchored(EntityUid uid, GasPortableComponent portable, UnanchoredEvent args)
+ {
+ if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
+ return;
+
+ if (!nodeContainer.TryGetNode(portable.PortName, out PipeNode? portableNode))
+ return;
+
+ portableNode.ConnectionsEnabled = false;
+
+ if (ComponentManager.TryGetComponent(uid, out AppearanceComponent? appearance))
+ {
+ appearance.SetData(GasPortableVisuals.ConnectedState, false);
+ }
+ }
+
+ private bool FindGasPortIn(GridId gridId, EntityCoordinates coordinates, [NotNullWhen(true)] out GasPortComponent? port)
+ {
+ port = null;
+
+ if (!gridId.IsValid())
+ return false;
+
+ var grid = _mapManager.GetGrid(gridId);
+
+ foreach (var entityUid in grid.GetLocal(coordinates))
+ {
+ if (ComponentManager.TryGetComponent(entityUid, out port))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasTankSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasTankSystem.cs
new file mode 100644
index 0000000000..ac329dc9bf
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasTankSystem.cs
@@ -0,0 +1,35 @@
+using Content.Server.Atmos.Components;
+using Content.Server.GameObjects.Components.NodeContainer.Nodes;
+using Content.Server.NodeContainer;
+using JetBrains.Annotations;
+using Robust.Shared.GameObjects;
+
+namespace Content.Server.Atmos.Piping.Unary.EntitySystems
+{
+ [UsedImplicitly]
+ public class GasTankSystem : EntitySystem
+ {
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnTankStartup);
+ }
+
+ private void OnTankStartup(EntityUid uid, GasTankComponent tank, ComponentStartup args)
+ {
+ if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
+ return;
+
+ if (!nodeContainer.TryGetNode(tank.TankName, out PipeNode? tankNode))
+ return;
+
+ // Create a pipenet if we don't have one already.
+ tankNode.TryAssignGroupIfNeeded();
+ tankNode.AssumeAir(tank.InitialMixture);
+ tankNode.Volume = tank.InitialMixture.Volume;
+ tankNode.Air.Volume = tank.InitialMixture.Volume;
+ tankNode.Air.Temperature = tank.InitialMixture.Temperature;
+ }
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs
new file mode 100644
index 0000000000..3d18755e5e
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs
@@ -0,0 +1,59 @@
+using Content.Server.Atmos.Piping.Components;
+using Content.Server.Atmos.Piping.Unary.Components;
+using Content.Server.GameObjects.Components.NodeContainer.Nodes;
+using Content.Server.NodeContainer;
+using Content.Shared.Atmos.Piping;
+using JetBrains.Annotations;
+using Robust.Server.GameObjects;
+using Robust.Shared.GameObjects;
+
+namespace Content.Server.Atmos.Piping.Unary.EntitySystems
+{
+ [UsedImplicitly]
+ public class GasThermoMachineSystem : EntitySystem
+ {
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnThermoMachineUpdated);
+ SubscribeLocalEvent(OnThermoMachineLeaveAtmosphere);
+ }
+
+ private void OnThermoMachineUpdated(EntityUid uid, GasThermoMachineComponent thermoMachine, AtmosDeviceUpdateEvent args)
+ {
+ var appearance = thermoMachine.Owner.GetComponentOrNull();
+ appearance?.SetData(ThermoMachineVisuals.Enabled, false);
+
+ if (!thermoMachine.Enabled)
+ return;
+
+ if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
+ return;
+
+ if (!nodeContainer.TryGetNode(thermoMachine.InletName, out PipeNode? inlet))
+ return;
+
+ var airHeatCapacity = inlet.Air.HeatCapacity;
+ var combinedHeatCapacity = airHeatCapacity + thermoMachine.HeatCapacity;
+ var oldTemperature = inlet.Air.Temperature;
+
+ if (combinedHeatCapacity > 0)
+ {
+ appearance?.SetData(ThermoMachineVisuals.Enabled, true);
+ var combinedEnergy = thermoMachine.HeatCapacity * thermoMachine.TargetTemperature + airHeatCapacity * inlet.Air.Temperature;
+ inlet.Air.Temperature = combinedEnergy / combinedHeatCapacity;
+ }
+
+ // TODO ATMOS: Active power usage.
+ }
+
+ private void OnThermoMachineLeaveAtmosphere(EntityUid uid, GasThermoMachineComponent component, AtmosDeviceDisabledEvent args)
+ {
+ if (ComponentManager.TryGetComponent(uid, out AppearanceComponent? appearance))
+ {
+ appearance.SetData(ThermoMachineVisuals.Enabled, false);
+ }
+ }
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs
new file mode 100644
index 0000000000..a310e4a225
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs
@@ -0,0 +1,101 @@
+using System;
+using Content.Server.Atmos.Piping.Components;
+using Content.Server.Atmos.Piping.Unary.Components;
+using Content.Server.GameObjects.Components.NodeContainer.Nodes;
+using Content.Server.NodeContainer;
+using Content.Shared.Atmos;
+using Content.Shared.Atmos.Visuals;
+using JetBrains.Annotations;
+using Robust.Server.GameObjects;
+using Robust.Shared.GameObjects;
+
+namespace Content.Server.Atmos.Piping.Unary.EntitySystems
+{
+ [UsedImplicitly]
+ public class GasVentPumpSystem : EntitySystem
+ {
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnGasVentPumpUpdated);
+ SubscribeLocalEvent(OnGasVentPumpLeaveAtmosphere);
+ }
+
+ private void OnGasVentPumpUpdated(EntityUid uid, GasVentPumpComponent vent, AtmosDeviceUpdateEvent args)
+ {
+ var appearance = vent.Owner.GetComponentOrNull();
+
+ if (vent.Welded)
+ {
+ appearance?.SetData(VentPumpVisuals.State, VentPumpState.Welded);
+ return;
+ }
+
+ appearance?.SetData(VentPumpVisuals.State, VentPumpState.Off);
+
+ if (!vent.Enabled)
+ return;
+
+ if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
+ return;
+
+ if (!nodeContainer.TryGetNode(vent.InletName, out PipeNode? pipe))
+ return;
+
+ var environment = args.Atmosphere.GetTile(vent.Owner.Transform.Coordinates)!;
+
+ // We're in an air-blocked tile... Do nothing.
+ if (environment.Air == null)
+ return;
+
+ if (vent.PumpDirection == VentPumpDirection.Releasing)
+ {
+ appearance?.SetData(VentPumpVisuals.State, VentPumpState.Out);
+ var pressureDelta = 10000f;
+
+ if ((vent.PressureChecks & VentPressureBound.ExternalBound) != 0)
+ pressureDelta = MathF.Min(pressureDelta, vent.ExternalPressureBound - environment.Air.Pressure);
+
+ if ((vent.PressureChecks & VentPressureBound.InternalBound) != 0)
+ pressureDelta = MathF.Min(pressureDelta, pipe.Air.Pressure - vent.InternalPressureBound);
+
+ if (pressureDelta > 0 && pipe.Air.Temperature > 0)
+ {
+ var transferMoles = pressureDelta * environment.Air.Volume / (pipe.Air.Temperature * Atmospherics.R);
+
+ environment.AssumeAir(pipe.Air.Remove(transferMoles));
+ }
+ }
+ else if (vent.PumpDirection == VentPumpDirection.Siphoning && environment.Air.Pressure > 0)
+ {
+ appearance?.SetData(VentPumpVisuals.State, VentPumpState.In);
+ var ourMultiplier = pipe.Air.Volume / (environment.Air.Temperature * Atmospherics.R);
+ var molesDelta = 10000f * ourMultiplier;
+
+ if ((vent.PressureChecks & VentPressureBound.ExternalBound) != 0)
+ molesDelta = MathF.Min(molesDelta,
+ (environment.Air.Pressure - vent.ExternalPressureBound) * environment.Air.Volume /
+ (environment.Air.Temperature * Atmospherics.R));
+
+ if ((vent.PressureChecks & VentPressureBound.InternalBound) != 0)
+ molesDelta = MathF.Min(molesDelta, (vent.InternalPressureBound - pipe.Air.Pressure) * ourMultiplier);
+
+ if (molesDelta > 0)
+ {
+ var removed = environment.Air.Remove(molesDelta);
+ pipe.AssumeAir(removed);
+ environment.Invalidate();
+ }
+ }
+ }
+
+ private void OnGasVentPumpLeaveAtmosphere(EntityUid uid, GasVentPumpComponent component, AtmosDeviceDisabledEvent args)
+ {
+ if (ComponentManager.TryGetComponent(uid, out AppearanceComponent? appearance))
+ {
+ appearance.SetData(VentPumpVisuals.State, VentPumpState.Off);
+ }
+ }
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs
new file mode 100644
index 0000000000..45a068e799
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs
@@ -0,0 +1,108 @@
+using System;
+using Content.Server.Atmos.Piping.Components;
+using Content.Server.Atmos.Piping.Unary.Components;
+using Content.Server.GameObjects.Components.NodeContainer.Nodes;
+using Content.Server.NodeContainer;
+using Content.Shared.Atmos;
+using Content.Shared.Atmos.Piping.Unary.Visuals;
+using JetBrains.Annotations;
+using Robust.Server.GameObjects;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Maths;
+
+namespace Content.Server.Atmos.Piping.Unary.EntitySystems
+{
+ [UsedImplicitly]
+ public class GasVentScrubberSystem : EntitySystem
+ {
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnVentScrubberUpdated);
+ SubscribeLocalEvent(OnVentScrubberLeaveAtmosphere);
+ }
+
+ private void OnVentScrubberUpdated(EntityUid uid, GasVentScrubberComponent scrubber, AtmosDeviceUpdateEvent args)
+ {
+ var appearance = scrubber.Owner.GetComponentOrNull();
+
+ if (scrubber.Welded)
+ {
+ appearance?.SetData(ScrubberVisuals.State, ScrubberState.Welded);
+ return;
+ }
+
+ appearance?.SetData(ScrubberVisuals.State, ScrubberState.Off);
+
+ if (!scrubber.Enabled)
+ return;
+
+ if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
+ return;
+
+ if (!nodeContainer.TryGetNode(scrubber.OutletName, out PipeNode? outlet))
+ return;
+
+ var environment = args.Atmosphere.GetTile(scrubber.Owner.Transform.Coordinates)!;
+
+ Scrub(scrubber, appearance, environment, outlet);
+
+ if (!scrubber.WideNet) return;
+
+ // Scrub adjacent tiles too.
+ foreach (var adjacent in environment.AdjacentTiles)
+ {
+ // Pass null appearance, we don't need to set it there.
+ Scrub(scrubber, null, adjacent, outlet);
+ }
+ }
+
+ private void OnVentScrubberLeaveAtmosphere(EntityUid uid, GasVentScrubberComponent component, AtmosDeviceDisabledEvent args)
+ {
+ if (ComponentManager.TryGetComponent(uid, out AppearanceComponent? appearance))
+ {
+ appearance.SetData(ScrubberVisuals.State, ScrubberState.Off);
+ }
+ }
+
+ private void Scrub(GasVentScrubberComponent scrubber, AppearanceComponent? appearance, TileAtmosphere? tile, PipeNode outlet)
+ {
+ // Cannot scrub if tile is null or air-blocked.
+ if (tile?.Air == null)
+ return;
+
+ // Cannot scrub if pressure too high.
+ if (outlet.Air.Pressure >= 50 * Atmospherics.OneAtmosphere)
+ return;
+
+ if (scrubber.PumpDirection == ScrubberPumpDirection.Scrubbing)
+ {
+ appearance?.SetData(ScrubberVisuals.State, scrubber.WideNet ? ScrubberState.WideScrub : ScrubberState.Scrub);
+ var transferMoles = MathF.Min(1f, (scrubber.VolumeRate / tile.Air.Volume) * tile.Air.TotalMoles);
+
+ // Take a gas sample.
+ var removed = tile.Air.Remove(transferMoles);
+
+ // Nothing left to remove from the tile.
+ if (MathHelper.CloseTo(removed.TotalMoles, 0f))
+ return;
+
+ removed.ScrubInto(outlet.Air, scrubber.FilterGases);
+
+ // Remix the gases.
+ tile.AssumeAir(removed);
+ }
+ else if (scrubber.PumpDirection == ScrubberPumpDirection.Siphoning)
+ {
+ appearance?.SetData(ScrubberVisuals.State, ScrubberState.Siphon);
+ var transferMoles = tile.Air.TotalMoles * (scrubber.VolumeRate / tile.Air.Volume);
+
+ var removed = tile.Air.Remove(transferMoles);
+
+ outlet.AssumeAir(removed);
+ tile.Invalidate();
+ }
+ }
+ }
+}
diff --git a/Content.Server/Atmos/Reactions/WaterVaporReaction.cs b/Content.Server/Atmos/Reactions/WaterVaporReaction.cs
index d01219a245..d49b39a9b1 100644
--- a/Content.Server/Atmos/Reactions/WaterVaporReaction.cs
+++ b/Content.Server/Atmos/Reactions/WaterVaporReaction.cs
@@ -1,7 +1,6 @@
#nullable enable
using Content.Server.Fluids.Components;
using Content.Server.Interfaces;
-using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Chemistry.Solution;
using Content.Shared.Maps;
diff --git a/Content.Server/Atmos/TileAtmosphere.cs b/Content.Server/Atmos/TileAtmosphere.cs
index d7952adef4..c297cf1a63 100644
--- a/Content.Server/Atmos/TileAtmosphere.cs
+++ b/Content.Server/Atmos/TileAtmosphere.cs
@@ -4,9 +4,9 @@ using System;
using System.Buffers;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
+using Content.Server.Atmos.Components;
using Content.Server.Atmos.Reactions;
using Content.Server.Coordinates.Helpers;
-using Content.Server.GameObjects.Components.Atmos;
using Content.Server.Interfaces;
using Content.Shared.Atmos;
using Content.Shared.Audio;
@@ -72,6 +72,8 @@ namespace Content.Server.Atmos
[ViewVariables]
private readonly TileAtmosphere[] _adjacentTiles = new TileAtmosphere[Atmospherics.Directions];
+ public IReadOnlyList AdjacentTiles => _adjacentTiles;
+
private AtmosDirection _adjacentBits = AtmosDirection.Invalid;
[ViewVariables, UsedImplicitly]
diff --git a/Content.Server/Body/Behavior/LungBehavior.cs b/Content.Server/Body/Behavior/LungBehavior.cs
index c4121eba7d..cf3954ba3a 100644
--- a/Content.Server/Body/Behavior/LungBehavior.cs
+++ b/Content.Server/Body/Behavior/LungBehavior.cs
@@ -1,9 +1,9 @@
#nullable enable
using System;
using Content.Server.Atmos;
+using Content.Server.Atmos.Components;
using Content.Server.Body.Circulatory;
using Content.Server.Body.Respiratory;
-using Content.Server.GameObjects.Components.Atmos;
using Content.Server.Notification;
using Content.Shared.Atmos;
using Content.Shared.Body.Components;
diff --git a/Content.Server/Body/Respiratory/InternalsComponent.cs b/Content.Server/Body/Respiratory/InternalsComponent.cs
index 37c833a614..85eba65e31 100644
--- a/Content.Server/Body/Respiratory/InternalsComponent.cs
+++ b/Content.Server/Body/Respiratory/InternalsComponent.cs
@@ -1,5 +1,5 @@
#nullable enable
-using Content.Server.GameObjects.Components.Atmos;
+using Content.Server.Atmos.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.ViewVariables;
diff --git a/Content.Server/Chemistry/Components/ChemMasterComponent.cs b/Content.Server/Chemistry/Components/ChemMasterComponent.cs
index 1ffae1e560..ce66ee0c08 100644
--- a/Content.Server/Chemistry/Components/ChemMasterComponent.cs
+++ b/Content.Server/Chemistry/Components/ChemMasterComponent.cs
@@ -12,7 +12,6 @@ using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Chemistry.Solution;
using Content.Shared.Interaction;
-using Content.Shared.Interaction.Events;
using Content.Shared.Notification.Managers;
using Content.Shared.Random.Helpers;
using Content.Shared.Verbs;
diff --git a/Content.Server/Chemistry/Components/HyposprayComponent.cs b/Content.Server/Chemistry/Components/HyposprayComponent.cs
index 384f7186a8..3df9575efb 100644
--- a/Content.Server/Chemistry/Components/HyposprayComponent.cs
+++ b/Content.Server/Chemistry/Components/HyposprayComponent.cs
@@ -4,7 +4,6 @@ using Content.Server.Weapon.Melee;
using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
-using Content.Shared.Notification;
using Content.Shared.Notification.Managers;
using Robust.Shared.Audio;
using Robust.Shared.GameObjects;
diff --git a/Content.Server/Chemistry/Components/InjectorComponent.cs b/Content.Server/Chemistry/Components/InjectorComponent.cs
index 3d1a22d835..c965315afb 100644
--- a/Content.Server/Chemistry/Components/InjectorComponent.cs
+++ b/Content.Server/Chemistry/Components/InjectorComponent.cs
@@ -8,7 +8,6 @@ using Content.Shared.Chemistry.Reagent;
using Content.Shared.Chemistry.Solution.Components;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Helpers;
-using Content.Shared.Notification;
using Content.Shared.Notification.Managers;
using Robust.Shared.GameObjects;
using Robust.Shared.Localization;
diff --git a/Content.Server/Chemistry/Components/PillComponent.cs b/Content.Server/Chemistry/Components/PillComponent.cs
index d03c951edc..6b3f53361b 100644
--- a/Content.Server/Chemistry/Components/PillComponent.cs
+++ b/Content.Server/Chemistry/Components/PillComponent.cs
@@ -6,7 +6,6 @@ using Content.Shared.Body.Components;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Helpers;
-using Content.Shared.Notification;
using Content.Shared.Notification.Managers;
using Robust.Shared.Audio;
using Robust.Shared.GameObjects;
diff --git a/Content.Server/Chemistry/Components/ReagentDispenserComponent.cs b/Content.Server/Chemistry/Components/ReagentDispenserComponent.cs
index 829870108f..790b7d8c72 100644
--- a/Content.Server/Chemistry/Components/ReagentDispenserComponent.cs
+++ b/Content.Server/Chemistry/Components/ReagentDispenserComponent.cs
@@ -13,7 +13,6 @@ using Content.Shared.Chemistry.Dispenser;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Chemistry.Solution;
using Content.Shared.Interaction;
-using Content.Shared.Interaction.Events;
using Content.Shared.Notification.Managers;
using Content.Shared.Verbs;
using JetBrains.Annotations;
diff --git a/Content.Server/Chemistry/Components/SolutionAreaEffectComponent.cs b/Content.Server/Chemistry/Components/SolutionAreaEffectComponent.cs
index db5b3e3f78..93587b0dff 100644
--- a/Content.Server/Chemistry/Components/SolutionAreaEffectComponent.cs
+++ b/Content.Server/Chemistry/Components/SolutionAreaEffectComponent.cs
@@ -1,8 +1,8 @@
#nullable enable
using System;
using System.Linq;
+using Content.Server.Atmos.Components;
using Content.Server.Coordinates.Helpers;
-using Content.Server.GameObjects.Components.Atmos;
using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Chemistry.Solution;
diff --git a/Content.Server/Chemistry/Components/SolutionTransferComponent.cs b/Content.Server/Chemistry/Components/SolutionTransferComponent.cs
index 54ccb883b6..1333999459 100644
--- a/Content.Server/Chemistry/Components/SolutionTransferComponent.cs
+++ b/Content.Server/Chemistry/Components/SolutionTransferComponent.cs
@@ -4,7 +4,6 @@ using Content.Shared.Chemistry.Reagent;
using Content.Shared.Chemistry.Solution.Components;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Helpers;
-using Content.Shared.Notification;
using Content.Shared.Notification.Managers;
using Robust.Shared.GameObjects;
using Robust.Shared.Localization;
diff --git a/Content.Server/Chemistry/ReagentEntityReactions/AddToSolutionReaction.cs b/Content.Server/Chemistry/ReagentEntityReactions/AddToSolutionReaction.cs
index 3d6975a36a..3218e4f983 100644
--- a/Content.Server/Chemistry/ReagentEntityReactions/AddToSolutionReaction.cs
+++ b/Content.Server/Chemistry/ReagentEntityReactions/AddToSolutionReaction.cs
@@ -1,6 +1,5 @@
using System.Collections.Generic;
using Content.Server.Chemistry.Components;
-using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Chemistry.Solution;
using JetBrains.Annotations;
diff --git a/Content.Server/Chemistry/ReagentEntityReactions/ExtinguishReaction.cs b/Content.Server/Chemistry/ReagentEntityReactions/ExtinguishReaction.cs
index b105f88093..9078eef2d1 100644
--- a/Content.Server/Chemistry/ReagentEntityReactions/ExtinguishReaction.cs
+++ b/Content.Server/Chemistry/ReagentEntityReactions/ExtinguishReaction.cs
@@ -1,6 +1,5 @@
using System.Collections.Generic;
-using Content.Server.GameObjects.Components.Atmos;
-using Content.Shared.Chemistry;
+using Content.Server.Atmos.Components;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Chemistry.Solution;
using JetBrains.Annotations;
diff --git a/Content.Server/Chemistry/ReagentEntityReactions/FlammableReaction.cs b/Content.Server/Chemistry/ReagentEntityReactions/FlammableReaction.cs
index f60c855e2a..5242565e0e 100644
--- a/Content.Server/Chemistry/ReagentEntityReactions/FlammableReaction.cs
+++ b/Content.Server/Chemistry/ReagentEntityReactions/FlammableReaction.cs
@@ -1,6 +1,5 @@
using System.Collections.Generic;
-using Content.Server.GameObjects.Components.Atmos;
-using Content.Shared.Chemistry;
+using Content.Server.Atmos.Components;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Chemistry.Solution;
using JetBrains.Annotations;
diff --git a/Content.Server/Chemistry/ReagentEntityReactions/WashCreamPieReaction.cs b/Content.Server/Chemistry/ReagentEntityReactions/WashCreamPieReaction.cs
index 97b258c8d1..44774ffcc9 100644
--- a/Content.Server/Chemistry/ReagentEntityReactions/WashCreamPieReaction.cs
+++ b/Content.Server/Chemistry/ReagentEntityReactions/WashCreamPieReaction.cs
@@ -1,6 +1,5 @@
using System.Collections.Generic;
using Content.Server.Nutrition.Components;
-using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Chemistry.Solution;
using JetBrains.Annotations;
diff --git a/Content.Server/Clothing/Components/ClothingComponent.cs b/Content.Server/Clothing/Components/ClothingComponent.cs
index a3281287f4..04f8520538 100644
--- a/Content.Server/Clothing/Components/ClothingComponent.cs
+++ b/Content.Server/Clothing/Components/ClothingComponent.cs
@@ -5,7 +5,6 @@ using Content.Shared.Clothing;
using Content.Shared.Interaction;
using Content.Shared.Item;
using Content.Shared.NetIDs;
-using Content.Shared.Notification;
using Content.Shared.Notification.Managers;
using Robust.Shared.GameObjects;
using Robust.Shared.Players;
diff --git a/Content.Server/Clothing/Components/MagbootsComponent.cs b/Content.Server/Clothing/Components/MagbootsComponent.cs
index f4dd5c8012..9101646f88 100644
--- a/Content.Server/Clothing/Components/MagbootsComponent.cs
+++ b/Content.Server/Clothing/Components/MagbootsComponent.cs
@@ -1,6 +1,6 @@
#nullable enable
using Content.Server.Alert;
-using Content.Server.GameObjects.Components.Atmos;
+using Content.Server.Atmos.Components;
using Content.Server.Inventory.Components;
using Content.Server.Items;
using Content.Shared.ActionBlocker;
@@ -10,7 +10,6 @@ using Content.Shared.Actions.Components;
using Content.Shared.Alert;
using Content.Shared.Clothing;
using Content.Shared.Interaction;
-using Content.Shared.Interaction.Events;
using Content.Shared.Inventory;
using Content.Shared.Verbs;
using JetBrains.Annotations;
diff --git a/Content.Server/Commands/Atmos/AddAtmosCommand.cs b/Content.Server/Commands/Atmos/AddAtmosCommand.cs
index 5605bb7320..5afc24057b 100644
--- a/Content.Server/Commands/Atmos/AddAtmosCommand.cs
+++ b/Content.Server/Commands/Atmos/AddAtmosCommand.cs
@@ -1,7 +1,6 @@
#nullable enable
using Content.Server.Administration;
-using Content.Server.Atmos;
-using Content.Server.GameObjects.Components.Atmos;
+using Content.Server.Atmos.Components;
using Content.Shared.Administration;
using Robust.Shared.Console;
using Robust.Shared.GameObjects;
diff --git a/Content.Server/Commands/Atmos/AddGasCommand.cs b/Content.Server/Commands/Atmos/AddGasCommand.cs
index ed582e8087..b745caf81a 100644
--- a/Content.Server/Commands/Atmos/AddGasCommand.cs
+++ b/Content.Server/Commands/Atmos/AddGasCommand.cs
@@ -1,6 +1,6 @@
#nullable enable
using Content.Server.Administration;
-using Content.Server.GameObjects.Components.Atmos;
+using Content.Server.Atmos.Components;
using Content.Shared.Administration;
using Content.Shared.Atmos;
using Robust.Shared.Console;
diff --git a/Content.Server/Commands/Atmos/AddUnsimulatedAtmosCommand.cs b/Content.Server/Commands/Atmos/AddUnsimulatedAtmosCommand.cs
index 2bee55935f..94c0e73e09 100644
--- a/Content.Server/Commands/Atmos/AddUnsimulatedAtmosCommand.cs
+++ b/Content.Server/Commands/Atmos/AddUnsimulatedAtmosCommand.cs
@@ -1,7 +1,6 @@
#nullable enable
using Content.Server.Administration;
-using Content.Server.Atmos;
-using Content.Server.GameObjects.Components.Atmos;
+using Content.Server.Atmos.Components;
using Content.Shared.Administration;
using Robust.Shared.Console;
using Robust.Shared.GameObjects;
diff --git a/Content.Server/Commands/Atmos/DeleteGasCommand.cs b/Content.Server/Commands/Atmos/DeleteGasCommand.cs
index d2ba43e381..2f03714c37 100644
--- a/Content.Server/Commands/Atmos/DeleteGasCommand.cs
+++ b/Content.Server/Commands/Atmos/DeleteGasCommand.cs
@@ -1,7 +1,7 @@
#nullable enable
using System;
using Content.Server.Administration;
-using Content.Server.GameObjects.Components.Atmos;
+using Content.Server.Atmos.Components;
using Content.Shared.Administration;
using Content.Shared.Atmos;
using Robust.Server.Player;
diff --git a/Content.Server/Commands/Atmos/FillGasCommand.cs b/Content.Server/Commands/Atmos/FillGasCommand.cs
index 2fa9768959..604f1f0165 100644
--- a/Content.Server/Commands/Atmos/FillGasCommand.cs
+++ b/Content.Server/Commands/Atmos/FillGasCommand.cs
@@ -1,7 +1,6 @@
#nullable enable
using Content.Server.Administration;
-using Content.Server.Atmos;
-using Content.Server.GameObjects.Components.Atmos;
+using Content.Server.Atmos.Components;
using Content.Shared.Administration;
using Content.Shared.Atmos;
using Robust.Shared.Console;
diff --git a/Content.Server/Commands/Atmos/FixGridAtmos.cs b/Content.Server/Commands/Atmos/FixGridAtmos.cs
index 01ead99b72..0a2885088e 100644
--- a/Content.Server/Commands/Atmos/FixGridAtmos.cs
+++ b/Content.Server/Commands/Atmos/FixGridAtmos.cs
@@ -1,7 +1,7 @@
#nullable enable
using Content.Server.Administration;
using Content.Server.Atmos;
-using Content.Server.GameObjects.Components.Atmos;
+using Content.Server.Atmos.Components;
using Content.Shared.Administration;
using Content.Shared.Atmos;
using Robust.Shared.Console;
diff --git a/Content.Server/Commands/Atmos/ListGasesCommand.cs b/Content.Server/Commands/Atmos/ListGasesCommand.cs
index fb909275d9..9b90a51755 100644
--- a/Content.Server/Commands/Atmos/ListGasesCommand.cs
+++ b/Content.Server/Commands/Atmos/ListGasesCommand.cs
@@ -1,6 +1,6 @@
#nullable enable
using Content.Server.Administration;
-using Content.Server.GameObjects.EntitySystems;
+using Content.Server.Atmos.EntitySystems;
using Content.Shared.Administration;
using Robust.Shared.Console;
using Robust.Shared.GameObjects;
diff --git a/Content.Server/Commands/Atmos/RemoveGasCommand.cs b/Content.Server/Commands/Atmos/RemoveGasCommand.cs
index 5935ef80b2..a421bf0f35 100644
--- a/Content.Server/Commands/Atmos/RemoveGasCommand.cs
+++ b/Content.Server/Commands/Atmos/RemoveGasCommand.cs
@@ -1,6 +1,6 @@
#nullable enable
using Content.Server.Administration;
-using Content.Server.GameObjects.Components.Atmos;
+using Content.Server.Atmos.Components;
using Content.Shared.Administration;
using Robust.Shared.Console;
using Robust.Shared.GameObjects;
diff --git a/Content.Server/Commands/Atmos/SetAtmosTemperatureCommand.cs b/Content.Server/Commands/Atmos/SetAtmosTemperatureCommand.cs
index ddcd587641..660173b566 100644
--- a/Content.Server/Commands/Atmos/SetAtmosTemperatureCommand.cs
+++ b/Content.Server/Commands/Atmos/SetAtmosTemperatureCommand.cs
@@ -1,6 +1,6 @@
#nullable enable
using Content.Server.Administration;
-using Content.Server.GameObjects.Components.Atmos;
+using Content.Server.Atmos.Components;
using Content.Shared.Administration;
using Content.Shared.Atmos;
using Robust.Shared.Console;
diff --git a/Content.Server/Commands/Atmos/SetTemperatureCommand.cs b/Content.Server/Commands/Atmos/SetTemperatureCommand.cs
index e271d51764..792ea8c9ce 100644
--- a/Content.Server/Commands/Atmos/SetTemperatureCommand.cs
+++ b/Content.Server/Commands/Atmos/SetTemperatureCommand.cs
@@ -1,6 +1,6 @@
#nullable enable
using Content.Server.Administration;
-using Content.Server.GameObjects.Components.Atmos;
+using Content.Server.Atmos.Components;
using Content.Shared.Administration;
using Content.Shared.Atmos;
using Robust.Shared.Console;
diff --git a/Content.Server/Commands/Atmos/ShowAtmosCommand.cs b/Content.Server/Commands/Atmos/ShowAtmosCommand.cs
index 73d61243aa..35bbf3fc29 100644
--- a/Content.Server/Commands/Atmos/ShowAtmosCommand.cs
+++ b/Content.Server/Commands/Atmos/ShowAtmosCommand.cs
@@ -1,6 +1,6 @@
#nullable enable
using Content.Server.Administration;
-using Content.Server.GameObjects.EntitySystems.Atmos;
+using Content.Server.Atmos.EntitySystems;
using Content.Shared.Administration;
using Robust.Server.Player;
using Robust.Shared.Console;
diff --git a/Content.Server/Construction/Completions/SetStackCount.cs b/Content.Server/Construction/Completions/SetStackCount.cs
index 888f927fae..7934d6c967 100644
--- a/Content.Server/Construction/Completions/SetStackCount.cs
+++ b/Content.Server/Construction/Completions/SetStackCount.cs
@@ -1,13 +1,9 @@
#nullable enable
-using System;
using System.Threading.Tasks;
using Content.Server.Stack;
using Content.Shared.Construction;
-using Content.Shared.GameObjects.EntitySystems;
-using Content.Shared.Stacks;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
-using Robust.Shared.Log;
using Robust.Shared.Serialization.Manager.Attributes;
namespace Content.Server.Construction.Completions
diff --git a/Content.Server/Construction/Completions/SpawnPrototype.cs b/Content.Server/Construction/Completions/SpawnPrototype.cs
index 5377d22c08..e490b73ea6 100644
--- a/Content.Server/Construction/Completions/SpawnPrototype.cs
+++ b/Content.Server/Construction/Completions/SpawnPrototype.cs
@@ -1,11 +1,8 @@
#nullable enable
-using System;
using System.Threading.Tasks;
using Content.Server.Stack;
using Content.Shared.Construction;
-using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Prototypes;
-using Content.Shared.Stacks;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
diff --git a/Content.Server/Construction/Components/MachineComponent.cs b/Content.Server/Construction/Components/MachineComponent.cs
index 28c49906b4..ee2b274dae 100644
--- a/Content.Server/Construction/Components/MachineComponent.cs
+++ b/Content.Server/Construction/Components/MachineComponent.cs
@@ -121,6 +121,7 @@ namespace Content.Server.Construction.Components
public void MapInit()
{
CreateBoardAndStockParts();
+ RefreshParts();
}
}
}
diff --git a/Content.Server/Conveyor/ConveyorComponent.cs b/Content.Server/Conveyor/ConveyorComponent.cs
index 1cd3e32696..55e8465154 100644
--- a/Content.Server/Conveyor/ConveyorComponent.cs
+++ b/Content.Server/Conveyor/ConveyorComponent.cs
@@ -26,7 +26,7 @@ namespace Content.Server.Conveyor
///
[ViewVariables(VVAccess.ReadWrite)]
[DataField("angle")]
- private Angle _angle;
+ private Angle _angle = Angle.Zero;
public float Speed => _speed;
diff --git a/Content.Server/Damage/GodmodeSystem.cs b/Content.Server/Damage/GodmodeSystem.cs
index 08f9fc0fc4..b3ddb7dd39 100644
--- a/Content.Server/Damage/GodmodeSystem.cs
+++ b/Content.Server/Damage/GodmodeSystem.cs
@@ -1,7 +1,7 @@
#nullable enable
using System.Collections.Generic;
+using Content.Server.Atmos.Components;
using System.Linq;
-using Content.Server.GameObjects.Components.Atmos;
using Content.Shared.Damage;
using Content.Shared.Damage.Components;
using Content.Shared.Damage.Resistances;
diff --git a/Content.Server/Damage/RejuvenateVerb.cs b/Content.Server/Damage/RejuvenateVerb.cs
index 68a68cdcd5..c5845fffa1 100644
--- a/Content.Server/Damage/RejuvenateVerb.cs
+++ b/Content.Server/Damage/RejuvenateVerb.cs
@@ -1,4 +1,4 @@
-using Content.Server.GameObjects.Components.Atmos;
+using Content.Server.Atmos.Components;
using Content.Server.Nutrition.Components;
using Content.Server.Stunnable.Components;
using Content.Shared.Damage.Components;
diff --git a/Content.Server/Disposal/Unit/Components/DisposalUnitComponent.cs b/Content.Server/Disposal/Unit/Components/DisposalUnitComponent.cs
index 0c292a5042..b73019adc1 100644
--- a/Content.Server/Disposal/Unit/Components/DisposalUnitComponent.cs
+++ b/Content.Server/Disposal/Unit/Components/DisposalUnitComponent.cs
@@ -6,9 +6,9 @@ using System.Threading;
using System.Threading.Tasks;
using Content.Server.Anchor;
using Content.Server.Atmos;
+using Content.Server.Atmos.EntitySystems;
using Content.Server.Disposal.Tube.Components;
using Content.Server.DoAfter;
-using Content.Server.GameObjects.EntitySystems;
using Content.Server.Hands.Components;
using Content.Server.Interfaces;
using Content.Server.Power.Components;
@@ -19,7 +19,6 @@ using Content.Shared.Disposal.Components;
using Content.Shared.DragDrop;
using Content.Shared.Interaction;
using Content.Shared.Movement;
-using Content.Shared.Notification;
using Content.Shared.Notification.Managers;
using Content.Shared.Throwing;
using Content.Shared.Verbs;
diff --git a/Content.Server/Doors/Components/ServerDoorComponent.cs b/Content.Server/Doors/Components/ServerDoorComponent.cs
index fc3d35bdb1..e368f04738 100644
--- a/Content.Server/Doors/Components/ServerDoorComponent.cs
+++ b/Content.Server/Doors/Components/ServerDoorComponent.cs
@@ -5,8 +5,8 @@ using System.Threading;
using System.Threading.Tasks;
using Content.Server.Access;
using Content.Server.Access.Components;
+using Content.Server.Atmos.Components;
using Content.Server.Construction.Components;
-using Content.Server.GameObjects.Components.Atmos;
using Content.Server.Hands.Components;
using Content.Server.Stunnable.Components;
using Content.Server.Tools.Components;
diff --git a/Content.Server/GameObjects/Components/Atmos/GasCanisterComponent.cs b/Content.Server/GameObjects/Components/Atmos/GasCanisterComponent.cs
deleted file mode 100644
index 7219af5b14..0000000000
--- a/Content.Server/GameObjects/Components/Atmos/GasCanisterComponent.cs
+++ /dev/null
@@ -1,320 +0,0 @@
-#nullable enable
-using System;
-using System.Linq;
-using Content.Server.Atmos;
-using Content.Server.GameObjects.Components.Atmos.Piping;
-using Content.Server.Interfaces;
-using Content.Server.UserInterface;
-using Content.Shared.ActionBlocker;
-using Content.Shared.Atmos;
-using Content.Shared.GameObjects.Components.Atmos;
-using Content.Shared.Interaction;
-using Content.Shared.Interaction.Events;
-using Robust.Server.GameObjects;
-using Robust.Shared.GameObjects;
-using Robust.Shared.IoC;
-using Robust.Shared.Map;
-using Robust.Shared.Physics;
-using Robust.Shared.Serialization.Manager.Attributes;
-using Robust.Shared.ViewVariables;
-
-namespace Content.Server.GameObjects.Components.Atmos
-{
- ///
- /// Component that manages gas mixtures temperature, pressure and output.
- ///
- [RegisterComponent]
- [ComponentReference(typeof(IActivate))]
- public class GasCanisterComponent : Component, IGasMixtureHolder, IActivate
- {
- [Dependency] private readonly IMapManager _mapManager = default!;
-
- public override string Name => "GasCanister";
-
- private const int MaxLabelLength = 32;
-
- [ViewVariables(VVAccess.ReadWrite)]
- public string Label { get; set; } = "Gas Canister";
-
- [ViewVariables(VVAccess.ReadWrite)]
- public bool ValveOpened { get; set; } = false;
-
- ///
- /// What the canister contains.
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("gasMixture")]
- public GasMixture Air { get; set; } = new (DefaultVolume);
-
- [ViewVariables]
- public bool Anchored => !Owner.TryGetComponent(out var physics) || physics.BodyType == BodyType.Static;
-
- ///
- /// The floor connector port that the canister is attached to.
- ///
- [ViewVariables]
- public GasCanisterPortComponent? ConnectedPort { get; private set; }
-
- [ViewVariables]
- public bool ConnectedToPort => ConnectedPort != null;
-
- public const float DefaultVolume = 10;
-
- [ViewVariables(VVAccess.ReadWrite)] public float ReleasePressure { get; set; }
-
- ///
- /// The user interface bound to the canister.
- ///
- private BoundUserInterface? UserInterface => Owner.GetUIOrNull(SharedGasCanisterComponent.GasCanisterUiKey.Key);
-
- ///
- /// Stores the last ui state after it's been casted into
- ///
- private GasCanisterBoundUserInterfaceState? _lastUiState;
-
- private AppearanceComponent? _appearance;
-
- public override void Initialize()
- {
- base.Initialize();
- if (Owner.TryGetComponent(out var physics))
- {
- AnchorUpdate();
- }
- if (UserInterface != null)
- {
- UserInterface.OnReceiveMessage += OnUiReceiveMessage;
- }
-
- // Init some variables
- Label = Owner.Name;
- Owner.TryGetComponent(out _appearance);
-
- UpdateUserInterface();
- UpdateAppearance();
- }
-
- #region Connector port methods
-
- public override void OnRemove()
- {
- base.OnRemove();
- if (UserInterface != null)
- {
- UserInterface.OnReceiveMessage -= OnUiReceiveMessage;
- }
- DisconnectFromPort();
- }
-
- public void TryConnectToPort()
- {
- if (!Owner.Transform.Anchored) return;
- var grid = _mapManager.GetGrid(Owner.Transform.GridID);
- var coords = Owner.Transform.Coordinates;
- var port = grid.GetLocal(coords)
- .Select(entity => Owner.EntityManager.ComponentManager.TryGetComponent(entity, out var port) ? port : null)
- .Where(port => port != null)
- .Where(port => !port!.ConnectedToCanister)
- .FirstOrDefault();
- if (port == null) return;
- ConnectedPort = port;
- ConnectedPort.ConnectGasCanister(this);
- }
-
-
- public void DisconnectFromPort()
- {
- ConnectedPort?.DisconnectGasCanister();
- ConnectedPort = null;
- }
-
- public void AnchorUpdate()
- {
- if (Anchored)
- {
- TryConnectToPort();
- }
- else
- {
- DisconnectFromPort();
- }
- UpdateAppearance();
- }
-
- #endregion
-
- void IActivate.Activate(ActivateEventArgs eventArgs)
- {
- if (!eventArgs.User.TryGetComponent(out ActorComponent? actor))
- return;
-
- UserInterface?.Open(actor.PlayerSession);
- }
-
- private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj)
- {
- if (obj.Session.AttachedEntity == null)
- {
- return;
- }
-
- if (!PlayerCanUse(obj.Session.AttachedEntity))
- {
- return;
- }
-
- // If the label has been changed by a client
- if (obj.Message is CanisterLabelChangedMessage canLabelMessage)
- {
- var newLabel = canLabelMessage.NewLabel;
- if (newLabel.Length > MaxLabelLength)
- newLabel = newLabel.Substring(0, MaxLabelLength);
- Label = newLabel;
- Owner.Name = Label;
- UpdateUserInterface();
- return;
- }
-
- // If the release pressure has been adjusted by the client on the gas canister
- if (obj.Message is ReleasePressureButtonPressedMessage rPMessage)
- {
- ReleasePressure += rPMessage.ReleasePressure;
- ReleasePressure = Math.Clamp(ReleasePressure, 0, 1000);
- ReleasePressure = MathF.Round(ReleasePressure, 2);
- UpdateUserInterface();
- return;
- }
-
-
- if (obj.Message is UiButtonPressedMessage btnPressedMessage)
- {
- switch (btnPressedMessage.Button)
- {
- case UiButton.ValveToggle:
- ToggleValve();
- break;
- }
- }
- }
-
- ///
- /// Update the user interface if relevant
- ///
- private void UpdateUserInterface()
- {
- var state = GetUserInterfaceState();
-
- if (_lastUiState != null && _lastUiState.Equals(state))
- {
- return;
- }
-
- _lastUiState = state;
- UserInterface?.SetState(state);
- }
-
- ///
- /// Update the canister's sprite
- ///
- private void UpdateAppearance()
- {
- _appearance?.SetData(GasCanisterVisuals.ConnectedState, ConnectedToPort);
- // The Eris canisters are being used, so best to use the Eris light logic unless someone else has a better idea.
- // https://github.com/discordia-space/CEV-Eris/blob/fdd6ee7012f46838a6711adb1737cd90c48ae448/code/game/machinery/atmoalter/canister.dm#L129
- if (Air.Pressure < 10)
- {
- _appearance?.SetData(GasCanisterVisuals.PressureState, 0);
- }
- else if (Air.Pressure < Atmospherics.OneAtmosphere)
- {
- _appearance?.SetData(GasCanisterVisuals.PressureState, 1);
- }
- else if (Air.Pressure < (15 * Atmospherics.OneAtmosphere))
- {
- _appearance?.SetData(GasCanisterVisuals.PressureState, 2);
- }
- else
- {
- _appearance?.SetData(GasCanisterVisuals.PressureState, 3);
- }
- }
-
- ///
- /// Get the current interface state from server data
- ///
- /// The state
- private GasCanisterBoundUserInterfaceState GetUserInterfaceState()
- {
- // We round the pressure for ease of reading
- return new GasCanisterBoundUserInterfaceState(Label,
- MathF.Round(Air.Pressure, 2),
- ReleasePressure,
- ValveOpened);
- }
-
- public void AirWasUpdated()
- {
- UpdateUserInterface();
- UpdateAppearance();
- }
-
- #region Check methods
-
- private bool PlayerCanUse(IEntity? player)
- {
- if (player == null)
- {
- return false;
- }
-
- var actionBlocker = EntitySystem.Get();
-
- if (!actionBlocker.CanInteract(player) ||
- !actionBlocker.CanUse(player))
- {
- return false;
- }
-
- return true;
- }
-
- #endregion
-
-
- ///
- /// Called when the canister's valve is toggled
- ///
- private void ToggleValve()
- {
- ValveOpened = !ValveOpened;
- UpdateUserInterface();
- }
-
- ///
- /// Called every frame
- ///
- ///
- public void Update(in float frameTime)
- {
- if (ValveOpened)
- {
- var tileAtmosphere = Owner.Transform.Coordinates.GetTileAtmosphere();
- if (tileAtmosphere != null)
- {
- // If tileAtmosphere.Air is null, then we're airblocked, so DON'T release
- if (tileAtmosphere.Air != null)
- {
- Air.ReleaseGasTo(tileAtmosphere.Air, ReleasePressure);
- tileAtmosphere.Invalidate();
- }
- }
- else
- {
- Air.ReleaseGasTo(null, ReleasePressure);
- }
-
- AirWasUpdated();
- }
- }
- }
-}
diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/GasCanisterPortComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/GasCanisterPortComponent.cs
deleted file mode 100644
index deadca50a4..0000000000
--- a/Content.Server/GameObjects/Components/Atmos/Piping/GasCanisterPortComponent.cs
+++ /dev/null
@@ -1,102 +0,0 @@
-#nullable enable
-using System.Collections.Generic;
-using System.Linq;
-using Content.Server.NodeContainer;
-using Content.Server.NodeContainer.Nodes;
-using Robust.Shared.GameObjects;
-using Robust.Shared.IoC;
-using Robust.Shared.Log;
-using Robust.Shared.Map;
-using Robust.Shared.ViewVariables;
-
-namespace Content.Server.GameObjects.Components.Atmos.Piping
-{
- [RegisterComponent]
- public class GasCanisterPortComponent : Component
- {
- public override string Name => "GasCanisterPort";
-
- [Dependency] private readonly IMapManager _mapManager = default!;
-
- [ViewVariables]
- public GasCanisterComponent? ConnectedCanister { get; private set; }
-
- [ViewVariables]
- public bool ConnectedToCanister => ConnectedCanister != null;
-
- [ViewVariables]
- private PipeNode? _gasPort;
-
- public override void Initialize()
- {
- base.Initialize();
- Owner.EnsureComponentWarn();
- SetGasPort();
- if (Owner.Transform.Anchored)
- {
- var grid = _mapManager.GetGrid(Owner.Transform.GridID);
- var coords = Owner.Transform.Coordinates;
- var entities = grid.GetLocal(coords);
- foreach (var entity in entities)
- {
- if (Owner.EntityManager.ComponentManager.TryGetComponent(entity, out var canister) && canister.Anchored && !canister.ConnectedToPort)
- {
- canister.TryConnectToPort();
- break;
- }
- }
- }
- }
-
- public override void OnRemove()
- {
- base.OnRemove();
- ConnectedCanister?.DisconnectFromPort();
- }
-
- public override void HandleMessage(ComponentMessage message, IComponent? component)
- {
- base.HandleMessage(message, component);
- switch (message)
- {
- case PipeNetUpdateMessage:
- Update();
- break;
- }
- }
-
- public void Update()
- {
- if (_gasPort == null || ConnectedCanister == null)
- return;
-
- ConnectedCanister.Air.Share(_gasPort.Air, 1);
- ConnectedCanister.AirWasUpdated();
- }
-
- public void ConnectGasCanister(GasCanisterComponent gasCanister)
- {
- ConnectedCanister = gasCanister;
- }
-
- public void DisconnectGasCanister()
- {
- ConnectedCanister = null;
- }
-
- private void SetGasPort()
- {
- if (!Owner.TryGetComponent(out var container))
- {
- Logger.Warning($"{nameof(GasCanisterPortComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} did not have a {nameof(NodeContainerComponent)}.");
- return;
- }
- _gasPort = container.Nodes.OfType().FirstOrDefault();
- if (_gasPort == null)
- {
- Logger.Warning($"{nameof(GasCanisterPortComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}.");
- return;
- }
- }
- }
-}
diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/GasFilterComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/GasFilterComponent.cs
deleted file mode 100644
index ed6fbddf64..0000000000
--- a/Content.Server/GameObjects/Components/Atmos/Piping/GasFilterComponent.cs
+++ /dev/null
@@ -1,170 +0,0 @@
-#nullable enable
-using System;
-using System.Linq;
-using Content.Server.Atmos;
-using Content.Server.NodeContainer;
-using Content.Server.NodeContainer.Nodes;
-using Content.Shared.Atmos;
-using Content.Shared.GameObjects.Components.Atmos;
-using Robust.Server.GameObjects;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Log;
-using Robust.Shared.Serialization.Manager.Attributes;
-using Robust.Shared.ViewVariables;
-
-namespace Content.Server.GameObjects.Components.Atmos.Piping
-{
- [RegisterComponent]
- public class GasFilterComponent : Component
- {
- public override string Name => "GasFilter";
-
- ///
- /// If the filter is currently filtering.
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- public bool FilterEnabled
- {
- get => _filterEnabled;
- set
- {
- _filterEnabled = value;
- UpdateAppearance();
- }
- }
- private bool _filterEnabled;
-
- [ViewVariables(VVAccess.ReadWrite)]
- public Gas GasToFilter
- {
- get => _gasToFilter;
- set
- {
- _gasToFilter = value;
- UpdateAppearance();
- }
- }
-
- [DataField("gasToFilter")] private Gas _gasToFilter = Gas.Plasma;
-
- [ViewVariables(VVAccess.ReadWrite)]
- public int VolumeFilterRate
- {
- get => _volumeFilterRate;
- set => _volumeFilterRate = Math.Clamp(value, 0, MaxVolumeFilterRate);
- }
-
- [DataField("startingVolumePumpRate")]
- private int _volumeFilterRate;
-
- [ViewVariables(VVAccess.ReadWrite)]
- public int MaxVolumeFilterRate
- {
- get => _maxVolumeFilterRate;
- set => Math.Max(value, 0);
- }
-
- [DataField("maxVolumePumpRate")] private int _maxVolumeFilterRate = 100;
-
- [DataField("inletDirection")] [ViewVariables]
- private PipeDirection _initialInletDirection = PipeDirection.None;
-
- ///
- /// The direction the filtered-out gas goes.
- ///
- [DataField("filterOutletDirection")] [ViewVariables]
- private PipeDirection _initialFilterOutletDirection = PipeDirection.None;
-
- ///
- /// The direction the rest of the gas goes.
- ///
- [DataField("outletDirection")] [ViewVariables]
- private PipeDirection _initialOutletDirection = PipeDirection.None;
-
- [ViewVariables]
- private PipeNode? _inletPipe;
-
- [ViewVariables]
- private PipeNode? _filterOutletPipe;
-
- [ViewVariables]
- private PipeNode? _outletPipe;
-
- [ComponentDependency]
- private readonly AppearanceComponent? _appearance = default;
-
- public override void Initialize()
- {
- base.Initialize();
- Owner.EnsureComponent();
- SetPipes();
- UpdateAppearance();
- }
-
- public override void HandleMessage(ComponentMessage message, IComponent? component)
- {
- base.HandleMessage(message, component);
- switch (message)
- {
- case PipeNetUpdateMessage:
- Update();
- break;
- }
- }
-
- public void Update()
- {
- if (!FilterEnabled)
- return;
-
- if (_inletPipe == null || _inletPipe.Air == null ||
- _filterOutletPipe == null || _filterOutletPipe.Air == null ||
- _outletPipe == null || _outletPipe.Air == null)
- return;
-
- FilterGas(_inletPipe.Air, _filterOutletPipe.Air, _outletPipe.Air);
- }
-
- private void FilterGas(GasMixture inletGas, GasMixture filterOutletGas, GasMixture outletGas)
- {
- var volumeRatio = Math.Clamp(VolumeFilterRate / inletGas.Volume, 0, 1);
- var gas = inletGas.RemoveRatio(volumeRatio);
-
- var molesToSeperate = gas.GetMoles(GasToFilter);
- gas.SetMoles(GasToFilter, 0);
- filterOutletGas.AdjustMoles(GasToFilter, molesToSeperate);
-
- outletGas.Merge(gas);
- }
-
- private void UpdateAppearance()
- {
- _appearance?.SetData(FilterVisuals.VisualState, new FilterVisualState(FilterEnabled));
- }
-
- private void SetPipes()
- {
- _inletPipe = null;
- _filterOutletPipe = null;
- _outletPipe = null;
-
- if (!Owner.TryGetComponent(out var container))
- {
- Logger.Warning($"{typeof(GasFilterComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} did not have a {nameof(NodeContainerComponent)}.");
- return;
- }
-
- var pipeNodes = container.Nodes.OfType();
-
- _inletPipe = pipeNodes.Where(pipe => pipe.PipeDirection == _initialInletDirection).FirstOrDefault();
- _filterOutletPipe = pipeNodes.Where(pipe => pipe.PipeDirection == _initialFilterOutletDirection).FirstOrDefault();
- _outletPipe = pipeNodes.Where(pipe => pipe.PipeDirection == _initialOutletDirection).FirstOrDefault();
-
- if (_inletPipe == null || _filterOutletPipe == null || _outletPipe == null)
- {
- Logger.Warning($"{nameof(GasFilterComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}.");
- return;
- }
- }
- }
-}
diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/GasGeneratorComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/GasGeneratorComponent.cs
deleted file mode 100644
index de4fa9ad35..0000000000
--- a/Content.Server/GameObjects/Components/Atmos/Piping/GasGeneratorComponent.cs
+++ /dev/null
@@ -1,99 +0,0 @@
-#nullable enable
-using System.Linq;
-using Content.Server.NodeContainer;
-using Content.Server.NodeContainer.Nodes;
-using Content.Shared.Atmos;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Log;
-using Robust.Shared.Serialization.Manager.Attributes;
-using Robust.Shared.ViewVariables;
-
-namespace Content.Server.GameObjects.Components.Atmos.Piping
-{
- ///
- /// Generates gas in the attached pipe.
- ///
- [RegisterComponent]
- public class GasGeneratorComponent : Component
- {
- public override string Name => "GasGenerator";
-
- ///
- /// If the generator is producing gas.
- ///
- [DataField("generatorEnabled")]
- [ViewVariables(VVAccess.ReadWrite)]
- public bool GeneratorEnabled { get; set; } = true;
-
- ///
- /// What gas is being generated.
- ///
- [DataField("generatedGas")]
- [ViewVariables(VVAccess.ReadWrite)]
- public Gas GeneratedGas { get; set; } = Gas.Oxygen;
-
- ///
- /// Molar rate of gas generation.
- ///
- [DataField("gasGenerationRate")]
- [ViewVariables(VVAccess.ReadWrite)]
- public float GasGenerationRate { get; set; } = 10;
-
- ///
- /// The pipe pressure above which the generator stops producing gas.
- ///
- [DataField("generatorPressureCap")]
- [ViewVariables(VVAccess.ReadWrite)]
- public float GeneratorPressureCap { get; set; } = 10;
-
- ///
- /// The pipe to which generated gas is added.
- ///
- [ViewVariables]
- private PipeNode? Pipe { get; set; }
-
- public override void Initialize()
- {
- base.Initialize();
- Owner.EnsureComponentWarn();
- SetPipes();
- }
-
- public override void HandleMessage(ComponentMessage message, IComponent? component)
- {
- base.HandleMessage(message, component);
- switch (message)
- {
- case PipeNetUpdateMessage:
- Update();
- break;
- }
- }
-
- private void Update()
- {
- if (!GeneratorEnabled)
- return;
-
- if (Pipe == null || Pipe.Air.Pressure > GeneratorPressureCap)
- return;
-
- Pipe.Air.AdjustMoles(GeneratedGas, GasGenerationRate);
- }
-
- private void SetPipes()
- {
- if (!Owner.TryGetComponent(out var container))
- {
- Logger.Warning($"{nameof(GasGeneratorComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} did not have a {nameof(NodeContainerComponent)}.");
- return;
- }
- Pipe = container.Nodes.OfType().FirstOrDefault();
- if (Pipe == null)
- {
- Logger.Warning($"{nameof(GasGeneratorComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}.");
- return;
- }
- }
- }
-}
diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/PipeHeaterComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/PipeHeaterComponent.cs
deleted file mode 100644
index 14ccd7fb75..0000000000
--- a/Content.Server/GameObjects/Components/Atmos/Piping/PipeHeaterComponent.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-#nullable enable
-using System.Linq;
-using Content.Server.NodeContainer;
-using Content.Server.NodeContainer.Nodes;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Log;
-using Robust.Shared.ViewVariables;
-
-namespace Content.Server.GameObjects.Components.Atmos.Piping
-{
- ///
- /// Placeholder component for adjusting the temperature of gas in pipes.
- ///
- [RegisterComponent]
- public class PipeHeaterComponent : Component
- {
- public override string Name => "PipeHeater";
-
- [ViewVariables]
- private PipeNode? _heaterPipe;
-
- [ViewVariables(VVAccess.ReadWrite)]
- private float TargetTemperature { get; set; }
-
- public override void Initialize()
- {
- base.Initialize();
- Owner.EnsureComponentWarn();
- SetPipe();
- }
-
- public override void HandleMessage(ComponentMessage message, IComponent? component)
- {
- base.HandleMessage(message, component);
- switch (message)
- {
- case PipeNetUpdateMessage:
- Update();
- break;
- }
- }
-
- public void Update()
- {
- if (_heaterPipe == null)
- return;
-
- _heaterPipe.Air.Temperature = TargetTemperature;
- }
-
- private void SetPipe()
- {
- if (!Owner.TryGetComponent(out var container))
- {
- Logger.Warning($"{nameof(PipeHeaterComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} did not have a {nameof(NodeContainerComponent)}.");
- return;
- }
- _heaterPipe = container.Nodes.OfType().FirstOrDefault();
- if (_heaterPipe == null)
- {
- Logger.Warning($"{nameof(PipeHeaterComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}.");
- return;
- }
- }
- }
-}
diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/PipeNetDeviceComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/PipeNetDeviceComponent.cs
deleted file mode 100644
index bb54fab26d..0000000000
--- a/Content.Server/GameObjects/Components/Atmos/Piping/PipeNetDeviceComponent.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-#nullable enable
-using Content.Server.Atmos;
-using Content.Server.GameObjects.EntitySystems;
-using Robust.Shared.GameObjects;
-
-namespace Content.Server.GameObjects.Components.Atmos.Piping
-{
- ///
- /// Adds itself to a to be updated by.
- /// TODO: Make compatible with unanchoring/anchoring. Currently assumes that the Owner does not move.
- ///
- [RegisterComponent]
- public class PipeNetDeviceComponent : Component
- {
- public override string Name => "PipeNetDevice";
-
- private IGridAtmosphereComponent? JoinedGridAtmos { get; set; }
-
- private PipeNetUpdateMessage _cachedUpdateMessage = new();
-
- public override void Initialize()
- {
- base.Initialize();
- JoinGridAtmos();
- }
-
- public override void OnRemove()
- {
- base.OnRemove();
- LeaveGridAtmos();
- }
-
- public void Update()
- {
- SendMessage(_cachedUpdateMessage);
- }
-
- private void JoinGridAtmos()
- {
- var gridAtmos = EntitySystem.Get()
- .GetGridAtmosphere(Owner.Transform.Coordinates);
- JoinedGridAtmos = gridAtmos;
- JoinedGridAtmos.AddPipeNetDevice(this);
- }
-
- private void LeaveGridAtmos()
- {
- JoinedGridAtmos?.RemovePipeNetDevice(this);
- JoinedGridAtmos = null;
- }
- }
-
- public class PipeNetUpdateMessage : ComponentMessage
- {
-
- }
-}
diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/BasePumpComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/BasePumpComponent.cs
deleted file mode 100644
index b1cefc91a3..0000000000
--- a/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/BasePumpComponent.cs
+++ /dev/null
@@ -1,124 +0,0 @@
-#nullable enable
-using System.Linq;
-using Content.Server.Atmos;
-using Content.Server.NodeContainer;
-using Content.Server.NodeContainer.Nodes;
-using Content.Shared.GameObjects.Components.Atmos;
-using Content.Shared.Interaction;
-using Robust.Server.GameObjects;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Log;
-using Robust.Shared.Serialization.Manager.Attributes;
-using Robust.Shared.ViewVariables;
-
-namespace Content.Server.GameObjects.Components.Atmos.Piping.Pumps
-{
- ///
- /// Transfer gas from one to another.
- ///
- public abstract class BasePumpComponent : Component, IActivate
- {
- ///
- /// If the pump is currently pumping.
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- public bool PumpEnabled
- {
- get => _pumpEnabled;
- set
- {
- _pumpEnabled = value;
- UpdateAppearance();
- }
- }
-
- [DataField("pumpEnabled")]
- private bool _pumpEnabled;
-
- ///
- /// Needs to be same as that of a on this entity.
- ///
- [ViewVariables]
- [DataField("initialInletDirection", required: true)]
- private PipeDirection _initialInletDirection = PipeDirection.None;
-
- ///
- /// Needs to be same as that of a on this entity.
- ///
- [ViewVariables]
- [DataField("initialOutletDirection", required: true)]
- private PipeDirection _initialOutletDirection = PipeDirection.None;
-
- [ViewVariables]
- private PipeNode? _inletPipe;
-
- [ViewVariables]
- private PipeNode? _outletPipe;
-
- private AppearanceComponent? _appearance;
-
- public override void Initialize()
- {
- base.Initialize();
- Owner.EnsureComponentWarn();
- SetPipes();
- Owner.TryGetComponent(out _appearance);
- UpdateAppearance();
- }
-
- public override void HandleMessage(ComponentMessage message, IComponent? component)
- {
- base.HandleMessage(message, component);
- switch (message)
- {
- case PipeNetUpdateMessage:
- Update();
- break;
- }
- }
-
- public void Update()
- {
- if (!PumpEnabled)
- return;
-
- if (_inletPipe == null || _outletPipe == null)
- return;
-
- PumpGas(_inletPipe.Air, _outletPipe.Air);
- }
-
- protected abstract void PumpGas(GasMixture inletGas, GasMixture outletGas);
-
- private void UpdateAppearance()
- {
- if (_inletPipe == null || _outletPipe == null) return;
- _appearance?.SetData(PumpVisuals.VisualState, new PumpVisualState(_initialInletDirection, _initialOutletDirection, PumpEnabled));
- }
-
- void IActivate.Activate(ActivateEventArgs eventArgs)
- {
- PumpEnabled = !PumpEnabled;
- }
-
- private void SetPipes()
- {
- _inletPipe = null;
- _outletPipe = null;
-
- if (!Owner.TryGetComponent(out var container))
- {
- Logger.Warning($"{nameof(BasePumpComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} did not have a {nameof(NodeContainerComponent)}.");
- return;
- }
- var pipeNodes = container.Nodes.OfType();
- _inletPipe = pipeNodes.Where(pipe => pipe.PipeDirection == _initialInletDirection).FirstOrDefault();
- _outletPipe = pipeNodes.Where(pipe => pipe.PipeDirection == _initialOutletDirection).FirstOrDefault();
- if (_inletPipe == null || _outletPipe == null)
- {
- Logger.Warning($"{nameof(BasePumpComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}.");
- return;
- }
- }
- }
-}
diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/PressurePumpComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/PressurePumpComponent.cs
deleted file mode 100644
index 93dc3eee3f..0000000000
--- a/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/PressurePumpComponent.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-#nullable enable
-using System;
-using Content.Server.Atmos;
-using Content.Shared.Interaction;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization;
-using Robust.Shared.Serialization.Manager.Attributes;
-using Robust.Shared.ViewVariables;
-
-namespace Content.Server.GameObjects.Components.Atmos.Piping.Pumps
-{
- [RegisterComponent]
- [ComponentReference(typeof(BasePumpComponent))]
- [ComponentReference(typeof(IActivate))]
- public class PressurePumpComponent : BasePumpComponent
- {
- public override string Name => "PressurePump";
-
- ///
- /// The pressure this pump will try to bring its oulet too.
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- public int PressurePumpTarget
- {
- get => _pressurePumpTarget;
- set => _pressurePumpTarget = Math.Clamp(value, 0, MaxPressurePumpTarget);
- }
-
- [DataField("startingPressurePumpTarget")]
- private int _pressurePumpTarget;
-
- ///
- /// Max value can be set to.
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- public int MaxPressurePumpTarget
- {
- get => _maxPressurePumpTarget;
- set => Math.Max(value, 0);
- }
- [DataField("maxPressurePumpTarget")]
- private int _maxPressurePumpTarget = 100;
-
- ///
- /// Every update, this pump will only increase the outlet pressure by this fraction of the amount needed to reach the .
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- public float TransferRatio
- {
- get => _transferRatio;
- set => _transferRatio = Math.Clamp(value, 0, 1);
- }
- [DataField("transferRatio")]
- private float _transferRatio = 0.5f;
-
- protected override void PumpGas(GasMixture inletGas, GasMixture outletGas)
- {
- var goalDiff = PressurePumpTarget - outletGas.Pressure;
- var realGoalPressureDiff = goalDiff * TransferRatio;
- var realTargetPressure = outletGas.Pressure + realGoalPressureDiff;
- var realCappedTargetPressure = Math.Max(realTargetPressure, outletGas.Pressure); //no lowering the outlet's pressure
- inletGas.PumpGasTo(outletGas, realCappedTargetPressure);
- }
- }
-}
diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/VolumePumpComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/VolumePumpComponent.cs
deleted file mode 100644
index 68afed389a..0000000000
--- a/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/VolumePumpComponent.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-#nullable enable
-using System;
-using Content.Server.Atmos;
-using Content.Shared.Interaction;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization;
-using Robust.Shared.Serialization.Manager.Attributes;
-using Robust.Shared.ViewVariables;
-
-namespace Content.Server.GameObjects.Components.Atmos.Piping.Pumps
-{
- [RegisterComponent]
- [ComponentReference(typeof(BasePumpComponent))]
- [ComponentReference(typeof(IActivate))]
- public class VolumePumpComponent : BasePumpComponent
- {
- [ViewVariables(VVAccess.ReadWrite)]
- public int VolumePumpRate
- {
- get => _volumePumpRate;
- set => _volumePumpRate = Math.Clamp(value, 0, MaxVolumePumpRate);
- }
- [DataField("startingVolumePumpRate")]
- private int _volumePumpRate;
-
- [ViewVariables(VVAccess.ReadWrite)]
- public int MaxVolumePumpRate
- {
- get => _maxVolumePumpRate;
- set => Math.Max(value, 0);
- }
- [DataField("maxVolumePumpRate")]
- private int _maxVolumePumpRate = 100;
-
- public override string Name => "VolumePump";
-
- protected override void PumpGas(GasMixture inletGas, GasMixture outletGas)
- {
- var volumeRatio = Math.Clamp(VolumePumpRate / inletGas.Volume, 0, 1);
- outletGas.Merge(inletGas.RemoveRatio(volumeRatio));
- }
- }
-}
diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/Scrubbers/BaseSiphonComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/Scrubbers/BaseSiphonComponent.cs
deleted file mode 100644
index 1be82b03af..0000000000
--- a/Content.Server/GameObjects/Components/Atmos/Piping/Scrubbers/BaseSiphonComponent.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-#nullable enable
-using System.Linq;
-using Content.Server.Atmos;
-using Content.Server.GameObjects.EntitySystems;
-using Content.Server.NodeContainer;
-using Content.Server.NodeContainer.Nodes;
-using Content.Shared.GameObjects.Components.Atmos;
-using Robust.Server.GameObjects;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Log;
-using Robust.Shared.ViewVariables;
-
-namespace Content.Server.GameObjects.Components.Atmos.Piping.Scrubbers
-{
- ///
- /// Transfers gas from the tile it is on to a .
- ///
- public abstract class BaseSiphonComponent : Component
- {
-
- [ViewVariables]
- private PipeNode? _scrubberOutlet;
-
- private AtmosphereSystem? _atmosSystem;
-
- [ViewVariables(VVAccess.ReadWrite)]
- public bool SiphonEnabled
- {
- get => _siphonEnabled;
- set
- {
- _siphonEnabled = value;
- UpdateAppearance();
- }
- }
- private bool _siphonEnabled = true;
-
- private AppearanceComponent? _appearance;
-
- public override void Initialize()
- {
- base.Initialize();
- Owner.EnsureComponentWarn();
- _atmosSystem = EntitySystem.Get();
- SetOutlet();
- Owner.TryGetComponent(out _appearance);
- UpdateAppearance();
- }
-
- public override void HandleMessage(ComponentMessage message, IComponent? component)
- {
- base.HandleMessage(message, component);
- switch (message)
- {
- case PipeNetUpdateMessage:
- Update();
- break;
- }
- }
-
- public void Update()
- {
- if (!SiphonEnabled)
- return;
-
- var tileAtmos = Owner.Transform.Coordinates.GetTileAtmosphere();
-
- if (_scrubberOutlet == null || tileAtmos == null || tileAtmos.Air == null)
- return;
-
- ScrubGas(tileAtmos.Air, _scrubberOutlet.Air);
- tileAtmos.Invalidate();
- }
-
- protected abstract void ScrubGas(GasMixture inletGas, GasMixture outletGas);
-
- private void SetOutlet()
- {
- if (!Owner.TryGetComponent(out var container))
- {
- Logger.Warning($"{nameof(BaseSiphonComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} did not have a {nameof(NodeContainerComponent)}.");
- return;
- }
- _scrubberOutlet = container.Nodes.OfType().FirstOrDefault();
- if (_scrubberOutlet == null)
- {
- Logger.Warning($"{nameof(BaseSiphonComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}.");
- return;
- }
- }
-
- private void UpdateAppearance()
- {
- _appearance?.SetData(SiphonVisuals.VisualState, new SiphonVisualState(SiphonEnabled));
- }
- }
-}
diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/Scrubbers/PressureSiphon.cs b/Content.Server/GameObjects/Components/Atmos/Piping/Scrubbers/PressureSiphon.cs
deleted file mode 100644
index 37f96e4a4e..0000000000
--- a/Content.Server/GameObjects/Components/Atmos/Piping/Scrubbers/PressureSiphon.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-#nullable enable
-using System;
-using Content.Server.Atmos;
-using Content.Shared.Atmos;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization;
-using Robust.Shared.Serialization.Manager.Attributes;
-using Robust.Shared.ViewVariables;
-
-namespace Content.Server.GameObjects.Components.Atmos.Piping.Scrubbers
-{
- [RegisterComponent]
- [ComponentReference(typeof(BaseSiphonComponent))]
- public class PressureSiphonComponent : BaseSiphonComponent
- {
- public override string Name => "PressureSiphon";
-
- ///
- /// The pressure this siphon will try to bring its inlet too.
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- public float SiphonPressureTarget
- {
- get => _siphonPressureTarget;
- set => _siphonPressureTarget = Math.Max(value, 0);
- }
- [DataField("startingSiphonPressureTarget")]
- private float _siphonPressureTarget = Atmospherics.OneAtmosphere * 2;
-
- ///
- /// Every update, this siphon will only decrease the inlet pressure by this fraction of the amount needed to reach the .
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- public float TransferRatio
- {
- get => _transferRatio;
- set => _transferRatio = Math.Clamp(value, 0, 1);
- }
- [DataField("transferRatio")]
- private float _transferRatio = 0.5f;
-
- protected override void ScrubGas(GasMixture inletGas, GasMixture outletGas)
- {
- var goalDiff = SiphonPressureTarget - inletGas.Pressure;
- var realGoalPressureDiff = goalDiff * TransferRatio;
-
- var moleRatioToTransfer = 1 - (inletGas.Pressure + realGoalPressureDiff) / inletGas.Pressure;
- moleRatioToTransfer = Math.Clamp(moleRatioToTransfer, 0, 1);
-
- var transferedGas = inletGas.RemoveRatio(moleRatioToTransfer);
- outletGas.Merge(transferedGas);
- }
- }
-}
diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/Vents/BaseVentComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/Vents/BaseVentComponent.cs
deleted file mode 100644
index 96f0bfbcce..0000000000
--- a/Content.Server/GameObjects/Components/Atmos/Piping/Vents/BaseVentComponent.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-#nullable enable
-using System.Linq;
-using Content.Server.Atmos;
-using Content.Server.GameObjects.EntitySystems;
-using Content.Server.NodeContainer;
-using Content.Server.NodeContainer.Nodes;
-using Content.Shared.GameObjects.Components.Atmos;
-using Robust.Server.GameObjects;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Log;
-using Robust.Shared.ViewVariables;
-
-namespace Content.Server.GameObjects.Components.Atmos.Piping.Vents
-{
- ///
- /// Transfers gas from a to the tile it is on.
- ///
- public abstract class BaseVentComponent : Component
- {
-
- [ViewVariables]
- private PipeNode? _ventInlet;
-
- private AtmosphereSystem? _atmosSystem;
-
- [ViewVariables(VVAccess.ReadWrite)]
- public bool VentEnabled
- {
- get => _ventEnabled;
- set
- {
- _ventEnabled = value;
- UpdateAppearance();
- }
- }
- private bool _ventEnabled = true;
-
- private AppearanceComponent? _appearance;
-
- public override void Initialize()
- {
- base.Initialize();
- Owner.EnsureComponentWarn();
- _atmosSystem = EntitySystem.Get();
- SetInlet();
- Owner.TryGetComponent(out _appearance);
- UpdateAppearance();
- }
-
- public override void HandleMessage(ComponentMessage message, IComponent? component)
- {
- base.HandleMessage(message, component);
- switch (message)
- {
- case PipeNetUpdateMessage:
- Update();
- break;
- }
- }
-
- public void Update()
- {
- if (!VentEnabled)
- return;
-
- var tileAtmos = Owner.Transform.Coordinates.GetTileAtmosphere();
-
- if (_ventInlet == null || tileAtmos == null || tileAtmos.Air == null)
- return;
-
- VentGas(_ventInlet.Air, tileAtmos.Air);
- tileAtmos.Invalidate();
- }
-
- protected abstract void VentGas(GasMixture inletGas, GasMixture outletGas);
-
- private void SetInlet()
- {
- if (!Owner.TryGetComponent(out var container))
- {
- Logger.Warning($"{nameof(BaseVentComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} did not have a {nameof(NodeContainerComponent)}.");
- return;
- }
- _ventInlet = container.Nodes.OfType().FirstOrDefault();
- if (_ventInlet == null)
- {
- Logger.Warning($"{nameof(BaseVentComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}.");
- return;
- }
- }
-
- private void UpdateAppearance()
- {
- _appearance?.SetData(VentVisuals.VisualState, new VentVisualState(VentEnabled));
- }
- }
-}
diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/Vents/PressureVentComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/Vents/PressureVentComponent.cs
deleted file mode 100644
index f58c674d06..0000000000
--- a/Content.Server/GameObjects/Components/Atmos/Piping/Vents/PressureVentComponent.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-#nullable enable
-using Content.Server.Atmos;
-using Content.Shared.Atmos;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Serialization;
-using Robust.Shared.ViewVariables;
-using System;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.Manager.Attributes;
-
-namespace Content.Server.GameObjects.Components.Atmos.Piping.Vents
-{
- [RegisterComponent]
- [ComponentReference(typeof(BaseVentComponent))]
- public class PressureVentComponent : BaseVentComponent
- {
- public override string Name => "PressureVent";
-
- ///
- /// The pressure this vent will try to bring its oulet to.
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- public float VentPressureTarget
- {
- get => _ventPressureTarget;
- set => _ventPressureTarget = Math.Clamp(value, 0, MaxVentPressureTarget);
- }
- [DataField("startingVentPressureTarget")]
- private float _ventPressureTarget = Atmospherics.OneAtmosphere;
-
- ///
- /// Max value can be set to.
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- public float MaxVentPressureTarget
- {
- get => _maxVentPressureTarget;
- set => Math.Max(value, 0);
- }
- [DataField("maxVentPressureTarget")]
- private float _maxVentPressureTarget = Atmospherics.OneAtmosphere * 2;
-
- ///
- /// Every update, this vent will only increase the outlet pressure by this fraction of the amount needed to reach the .
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- public float TransferRatio
- {
- get => _transferRatio;
- set => _transferRatio = Math.Clamp(value, 0, 1);
- }
- [DataField("transferRatio")]
- private float _transferRatio = 0.5f;
-
- protected override void VentGas(GasMixture inletGas, GasMixture outletGas)
- {
- var goalDiff = VentPressureTarget - outletGas.Pressure;
- var realGoalPressureDiff = goalDiff * TransferRatio;
- var realTargetPressure = outletGas.Pressure + realGoalPressureDiff;
- var realCappedTargetPressure = Math.Max(realTargetPressure, outletGas.Pressure); //no lowering the outlet's pressure
- inletGas.PumpGasTo(outletGas, realCappedTargetPressure);
- }
- }
-}
diff --git a/Content.Server/GameObjects/DONT_PUT_STUFF_HERE_ATMOS_LEFTOVER b/Content.Server/GameObjects/DONT_PUT_STUFF_HERE_ATMOS_LEFTOVER
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/Content.Server/GameObjects/EntitySystems/AtmosExposedSystem.cs b/Content.Server/GameObjects/EntitySystems/AtmosExposedSystem.cs
deleted file mode 100644
index 3bce1680f9..0000000000
--- a/Content.Server/GameObjects/EntitySystems/AtmosExposedSystem.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using Content.Server.Atmos;
-using Content.Server.GameObjects.Components.Atmos;
-using JetBrains.Annotations;
-using Robust.Shared.GameObjects;
-
-namespace Content.Server.GameObjects.EntitySystems
-{
- [UsedImplicitly]
- public class AtmosExposedSystem
- : EntitySystem
- {
-
- private const float UpdateDelay = 1f;
- private float _lastUpdate;
-
- public override void Update(float frameTime)
- {
- _lastUpdate += frameTime;
- if (_lastUpdate < UpdateDelay) return;
-
- // creadth: everything exposable by atmos should be updated as well
- foreach (var atmosExposedComponent in EntityManager.ComponentManager.EntityQuery(true))
- {
- var tile = atmosExposedComponent.Owner.Transform.Coordinates.GetTileAtmosphere();
- if (tile == null) continue;
- atmosExposedComponent.Update(tile, _lastUpdate);
- }
-
- _lastUpdate = 0;
- }
- }
-}
diff --git a/Content.Server/GameObjects/EntitySystems/GasCanisterSystem.cs b/Content.Server/GameObjects/EntitySystems/GasCanisterSystem.cs
deleted file mode 100644
index 0377d14510..0000000000
--- a/Content.Server/GameObjects/EntitySystems/GasCanisterSystem.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using Content.Server.GameObjects.Components.Atmos;
-using JetBrains.Annotations;
-using Robust.Shared.GameObjects;
-
-namespace Content.Server.GameObjects.EntitySystems
-{
- [UsedImplicitly]
- internal sealed class GasCanisterSystem : EntitySystem
- {
- public override void Initialize()
- {
- base.Initialize();
-
- SubscribeLocalEvent(OnBodyTypeChanged);
- }
-
- private static void OnBodyTypeChanged(
- EntityUid uid,
- GasCanisterComponent component,
- PhysicsBodyTypeChangedEvent args)
- {
- component.AnchorUpdate();
- }
-
- public override void Update(float frameTime)
- {
- foreach (var component in ComponentManager.EntityQuery(true))
- {
- component.Update(frameTime);
- }
- }
- }
-}
diff --git a/Content.Server/Ghost/GhostSystem.cs b/Content.Server/Ghost/GhostSystem.cs
index bf0ca1b695..8cdc54e471 100644
--- a/Content.Server/Ghost/GhostSystem.cs
+++ b/Content.Server/Ghost/GhostSystem.cs
@@ -6,7 +6,6 @@ using Content.Server.Players;
using Content.Server.Visible;
using Content.Server.Warps;
using Content.Shared.Examine;
-using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Ghost;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
diff --git a/Content.Server/Interfaces/IGasMixtureHolder.cs b/Content.Server/Interfaces/IGasMixtureHolder.cs
index d155f02bea..171bb3c64d 100644
--- a/Content.Server/Interfaces/IGasMixtureHolder.cs
+++ b/Content.Server/Interfaces/IGasMixtureHolder.cs
@@ -6,7 +6,7 @@ namespace Content.Server.Interfaces
{
public GasMixture Air { get; set; }
- public void AssumeAir(GasMixture giver)
+ public virtual void AssumeAir(GasMixture giver)
{
Air.Merge(giver);
}
diff --git a/Content.Server/NodeContainer/NodeGroups/INodeGroup.cs b/Content.Server/NodeContainer/NodeGroups/INodeGroup.cs
index a727ebe099..bc8868bc11 100644
--- a/Content.Server/NodeContainer/NodeGroups/INodeGroup.cs
+++ b/Content.Server/NodeContainer/NodeGroups/INodeGroup.cs
@@ -72,11 +72,14 @@ namespace Content.Server.NodeContainer.NodeGroups
newGroup.CombineGroup(this);
return;
}
+
OnGivingNodesForCombine(newGroup);
+
foreach (var node in Nodes)
{
node.NodeGroup = newGroup;
}
+
Removed = true;
}
@@ -90,7 +93,9 @@ namespace Content.Server.NodeContainer.NodeGroups
{
node.ClearNodeGroup();
}
- var newGroups = new List();
+
+ var newGroups = new HashSet();
+
foreach (var node in Nodes)
{
if (node.TryAssignGroupIfNeeded())
@@ -99,7 +104,9 @@ namespace Content.Server.NodeContainer.NodeGroups
newGroups.Add(node.NodeGroup);
}
}
+
AfterRemake(newGroups);
+
Removed = true;
}
@@ -111,7 +118,7 @@ namespace Content.Server.NodeContainer.NodeGroups
protected virtual void AfterRemake(IEnumerable newGroups) { }
- private class NullNodeGroup : INodeGroup
+ protected class NullNodeGroup : INodeGroup
{
public IReadOnlyList Nodes => _nodes;
private readonly List _nodes = new();
diff --git a/Content.Server/NodeContainer/NodeGroups/IPipeNet.cs b/Content.Server/NodeContainer/NodeGroups/IPipeNet.cs
index 9856e55aa1..7809433318 100644
--- a/Content.Server/NodeContainer/NodeGroups/IPipeNet.cs
+++ b/Content.Server/NodeContainer/NodeGroups/IPipeNet.cs
@@ -1,15 +1,19 @@
#nullable enable
+using System;
using System.Collections.Generic;
using Content.Server.Atmos;
-using Content.Server.GameObjects.EntitySystems;
+using Content.Server.Atmos.Components;
+using Content.Server.Atmos.EntitySystems;
+using Content.Server.GameObjects.Components.NodeContainer.Nodes;
using Content.Server.Interfaces;
using Content.Server.NodeContainer.Nodes;
+using Content.Shared.Atmos;
using Robust.Shared.GameObjects;
using Robust.Shared.ViewVariables;
namespace Content.Server.NodeContainer.NodeGroups
{
- public interface IPipeNet : IGasMixtureHolder
+ public interface IPipeNet : INodeGroup, IGasMixtureHolder
{
///
/// Causes gas in the PipeNet to react.
@@ -21,7 +25,7 @@ namespace Content.Server.NodeContainer.NodeGroups
public class PipeNet : BaseNodeGroup, IPipeNet
{
[ViewVariables]
- public GasMixture Air { get; set; } = new();
+ public GasMixture Air { get; set; } = new() {Temperature = Atmospherics.T20C};
public static readonly IPipeNet NullNet = new NullPipeNet();
@@ -49,11 +53,10 @@ namespace Content.Server.NodeContainer.NodeGroups
{
if (node is not PipeNode pipeNode)
return;
+
_pipes.Add(pipeNode);
pipeNode.JoinPipeNet(this);
Air.Volume += pipeNode.Volume;
- Air.Merge(pipeNode.LocalAir);
- pipeNode.LocalAir.Clear();
}
protected override void OnRemoveNode(Node node)
@@ -61,9 +64,8 @@ namespace Content.Server.NodeContainer.NodeGroups
RemoveFromGridAtmos();
if (node is not PipeNode pipeNode)
return;
- var pipeAir = pipeNode.LocalAir;
- pipeAir.Merge(Air);
- pipeAir.Multiply(pipeNode.Volume / Air.Volume);
+
+ pipeNode.ClearPipeNet();
_pipes.Remove(pipeNode);
}
@@ -71,21 +73,28 @@ namespace Content.Server.NodeContainer.NodeGroups
{
if (newGroup is not IPipeNet newPipeNet)
return;
+
newPipeNet.Air.Merge(Air);
- Air.Clear();
}
protected override void AfterRemake(IEnumerable newGroups)
{
+ RemoveFromGridAtmos();
+
+ var buffer = new GasMixture(Air.Volume) {Temperature = Air.Temperature};
+
foreach (var newGroup in newGroups)
{
if (newGroup is not IPipeNet newPipeNet)
continue;
- newPipeNet.Air.Merge(Air);
- var newPipeNetGas = newPipeNet.Air;
- newPipeNetGas.Multiply(newPipeNetGas.Volume / Air.Volume);
+
+ var newAir = newPipeNet.Air;
+
+ buffer.Clear();
+ buffer.Merge(Air);
+ buffer.Multiply(MathF.Min(newAir.Volume / Air.Volume, 1f));
+ newAir.Merge(buffer);
}
- RemoveFromGridAtmos();
}
private void RemoveFromGridAtmos()
@@ -93,9 +102,18 @@ namespace Content.Server.NodeContainer.NodeGroups
GridAtmos?.RemovePipeNet(this);
}
- private class NullPipeNet : IPipeNet
+ private class NullPipeNet : NullNodeGroup, IPipeNet
{
- GasMixture IGasMixtureHolder.Air { get; set; } = new();
+ private readonly GasMixture _air;
+
+ GasMixture IGasMixtureHolder.Air { get => _air; set { } }
+
+ public NullPipeNet()
+ {
+ _air = new GasMixture(1f) {Temperature = Atmospherics.T20C};
+ _air.MarkImmutable();
+ }
+
public void Update() { }
}
}
diff --git a/Content.Server/NodeContainer/Nodes/Node.cs b/Content.Server/NodeContainer/Nodes/Node.cs
index 2d4d8163af..a7e9cddd3f 100644
--- a/Content.Server/NodeContainer/Nodes/Node.cs
+++ b/Content.Server/NodeContainer/Nodes/Node.cs
@@ -41,7 +41,11 @@ namespace Content.Server.NodeContainer.Nodes
///
public bool Connectable => !_deleting && Anchored;
- private bool Anchored => !Owner.TryGetComponent(out var physics) || physics.BodyType == BodyType.Static;
+ protected bool Anchored => !NeedAnchored || !Owner.TryGetComponent(out var physics) || physics.BodyType == BodyType.Static;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("needAnchored")]
+ private bool NeedAnchored { get; } = true;
///
/// Prevents a node from being used by other nodes while midway through removal.
diff --git a/Content.Server/NodeContainer/Nodes/PipeNode.cs b/Content.Server/NodeContainer/Nodes/PipeNode.cs
index 21ef2801fe..f567c204af 100644
--- a/Content.Server/NodeContainer/Nodes/PipeNode.cs
+++ b/Content.Server/NodeContainer/Nodes/PipeNode.cs
@@ -2,17 +2,19 @@
using System.Collections.Generic;
using Content.Server.Atmos;
using Content.Server.Interfaces;
+using Content.Server.NodeContainer;
using Content.Server.NodeContainer.NodeGroups;
-using Content.Shared.GameObjects.Components.Atmos;
+using Content.Server.NodeContainer.Nodes;
+using Content.Shared.Atmos;
using Robust.Server.GameObjects;
+using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
-using Robust.Shared.Maths;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
-namespace Content.Server.NodeContainer.Nodes
+namespace Content.Server.GameObjects.Components.NodeContainer.Nodes
{
///
/// Connects with other s whose
@@ -21,12 +23,7 @@ namespace Content.Server.NodeContainer.Nodes
[DataDefinition]
public class PipeNode : Node, IGasMixtureHolder, IRotatableNode
{
- ///
- /// Modifies the of this pipe, and ensures the sprite is correctly rotated.
- /// This is a property for the sake of calling the method via ViewVariables.
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- public PipeDirection SetPipeDirectionAndSprite { get => PipeDirection; set => AdjustPipeDirectionAndSprite(value); }
+ private PipeDirection _connectedDirections;
///
/// The directions in which this pipe can connect to other pipes around it.
@@ -36,13 +33,41 @@ namespace Content.Server.NodeContainer.Nodes
[DataField("pipeDirection")]
public PipeDirection PipeDirection { get; private set; }
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("connectToContainedEntities")]
+ public bool ConnectToContainedEntities { get; set; } = false;
+
///
/// The directions in which this node is connected to other nodes.
/// Used by .
///
[ViewVariables(VVAccess.ReadWrite)]
- private PipeDirection ConnectedDirections { get => _connectedDirections; set { _connectedDirections = value; UpdateAppearance(); } }
- private PipeDirection _connectedDirections;
+ public PipeDirection ConnectedDirections
+ {
+ get => _connectedDirections;
+ private set
+ {
+ _connectedDirections = value;
+ UpdateAppearance();
+ }
+ }
+
+ ///
+ /// Whether this node can connect to others or not.
+ ///
+ [ViewVariables(VVAccess.ReadWrite)]
+ public bool ConnectionsEnabled
+ {
+ get => _connectionsEnabled;
+ set
+ {
+ _connectionsEnabled = value;
+ RefreshNodeGroup();
+ }
+ }
+
+ [DataField("rotationsEnabled")]
+ public bool RotationsEnabled { get; set; } = true;
///
/// The this pipe is a part of. Set to when not in an .
@@ -50,18 +75,15 @@ namespace Content.Server.NodeContainer.Nodes
[ViewVariables]
private IPipeNet _pipeNet = PipeNet.NullNet;
- ///
- /// If is set to .
- /// When true, this pipe may be storing gas in .
- ///
- [ViewVariables]
- private bool _needsPipeNet = true;
+ [DataField("connectionsEnabled")]
+ private bool _connectionsEnabled = true;
///
- /// Prevents rotation events from re-calculating the .
- /// Used while rotating the sprite to the correct orientation while not affecting the pipe.
+ /// Whether to ignore the pipenet and return the environment's air.
///
- private bool IgnoreRotation { get; set; }
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("environmentalAir")]
+ public bool EnvironmentalAir { get; set; } = false;
///
/// The gases in this pipe.
@@ -69,42 +91,32 @@ namespace Content.Server.NodeContainer.Nodes
[ViewVariables]
public GasMixture Air
{
- get => _needsPipeNet ? LocalAir : _pipeNet.Air;
- set
- {
- if (_needsPipeNet)
- LocalAir = value;
- else
- _pipeNet.Air = value;
- }
+ get => !EnvironmentalAir ? _pipeNet.Air : Owner.Transform.Coordinates.GetTileAir() ?? GasMixture.SpaceGas;
+ set => _pipeNet.Air = value;
}
- ///
- /// Stores gas in this pipe when disconnected from a .
- /// Only for usage by s.
- ///
- [ViewVariables]
- [DataField("gasMixture")]
- public GasMixture LocalAir { get; set; } = new(DefaultVolume);
-
- [ViewVariables]
- public float Volume => LocalAir.Volume;
-
- private AppearanceComponent? _appearance;
-
- private const float DefaultVolume = 1;
-
- public override void Initialize(IEntity owner)
+ public void AssumeAir(GasMixture giver)
{
- base.Initialize(owner);
- Owner.TryGetComponent(out _appearance);
+ if (EnvironmentalAir)
+ {
+ var tileAtmosphere = Owner.Transform.Coordinates.GetTileAtmosphere();
+ tileAtmosphere?.AssumeAir(giver);
+ return;
+ }
+
+ _pipeNet.Air.Merge(giver);
}
+ [ViewVariables]
+ [DataField("volume")]
+ public float Volume { get; set; } = DefaultVolume;
+
+ private const float DefaultVolume = 200f;
+
public override void OnContainerStartup()
{
base.OnContainerStartup();
OnConnectedDirectionsNeedsUpdating();
- UpdateAppearance();
}
public override void OnContainerShutdown()
@@ -113,16 +125,21 @@ namespace Content.Server.NodeContainer.Nodes
UpdateAdjacentConnectedDirections();
}
+ public override void OnSnapGridMove()
+ {
+ OnConnectedDirectionsNeedsUpdating();
+ }
+
public void JoinPipeNet(IPipeNet pipeNet)
{
_pipeNet = pipeNet;
- _needsPipeNet = false;
+ OnConnectedDirectionsNeedsUpdating();
}
public void ClearPipeNet()
{
_pipeNet = PipeNet.NullNet;
- _needsPipeNet = true;
+ OnConnectedDirectionsNeedsUpdating();
}
///
@@ -130,9 +147,7 @@ namespace Content.Server.NodeContainer.Nodes
///
void IRotatableNode.RotateEvent(RotateEvent ev)
{
- if (IgnoreRotation)
- return;
-
+ if (!RotationsEnabled) return;
var diff = ev.NewRotation - ev.OldRotation;
PipeDirection = PipeDirection.RotatePipeDirection(diff);
RefreshNodeGroup();
@@ -142,7 +157,7 @@ namespace Content.Server.NodeContainer.Nodes
protected override IEnumerable GetReachableNodes()
{
- for (var i = 0; i < PipeDirectionHelpers.PipeDirections; i++)
+ for (var i = 0; i < PipeDirectionHelpers.AllPipeDirections; i++)
{
var pipeDir = (PipeDirection) (1 << i);
@@ -150,18 +165,52 @@ namespace Content.Server.NodeContainer.Nodes
continue;
foreach (var pipe in LinkableNodesInDirection(pipeDir))
+ {
yield return pipe;
+ }
+ }
+
+ if (!ConnectionsEnabled || !ConnectToContainedEntities || !Owner.TryGetComponent(out ContainerManagerComponent? containerManager))
+ yield break;
+
+ // TODO ATMOS Kill it with fire.
+ foreach (var container in containerManager.GetAllContainers())
+ {
+ foreach (var entity in container.ContainedEntities)
+ {
+ if (!entity.TryGetComponent(out NodeContainerComponent? nodeContainer))
+ continue;
+
+ foreach (var node in nodeContainer.Nodes.Values)
+ {
+ yield return node;
+ }
+ }
}
}
///
- /// Gets the pipes that can connect to us from entities on the tile adjacent in a direction.
+ /// Gets the pipes that can connect to us from entities on the tile or adjacent in a direction.
///
private IEnumerable LinkableNodesInDirection(PipeDirection pipeDir)
{
+ if (!Anchored)
+ yield break;
+
+ if (pipeDir is PipeDirection.Port or PipeDirection.Connector)
+ {
+ foreach (var pipe in PipesInTile())
+ {
+ if (pipe.Anchored && pipe.ConnectionsEnabled && pipe.PipeDirection.HasDirection(pipeDir.GetOpposite()))
+ yield return pipe;
+ }
+
+ yield break;
+ }
+
foreach (var pipe in PipesInDirection(pipeDir))
{
- if (pipe.PipeDirection.HasDirection(pipeDir.GetOpposite()))
+ if (pipe.ConnectionsEnabled && pipe.PipeDirection.HasDirection(pipeDir.GetOpposite()))
yield return pipe;
}
}
@@ -189,6 +238,29 @@ namespace Content.Server.NodeContainer.Nodes
}
}
+ ///
+ /// Gets the pipes from entities on the tile adjacent in a direction.
+ ///
+ private IEnumerable PipesInTile()
+ {
+ if (!Owner.Transform.Anchored)
+ yield break;
+
+ var grid = IoCManager.Resolve().GetGrid(Owner.Transform.GridID);
+ var position = Owner.Transform.Coordinates;
+ foreach (var entity in grid.GetLocal(position))
+ {
+ if (!Owner.EntityManager.ComponentManager.TryGetComponent(entity, out var container))
+ continue;
+
+ foreach (var node in container.Nodes.Values)
+ {
+ if (node is PipeNode pipe)
+ yield return pipe;
+ }
+ }
+ }
+
///
/// Updates the of this and all sorrounding pipes.
///
@@ -196,6 +268,7 @@ namespace Content.Server.NodeContainer.Nodes
{
UpdateConnectedDirections();
UpdateAdjacentConnectedDirections();
+ UpdateAppearance();
}
///
@@ -204,7 +277,8 @@ namespace Content.Server.NodeContainer.Nodes
private void UpdateConnectedDirections()
{
ConnectedDirections = PipeDirection.None;
- for (var i = 0; i < PipeDirectionHelpers.PipeDirections; i++)
+
+ for (var i = 0; i < PipeDirectionHelpers.AllPipeDirections; i++)
{
var pipeDir = (PipeDirection) (1 << i);
@@ -231,8 +305,12 @@ namespace Content.Server.NodeContainer.Nodes
for (var i = 0; i < PipeDirectionHelpers.PipeDirections; i++)
{
var pipeDir = (PipeDirection) (1 << i);
+
foreach (var pipe in LinkableNodesInDirection(pipeDir))
+ {
pipe.UpdateConnectedDirections();
+ pipe.UpdateAppearance();
+ }
}
}
@@ -242,50 +320,21 @@ namespace Content.Server.NodeContainer.Nodes
///
private void UpdateAppearance()
{
+ if (!Owner.TryGetComponent(out AppearanceComponent? appearance)
+ || !Owner.TryGetComponent(out NodeContainerComponent? container))
+ return;
+
var netConnectedDirections = PipeDirection.None;
- if (Owner.TryGetComponent(out var container))
+
+ foreach (var node in container.Nodes.Values)
{
- foreach (var node in container.Nodes.Values)
+ if (node is PipeNode pipe)
{
- if (node is PipeNode pipe)
- {
- netConnectedDirections |= pipe.ConnectedDirections;
- }
+ netConnectedDirections |= pipe.ConnectedDirections;
}
}
- _appearance?.SetData(PipeVisuals.VisualState, new PipeVisualState(PipeDirection.PipeDirectionToPipeShape(), netConnectedDirections));
- }
-
- ///
- /// Changes the directions of this pipe while ensuring the sprite is correctly rotated.
- ///
- public void AdjustPipeDirectionAndSprite(PipeDirection newDir)
- {
- IgnoreRotation = true;
-
- var baseDir = newDir.PipeDirectionToPipeShape().ToBaseDirection();
-
- var newAngle = Angle.FromDegrees(0);
-
- for (var i = 0; i < PipeDirectionHelpers.PipeDirections; i++)
- {
- var pipeDir = (PipeDirection) (1 << i);
- var angle = pipeDir.ToAngle();
- if (baseDir.RotatePipeDirection(angle) == newDir) //finds what angle the entity needs to be rotated from the base to be set to the correct direction
- {
- newAngle = angle;
- break;
- }
- }
-
- Owner.Transform.LocalRotation = newAngle; //rotate the entity so the sprite's new state will be of the correct direction
- PipeDirection = newDir;
-
- RefreshNodeGroup();
- OnConnectedDirectionsNeedsUpdating();
- UpdateAppearance();
- IgnoreRotation = false;
+ appearance.SetData(PipeVisuals.VisualState, new PipeVisualState(netConnectedDirections));
}
}
}
diff --git a/Content.Server/Physics/Controllers/PullController.cs b/Content.Server/Physics/Controllers/PullController.cs
index 5068405bbd..23a27af383 100644
--- a/Content.Server/Physics/Controllers/PullController.cs
+++ b/Content.Server/Physics/Controllers/PullController.cs
@@ -1,7 +1,6 @@
#nullable enable
using System;
using System.Collections.Generic;
-using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Pulling;
using Robust.Shared.GameObjects;
using Robust.Shared.Physics;
diff --git a/Content.Server/StationEvents/Events/GasLeak.cs b/Content.Server/StationEvents/Events/GasLeak.cs
index 92961431d0..5b7238ee65 100644
--- a/Content.Server/StationEvents/Events/GasLeak.cs
+++ b/Content.Server/StationEvents/Events/GasLeak.cs
@@ -1,4 +1,4 @@
-using Content.Server.GameObjects.Components.Atmos;
+using Content.Server.Atmos.Components;
using Content.Server.GameTicking;
using Content.Shared.Atmos;
using Robust.Shared.Audio;
diff --git a/Content.Shared/Atmos/Atmospherics.cs b/Content.Shared/Atmos/Atmospherics.cs
index 98310dc8b3..f22d4ceb6b 100644
--- a/Content.Shared/Atmos/Atmospherics.cs
+++ b/Content.Shared/Atmos/Atmospherics.cs
@@ -244,6 +244,20 @@ namespace Content.Shared.Atmos
public const float HumanProducedOxygen = HumanNeededOxygen * 0.75f;
public const float HumanProducedCarbonDioxide = HumanNeededOxygen * 0.25f;
+
+ #region Pipes
+
+ ///
+ /// The pressure pumps and powered equipment max out at, in kPa.
+ ///
+ public const float MaxOutputPressure = 4500;
+
+ ///
+ /// The maximum speed powered equipment can work at, in L/s.
+ ///
+ public const float MaxTransferRate = 200;
+
+ #endregion
}
///
@@ -252,6 +266,7 @@ namespace Content.Shared.Atmos
[Serializable, NetSerializable]
public enum Gas : sbyte
{
+ Invalid = -1,
Oxygen = 0,
Nitrogen = 1,
CarbonDioxide = 2,
diff --git a/Content.Shared/GameObjects/Components/Atmos/SharedFlammableComponent.cs b/Content.Shared/Atmos/Components/SharedFlammableComponent.cs
similarity index 86%
rename from Content.Shared/GameObjects/Components/Atmos/SharedFlammableComponent.cs
rename to Content.Shared/Atmos/Components/SharedFlammableComponent.cs
index 72df65b885..cb965945b7 100644
--- a/Content.Shared/GameObjects/Components/Atmos/SharedFlammableComponent.cs
+++ b/Content.Shared/Atmos/Components/SharedFlammableComponent.cs
@@ -3,7 +3,7 @@ using System;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization;
-namespace Content.Shared.GameObjects.Components.Atmos
+namespace Content.Shared.Atmos.Components
{
public class SharedFlammableComponent : Component
{
diff --git a/Content.Shared/GameObjects/Components/SharedGasAnalyzerComponent.cs b/Content.Shared/Atmos/Components/SharedGasAnalyzerComponent.cs
similarity index 89%
rename from Content.Shared/GameObjects/Components/SharedGasAnalyzerComponent.cs
rename to Content.Shared/Atmos/Components/SharedGasAnalyzerComponent.cs
index cc52b4ff08..0e0b3dab45 100644
--- a/Content.Shared/GameObjects/Components/SharedGasAnalyzerComponent.cs
+++ b/Content.Shared/Atmos/Components/SharedGasAnalyzerComponent.cs
@@ -4,7 +4,7 @@ using Robust.Shared.GameObjects;
using Robust.Shared.Localization;
using Robust.Shared.Serialization;
-namespace Content.Shared.GameObjects.Components
+namespace Content.Shared.Atmos.Components
{
public class SharedGasAnalyzerComponent : Component
{
@@ -83,4 +83,19 @@ namespace Content.Shared.GameObjects.Components
}
}
}
+
+ [NetSerializable]
+ [Serializable]
+ public enum GasAnalyzerVisuals
+ {
+ VisualState,
+ }
+
+ [NetSerializable]
+ [Serializable]
+ public enum GasAnalyzerVisualState
+ {
+ Off,
+ Working,
+ }
}
diff --git a/Content.Shared/GameObjects/Components/Atmos/GasTank/GasTankBoundUserInterfaceState.cs b/Content.Shared/Atmos/Components/SharedGasTankComponent.cs
similarity index 50%
rename from Content.Shared/GameObjects/Components/Atmos/GasTank/GasTankBoundUserInterfaceState.cs
rename to Content.Shared/Atmos/Components/SharedGasTankComponent.cs
index a99905bf39..de5b64c6eb 100644
--- a/Content.Shared/GameObjects/Components/Atmos/GasTank/GasTankBoundUserInterfaceState.cs
+++ b/Content.Shared/Atmos/Components/SharedGasTankComponent.cs
@@ -3,8 +3,25 @@ using System;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization;
-namespace Content.Shared.GameObjects.Components.Atmos.GasTank
+namespace Content.Shared.Atmos.Components
{
+ [Serializable, NetSerializable]
+ public enum SharedGasTankUiKey
+ {
+ Key
+ }
+
+ [Serializable, NetSerializable]
+ public class GasTankToggleInternalsMessage : BoundUserInterfaceMessage
+ {
+ }
+
+ [Serializable, NetSerializable]
+ public class GasTankSetPressureMessage : BoundUserInterfaceMessage
+ {
+ public float Pressure { get; set; }
+ }
+
[Serializable, NetSerializable]
public class GasTankBoundUserInterfaceState : BoundUserInterfaceState
{
diff --git a/Content.Shared/GameObjects/EntitySystems/Atmos/SharedAtmosDebugOverlaySystem.cs b/Content.Shared/Atmos/EntitySystems/SharedAtmosDebugOverlaySystem.cs
similarity index 96%
rename from Content.Shared/GameObjects/EntitySystems/Atmos/SharedAtmosDebugOverlaySystem.cs
rename to Content.Shared/Atmos/EntitySystems/SharedAtmosDebugOverlaySystem.cs
index 012d8b4032..33e69fa700 100644
--- a/Content.Shared/GameObjects/EntitySystems/Atmos/SharedAtmosDebugOverlaySystem.cs
+++ b/Content.Shared/Atmos/EntitySystems/SharedAtmosDebugOverlaySystem.cs
@@ -2,11 +2,10 @@
using System;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
-using Robust.Shared.Serialization;
-using Content.Shared.Atmos;
using Robust.Shared.Maths;
+using Robust.Shared.Serialization;
-namespace Content.Shared.GameObjects.EntitySystems.Atmos
+namespace Content.Shared.Atmos.EntitySystems
{
public abstract class SharedAtmosDebugOverlaySystem : EntitySystem
{
diff --git a/Content.Shared/GameObjects/EntitySystems/Atmos/SharedAtmosphereSystem.cs b/Content.Shared/Atmos/EntitySystems/SharedAtmosphereSystem.cs
similarity index 95%
rename from Content.Shared/GameObjects/EntitySystems/Atmos/SharedAtmosphereSystem.cs
rename to Content.Shared/Atmos/EntitySystems/SharedAtmosphereSystem.cs
index 68abfbde8c..a28035e3b2 100644
--- a/Content.Shared/GameObjects/EntitySystems/Atmos/SharedAtmosphereSystem.cs
+++ b/Content.Shared/Atmos/EntitySystems/SharedAtmosphereSystem.cs
@@ -1,12 +1,12 @@
#nullable enable
using System.Collections.Generic;
-using Content.Shared.Atmos;
+using Content.Shared.Atmos.Prototypes;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
-namespace Content.Shared.GameObjects.EntitySystems.Atmos
+namespace Content.Shared.Atmos.EntitySystems
{
public class SharedAtmosphereSystem : EntitySystem
{
diff --git a/Content.Shared/GameObjects/EntitySystems/Atmos/SharedGasTileOverlaySystem.cs b/Content.Shared/Atmos/EntitySystems/SharedGasTileOverlaySystem.cs
similarity index 98%
rename from Content.Shared/GameObjects/EntitySystems/Atmos/SharedGasTileOverlaySystem.cs
rename to Content.Shared/Atmos/EntitySystems/SharedGasTileOverlaySystem.cs
index 1869f0113b..3092ec0bae 100644
--- a/Content.Shared/GameObjects/EntitySystems/Atmos/SharedGasTileOverlaySystem.cs
+++ b/Content.Shared/Atmos/EntitySystems/SharedGasTileOverlaySystem.cs
@@ -6,7 +6,7 @@ using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Serialization;
-namespace Content.Shared.GameObjects.EntitySystems.Atmos
+namespace Content.Shared.Atmos.EntitySystems
{
public abstract class SharedGasTileOverlaySystem : EntitySystem
{
diff --git a/Content.Shared/GameObjects/EntitySystems/Atmos/GasOverlayChunk.cs b/Content.Shared/Atmos/GasOverlayChunk.cs
similarity index 97%
rename from Content.Shared/GameObjects/EntitySystems/Atmos/GasOverlayChunk.cs
rename to Content.Shared/Atmos/GasOverlayChunk.cs
index 8fdd208c6f..74162f5b55 100644
--- a/Content.Shared/GameObjects/EntitySystems/Atmos/GasOverlayChunk.cs
+++ b/Content.Shared/Atmos/GasOverlayChunk.cs
@@ -1,11 +1,12 @@
#nullable enable
using System.Collections.Generic;
+using Content.Shared.Atmos.EntitySystems;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
-namespace Content.Shared.GameObjects.EntitySystems.Atmos
+namespace Content.Shared.Atmos
{
public sealed class GasOverlayChunk
{
diff --git a/Content.Shared/GameObjects/Components/Atmos/SharedPipeComponent.cs b/Content.Shared/Atmos/PipeDirection.cs
similarity index 83%
rename from Content.Shared/GameObjects/Components/Atmos/SharedPipeComponent.cs
rename to Content.Shared/Atmos/PipeDirection.cs
index 17adc306bd..d00398f19b 100644
--- a/Content.Shared/GameObjects/Components/Atmos/SharedPipeComponent.cs
+++ b/Content.Shared/Atmos/PipeDirection.cs
@@ -1,9 +1,10 @@
#nullable enable
+using System;
using Robust.Shared.Maths;
using Robust.Shared.Serialization;
-using System;
+using Robust.Shared.ViewVariables;
-namespace Content.Shared.GameObjects.Components.Atmos
+namespace Content.Shared.Atmos
{
[Serializable, NetSerializable]
public enum PipeVisuals
@@ -14,13 +15,12 @@ namespace Content.Shared.GameObjects.Components.Atmos
[Serializable, NetSerializable]
public class PipeVisualState
{
- public readonly PipeShape PipeShape;
-
+ // TODO ATMOS: Make this not a class and just be the field below...
+ [ViewVariables]
public readonly PipeDirection ConnectedDirections;
- public PipeVisualState(PipeShape pipeShape, PipeDirection connectedDirections)
+ public PipeVisualState(PipeDirection connectedDirections)
{
- PipeShape = pipeShape;
ConnectedDirections = connectedDirections;
}
}
@@ -34,8 +34,10 @@ namespace Content.Shared.GameObjects.Components.Atmos
//Half of a pipe in a direction
North = 1 << 0,
South = 1 << 1,
- West = 1 << 2,
- East = 1 << 3,
+ West = 1 << 2,
+ East = 1 << 3,
+ Port = 1 << 4,
+ Connector = 1 << 5,
//Straight pipes
Longitudinal = North | South,
@@ -47,6 +49,12 @@ namespace Content.Shared.GameObjects.Components.Atmos
SWBend = South | West,
SEBend = South | East,
+ //Vertical Bends (Port only)
+ NPBend = North | Port,
+ SPBend = South | Port,
+ WPBend = West | Port,
+ EPBend = East | Port,
+
//T-Junctions
TNorth = North | Lateral,
TSouth = South | Lateral,
@@ -64,6 +72,7 @@ namespace Content.Shared.GameObjects.Components.Atmos
Half,
Straight,
Bend,
+ VerticalBend,
TJunction,
Fourway
}
@@ -80,6 +89,7 @@ namespace Content.Shared.GameObjects.Components.Atmos
PipeShape.Half => PipeDirection.South,
PipeShape.Straight => PipeDirection.Longitudinal,
PipeShape.Bend => PipeDirection.SWBend,
+ PipeShape.VerticalBend => PipeDirection.SPBend,
PipeShape.TJunction => PipeDirection.TSouth,
PipeShape.Fourway => PipeDirection.Fourway,
_ => throw new ArgumentOutOfRangeException(nameof(shape), $"{shape} does not have an associated {nameof(PipeDirection)}."),
@@ -91,6 +101,11 @@ namespace Content.Shared.GameObjects.Components.Atmos
{
public const int PipeDirections = 4;
+ ///
+ /// Includes the Up and Down directions.
+ ///
+ public const int AllPipeDirections = 6;
+
public static bool HasDirection(this PipeDirection pipeDirection, PipeDirection other)
{
return (pipeDirection & other) == other;
@@ -133,6 +148,8 @@ namespace Content.Shared.GameObjects.Components.Atmos
PipeDirection.South => PipeDirection.North,
PipeDirection.East => PipeDirection.West,
PipeDirection.West => PipeDirection.East,
+ PipeDirection.Port => PipeDirection.Connector,
+ PipeDirection.Connector => PipeDirection.Port,
_ => throw new ArgumentOutOfRangeException(nameof(pipeDirection)),
};
}
@@ -154,6 +171,11 @@ namespace Content.Shared.GameObjects.Components.Atmos
PipeDirection.SEBend => PipeShape.Bend,
PipeDirection.SWBend => PipeShape.Bend,
+ PipeDirection.NPBend => PipeShape.VerticalBend,
+ PipeDirection.SPBend => PipeShape.VerticalBend,
+ PipeDirection.WPBend => PipeShape.VerticalBend,
+ PipeDirection.EPBend => PipeShape.VerticalBend,
+
PipeDirection.TNorth => PipeShape.TJunction,
PipeDirection.TSouth => PipeShape.TJunction,
PipeDirection.TEast => PipeShape.TJunction,
diff --git a/Content.Shared/Atmos/Piping/Binary/Components/SharedGasCanisterComponent.cs b/Content.Shared/Atmos/Piping/Binary/Components/SharedGasCanisterComponent.cs
new file mode 100644
index 0000000000..3e7e250481
--- /dev/null
+++ b/Content.Shared/Atmos/Piping/Binary/Components/SharedGasCanisterComponent.cs
@@ -0,0 +1,90 @@
+#nullable enable
+using System;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Atmos.Piping.Binary.Components
+{
+ ///
+ /// Key representing which is currently open.
+ /// Useful when there are multiple UI for an object. Here it's future-proofing only.
+ ///
+ [Serializable, NetSerializable]
+ public enum GasCanisterUiKey
+ {
+ Key,
+ }
+
+ #region Enums
+
+ ///
+ /// Used in to determine which visuals to update.
+ ///
+ [Serializable, NetSerializable]
+ public enum GasCanisterVisuals
+ {
+ PressureState,
+ TankInserted,
+ }
+
+ #endregion
+
+ ///
+ /// Represents a state that can be sent to the client
+ ///
+ [Serializable, NetSerializable]
+ public class GasCanisterBoundUserInterfaceState : BoundUserInterfaceState
+ {
+ public string CanisterLabel { get; }
+ public float CanisterPressure { get; }
+ public bool PortStatus { get; }
+ public string? TankLabel { get; }
+ public float TankPressure { get; }
+ public float ReleasePressure { get; }
+ public bool ReleaseValve { get; }
+ public float ReleasePressureMin { get; }
+ public float ReleasePressureMax { get; }
+
+ public GasCanisterBoundUserInterfaceState(string canisterLabel, float canisterPressure, bool portStatus, string? tankLabel, float tankPressure, float releasePressure, bool releaseValve, float releaseValveMin, float releaseValveMax)
+ {
+ CanisterLabel = canisterLabel;
+ CanisterPressure = canisterPressure;
+ PortStatus = portStatus;
+ TankLabel = tankLabel;
+ TankPressure = tankPressure;
+ ReleasePressure = releasePressure;
+ ReleaseValve = releaseValve;
+ ReleasePressureMin = releaseValveMin;
+ ReleasePressureMax = releaseValveMax;
+ }
+ }
+
+ [Serializable, NetSerializable]
+ public class GasCanisterHoldingTankEjectMessage : BoundUserInterfaceMessage
+ {
+ public GasCanisterHoldingTankEjectMessage()
+ {}
+ }
+
+ [Serializable, NetSerializable]
+ public class GasCanisterChangeReleasePressureMessage : BoundUserInterfaceMessage
+ {
+ public float Pressure { get; }
+
+ public GasCanisterChangeReleasePressureMessage(float pressure)
+ {
+ Pressure = pressure;
+ }
+ }
+
+ [Serializable, NetSerializable]
+ public class GasCanisterChangeReleaseValveMessage : BoundUserInterfaceMessage
+ {
+ public bool Valve { get; }
+
+ public GasCanisterChangeReleaseValveMessage(bool valve)
+ {
+ Valve = valve;
+ }
+ }
+}
diff --git a/Content.Shared/Atmos/Piping/EnabledAtmosDeviceVisuals.cs b/Content.Shared/Atmos/Piping/EnabledAtmosDeviceVisuals.cs
new file mode 100644
index 0000000000..e95188cc0b
--- /dev/null
+++ b/Content.Shared/Atmos/Piping/EnabledAtmosDeviceVisuals.cs
@@ -0,0 +1,35 @@
+using System;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Atmos.Piping
+{
+ [Serializable, NetSerializable]
+ public enum OutletInjectorVisuals
+ {
+ Enabled,
+ }
+
+ [Serializable, NetSerializable]
+ public enum PassiveVentVisuals
+ {
+ Enabled,
+ }
+
+ [Serializable, NetSerializable]
+ public enum VentScrubberVisuals
+ {
+ Enabled,
+ }
+
+ [Serializable, NetSerializable]
+ public enum ThermoMachineVisuals
+ {
+ Enabled,
+ }
+
+ [Serializable, NetSerializable]
+ public enum PressurePumpVisuals
+ {
+ Enabled,
+ }
+}
diff --git a/Content.Shared/Atmos/Piping/Unary/Components/SharedGasPortableComponent.cs b/Content.Shared/Atmos/Piping/Unary/Components/SharedGasPortableComponent.cs
new file mode 100644
index 0000000000..d4b695bf13
--- /dev/null
+++ b/Content.Shared/Atmos/Piping/Unary/Components/SharedGasPortableComponent.cs
@@ -0,0 +1,14 @@
+using System;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Atmos.Piping.Unary.Components
+{
+ ///
+ /// Used in to determine which visuals to update.
+ ///
+ [Serializable, NetSerializable]
+ public enum GasPortableVisuals
+ {
+ ConnectedState,
+ }
+}
diff --git a/Content.Shared/Atmos/Piping/Unary/Visuals/ScrubberVisuals.cs b/Content.Shared/Atmos/Piping/Unary/Visuals/ScrubberVisuals.cs
new file mode 100644
index 0000000000..c6cccad809
--- /dev/null
+++ b/Content.Shared/Atmos/Piping/Unary/Visuals/ScrubberVisuals.cs
@@ -0,0 +1,21 @@
+using System;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Atmos.Piping.Unary.Visuals
+{
+ [Serializable, NetSerializable]
+ public enum ScrubberVisuals : byte
+ {
+ State,
+ }
+
+ [Serializable, NetSerializable]
+ public enum ScrubberState : byte
+ {
+ Off,
+ Scrub,
+ Siphon,
+ WideScrub,
+ Welded,
+ }
+}
diff --git a/Content.Shared/Atmos/Piping/Unary/Visuals/VentPumpVisuals.cs b/Content.Shared/Atmos/Piping/Unary/Visuals/VentPumpVisuals.cs
new file mode 100644
index 0000000000..a94a06e790
--- /dev/null
+++ b/Content.Shared/Atmos/Piping/Unary/Visuals/VentPumpVisuals.cs
@@ -0,0 +1,20 @@
+using System;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Atmos.Visuals
+{
+ [Serializable, NetSerializable]
+ public enum VentPumpVisuals : byte
+ {
+ State,
+ }
+
+ [Serializable, NetSerializable]
+ public enum VentPumpState : byte
+ {
+ Off,
+ In,
+ Out,
+ Welded,
+ }
+}
diff --git a/Content.Shared/Atmos/GasPrototype.cs b/Content.Shared/Atmos/Prototypes/GasPrototype.cs
similarity index 98%
rename from Content.Shared/Atmos/GasPrototype.cs
rename to Content.Shared/Atmos/Prototypes/GasPrototype.cs
index 43f5ddcb41..37442375d6 100644
--- a/Content.Shared/Atmos/GasPrototype.cs
+++ b/Content.Shared/Atmos/Prototypes/GasPrototype.cs
@@ -3,7 +3,7 @@ using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
-namespace Content.Shared.Atmos
+namespace Content.Shared.Atmos.Prototypes
{
[Prototype("gas")]
public class GasPrototype : IPrototype
diff --git a/Content.Shared/GameObjects/Components/Atmos/AtmosPlaqueVisuals.cs b/Content.Shared/Atmos/Visuals/AtmosPlaqueVisuals.cs
similarity index 74%
rename from Content.Shared/GameObjects/Components/Atmos/AtmosPlaqueVisuals.cs
rename to Content.Shared/Atmos/Visuals/AtmosPlaqueVisuals.cs
index c7e088c40f..11da1d071b 100644
--- a/Content.Shared/GameObjects/Components/Atmos/AtmosPlaqueVisuals.cs
+++ b/Content.Shared/Atmos/Visuals/AtmosPlaqueVisuals.cs
@@ -1,7 +1,7 @@
using System;
using Robust.Shared.Serialization;
-namespace Content.Shared.GameObjects.Components.Atmos
+namespace Content.Shared.Atmos.Visuals
{
[Serializable, NetSerializable]
public enum AtmosPlaqueVisuals
diff --git a/Content.Shared/Damage/DamageClass.cs b/Content.Shared/Damage/DamageClass.cs
index 6b4f0f7f3d..c97041b8eb 100644
--- a/Content.Shared/Damage/DamageClass.cs
+++ b/Content.Shared/Damage/DamageClass.cs
@@ -3,7 +3,6 @@ using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
-using Content.Shared.GameObjects.EntitySystems;
using Robust.Shared.Serialization;
namespace Content.Shared.Damage
diff --git a/Content.Shared/Damage/DamageType.cs b/Content.Shared/Damage/DamageType.cs
index c639c86ac1..a6d62575be 100644
--- a/Content.Shared/Damage/DamageType.cs
+++ b/Content.Shared/Damage/DamageType.cs
@@ -2,7 +2,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using Content.Shared.GameObjects.EntitySystems;
using Robust.Shared.Serialization;
namespace Content.Shared.Damage
diff --git a/Content.Shared/GameObjects/Components/Atmos/GasTank/GasTankSetPressureMessage.cs b/Content.Shared/GameObjects/Components/Atmos/GasTank/GasTankSetPressureMessage.cs
deleted file mode 100644
index c3255ab6c8..0000000000
--- a/Content.Shared/GameObjects/Components/Atmos/GasTank/GasTankSetPressureMessage.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-#nullable enable
-using System;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Serialization;
-
-namespace Content.Shared.GameObjects.Components.Atmos.GasTank
-{
- [Serializable, NetSerializable]
- public class GasTankSetPressureMessage : BoundUserInterfaceMessage
- {
- public float Pressure { get; set; }
- }
-}
diff --git a/Content.Shared/GameObjects/Components/Atmos/GasTank/GasTankToggleInternalsMessage.cs b/Content.Shared/GameObjects/Components/Atmos/GasTank/GasTankToggleInternalsMessage.cs
deleted file mode 100644
index c89b47b94a..0000000000
--- a/Content.Shared/GameObjects/Components/Atmos/GasTank/GasTankToggleInternalsMessage.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-#nullable enable
-using System;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Serialization;
-
-namespace Content.Shared.GameObjects.Components.Atmos.GasTank
-{
- [Serializable, NetSerializable]
- public class GasTankToggleInternalsMessage : BoundUserInterfaceMessage
- {
- }
-}
diff --git a/Content.Shared/GameObjects/Components/Atmos/GasTank/SharedGasTankComponent.cs b/Content.Shared/GameObjects/Components/Atmos/GasTank/SharedGasTankComponent.cs
deleted file mode 100644
index 9ffd4361fb..0000000000
--- a/Content.Shared/GameObjects/Components/Atmos/GasTank/SharedGasTankComponent.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-#nullable enable
-using Content.Shared.NetIDs;
-using Robust.Shared.GameObjects;
-
-namespace Content.Shared.GameObjects.Components.Atmos.GasTank
-{
- public class SharedGasTankComponent : Component
- {
- public override string Name => "GasTank";
- public override uint? NetID => ContentNetIDs.GAS_TANK;
- }
-}
diff --git a/Content.Shared/GameObjects/Components/Atmos/GasTank/SharedGasTankUiKey.cs b/Content.Shared/GameObjects/Components/Atmos/GasTank/SharedGasTankUiKey.cs
deleted file mode 100644
index ce1492d694..0000000000
--- a/Content.Shared/GameObjects/Components/Atmos/GasTank/SharedGasTankUiKey.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-#nullable enable
-using System;
-using Robust.Shared.Serialization;
-
-namespace Content.Shared.GameObjects.Components.Atmos.GasTank
-{
- [Serializable, NetSerializable]
- public enum SharedGasTankUiKey
- {
- Key
- }
-}
diff --git a/Content.Shared/GameObjects/Components/Atmos/SharedFilterComponent.cs b/Content.Shared/GameObjects/Components/Atmos/SharedFilterComponent.cs
deleted file mode 100644
index 11d7e9972a..0000000000
--- a/Content.Shared/GameObjects/Components/Atmos/SharedFilterComponent.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-#nullable enable
-using System;
-using Robust.Shared.Serialization;
-
-namespace Content.Shared.GameObjects.Components.Atmos
-{
- [Serializable, NetSerializable]
- public enum FilterVisuals
- {
- VisualState
- }
-
- [Serializable, NetSerializable]
- public class FilterVisualState
- {
- public bool Enabled { get; }
-
- public FilterVisualState(bool enabled)
- {
- Enabled = enabled;
- }
- }
-}
diff --git a/Content.Shared/GameObjects/Components/Atmos/SharedGasAnalyzerComponent.cs b/Content.Shared/GameObjects/Components/Atmos/SharedGasAnalyzerComponent.cs
deleted file mode 100644
index aeee8ee92f..0000000000
--- a/Content.Shared/GameObjects/Components/Atmos/SharedGasAnalyzerComponent.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-#nullable enable
-using Robust.Shared.Serialization;
-using System;
-
-namespace Content.Shared.GameObjects.Components.Atmos
-{
- [NetSerializable]
- [Serializable]
- public enum GasAnalyzerVisuals
- {
- VisualState,
- }
-
- [NetSerializable]
- [Serializable]
- public enum GasAnalyzerVisualState
- {
- Off,
- Working,
- }
-}
diff --git a/Content.Shared/GameObjects/Components/Atmos/SharedGasCanisterComponent.cs b/Content.Shared/GameObjects/Components/Atmos/SharedGasCanisterComponent.cs
deleted file mode 100644
index fa5b18484b..0000000000
--- a/Content.Shared/GameObjects/Components/Atmos/SharedGasCanisterComponent.cs
+++ /dev/null
@@ -1,121 +0,0 @@
-#nullable enable
-using System;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Serialization;
-
-namespace Content.Shared.GameObjects.Components.Atmos
-{
- public class SharedGasCanisterComponent : Component
- {
- public override string Name => "GasCanister";
-
- ///
- /// Key representing which is currently open.
- /// Useful when there are multiple UI for an object. Here it's future-proofing only.
- ///
- [Serializable, NetSerializable]
- public enum GasCanisterUiKey
- {
- Key,
- }
- }
-
- #region Enums
-
- ///
- /// Enum representing a UI button.
- ///
- [Serializable, NetSerializable]
- public enum UiButton
- {
- ValveToggle
- }
-
- ///
- /// Used in to determine which visuals to update.
- ///
- [Serializable, NetSerializable]
- public enum GasCanisterVisuals
- {
- ConnectedState,
- PressureState
- }
-
- #endregion
-
- ///
- /// Represents a state that can be sent to the client
- ///
- [Serializable, NetSerializable]
- public class GasCanisterBoundUserInterfaceState : BoundUserInterfaceState
- {
- public readonly string Label;
- public readonly float Volume;
- public readonly float ReleasePressure;
- public readonly bool ValveOpened;
-
- public GasCanisterBoundUserInterfaceState(string newLabel, float volume, float releasePressure, bool valveOpened)
- {
- Label = newLabel;
- Volume = volume;
- ReleasePressure = releasePressure;
- ValveOpened = valveOpened;
- }
-
- public bool Equals(GasCanisterBoundUserInterfaceState? other)
- {
- if (ReferenceEquals(null, other)) return false;
- if (ReferenceEquals(this, other)) return true;
- return Label == other.Label &&
- Volume.Equals(other.Volume) &&
- ReleasePressure.Equals(other.ReleasePressure) &&
- ValveOpened == other.ValveOpened;
- }
- }
-
- #region NetMessages
-
- ///
- /// Message sent from the client to the server when a gas canister button is pressed
- ///
- [Serializable, NetSerializable]
- public class UiButtonPressedMessage : BoundUserInterfaceMessage
- {
- public readonly UiButton Button;
-
- public UiButtonPressedMessage(UiButton button)
- {
- Button = button;
- }
- }
-
- ///
- /// Message sent when the release pressure is changed client side
- ///
- [Serializable, NetSerializable]
- public class ReleasePressureButtonPressedMessage : BoundUserInterfaceMessage
- {
- public readonly float ReleasePressure;
-
- public ReleasePressureButtonPressedMessage(float val) : base()
- {
- ReleasePressure = val;
- }
- }
-
- ///
- /// Message sent when the canister label has been changed
- ///
- [Serializable, NetSerializable]
- public class CanisterLabelChangedMessage : BoundUserInterfaceMessage
- {
- public readonly string NewLabel;
-
- public CanisterLabelChangedMessage(string newLabel) : base()
- {
- NewLabel = newLabel;
- }
- }
-
- #endregion
-}
diff --git a/Content.Shared/GameObjects/Components/Atmos/SharedPumpComponent.cs b/Content.Shared/GameObjects/Components/Atmos/SharedPumpComponent.cs
deleted file mode 100644
index fc17e37918..0000000000
--- a/Content.Shared/GameObjects/Components/Atmos/SharedPumpComponent.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-#nullable enable
-using System;
-using Robust.Shared.Serialization;
-
-namespace Content.Shared.GameObjects.Components.Atmos
-{
- [Serializable, NetSerializable]
- public enum PumpVisuals
- {
- VisualState
- }
-
- [Serializable, NetSerializable]
- public class PumpVisualState
- {
- public readonly PipeDirection InletDirection;
- public readonly PipeDirection OutletDirection;
- public readonly bool PumpEnabled;
-
- public PumpVisualState(PipeDirection inletDirection, PipeDirection outletDirection, bool pumpEnabled)
- {
- InletDirection = inletDirection;
- OutletDirection = outletDirection;
- PumpEnabled = pumpEnabled;
- }
- }
-}
diff --git a/Content.Shared/GameObjects/Components/Atmos/SharedSiphonComponent.cs b/Content.Shared/GameObjects/Components/Atmos/SharedSiphonComponent.cs
deleted file mode 100644
index f2f900c90d..0000000000
--- a/Content.Shared/GameObjects/Components/Atmos/SharedSiphonComponent.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-#nullable enable
-using System;
-using Robust.Shared.Serialization;
-
-namespace Content.Shared.GameObjects.Components.Atmos
-{
- [Serializable, NetSerializable]
- public enum SiphonVisuals
- {
- VisualState
- }
-
- [Serializable, NetSerializable]
- public class SiphonVisualState
- {
- public readonly bool SiphonEnabled;
-
- public SiphonVisualState(bool siphonEnabled)
- {
- SiphonEnabled = siphonEnabled;
- }
- }
-}
diff --git a/Content.Shared/GameObjects/Components/Atmos/SharedVentComponent.cs b/Content.Shared/GameObjects/Components/Atmos/SharedVentComponent.cs
deleted file mode 100644
index 83dfd90131..0000000000
--- a/Content.Shared/GameObjects/Components/Atmos/SharedVentComponent.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-#nullable enable
-using System;
-using Robust.Shared.Serialization;
-
-namespace Content.Shared.GameObjects.Components.Atmos
-{
- [Serializable, NetSerializable]
- public enum VentVisuals
- {
- VisualState
- }
-
- [Serializable, NetSerializable]
- public class VentVisualState
- {
- public readonly bool VentEnabled;
-
- public VentVisualState(bool ventEnabled)
- {
- VentEnabled = ventEnabled;
- }
- }
-}
diff --git a/Content.Tests/Shared/WireHackingTest.cs b/Content.Tests/Shared/WireHackingTest.cs
index ea4bdefb9c..f1ba574861 100644
--- a/Content.Tests/Shared/WireHackingTest.cs
+++ b/Content.Tests/Shared/WireHackingTest.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using Content.Shared.GameObjects.Components;
using Content.Shared.Wires;
using NUnit.Framework;
using Robust.UnitTesting;
diff --git a/Resources/Locale/en-US/components/atmos-unsafe-unanchor-component.ftl b/Resources/Locale/en-US/components/atmos-unsafe-unanchor-component.ftl
new file mode 100644
index 0000000000..8c2f372980
--- /dev/null
+++ b/Resources/Locale/en-US/components/atmos-unsafe-unanchor-component.ftl
@@ -0,0 +1,4 @@
+### AtmosUnsafeUnanchorComponent
+
+# Examine text showing pressure in tank.
+comp-atmos-unsafe-unanchor-warning = A gush of air blows in your face... Maybe you should reconsider?
diff --git a/Resources/Locale/en-US/components/gas-canister-component.ftl b/Resources/Locale/en-US/components/gas-canister-component.ftl
new file mode 100644
index 0000000000..437cffef05
--- /dev/null
+++ b/Resources/Locale/en-US/components/gas-canister-component.ftl
@@ -0,0 +1,21 @@
+comp-gas-canister-ui-canister-status = Canister Status
+comp-gas-canister-ui-canister-relabel = Relabel
+comp-gas-canister-ui-canister-pressure = Canister Pressure:
+
+comp-gas-canister-ui-port-status = Port Status:
+comp-gas-canister-ui-port-connected = Connected
+comp-gas-canister-ui-port-disconnected = Disconnected
+
+comp-gas-canister-ui-holding-tank-status = Holding Tank Status
+comp-gas-canister-ui-holding-tank-label = Tank Label:
+comp-gas-canister-ui-holding-tank-label-empty = Empty
+comp-gas-canister-ui-holding-tank-pressure = Tank Pressure:
+comp-gas-canister-ui-holding-tank-eject = Eject
+
+comp-gas-canister-ui-release-valve-status = Release Valve Status
+comp-gas-canister-ui-release-pressure = Release Pressure:
+comp-gas-canister-ui-release-valve = Release Valve:
+comp-gas-canister-ui-release-valve-open = Open
+comp-gas-canister-ui-release-valve-close = Close
+
+comp-gas-canister-ui-pressure = {$pressure} kPa
diff --git a/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/binary.yml b/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/binary.yml
new file mode 100644
index 0000000000..5abc5f036f
--- /dev/null
+++ b/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/binary.yml
@@ -0,0 +1,133 @@
+- type: entity
+ parent: GasPipeBase
+ abstract: true
+ id: GasBinaryBase
+ placement:
+ mode: SnapgridCenter
+ components:
+ - type: AtmosDevice
+ - type: NodeContainer
+ nodes:
+ inlet:
+ !type:PipeNode
+ nodeGroupID: Pipe
+ pipeDirection: North
+ outlet:
+ !type:PipeNode
+ nodeGroupID: Pipe
+ pipeDirection: South
+
+- type: entity
+ parent: GasBinaryBase
+ id: GasPressurePump
+ name: gas pump
+ description: A pump that moves gas by pressure.
+ placement:
+ mode: SnapgridCenter
+ components:
+ - type: Sprite
+ netsync: false
+ sprite: Constructible/Atmos/pump.rsi
+ layers:
+ - sprite: Constructible/Atmos/pipe.rsi
+ state: pipeStraight
+ - state: pumpPressure
+ - type: Appearance
+ visuals:
+ - type: PipeConnectorVisualizer
+ - type: PressurePumpVisualizer
+ enabledState: pumpPressureOn
+ - type: GasPressurePump
+
+- type: entity
+ parent: GasBinaryBase
+ id: GasVolumePump
+ name: volumetric gas pump
+ description: A pump that moves gas by volume.
+ placement:
+ mode: SnapgridCenter
+ components:
+ - type: Sprite
+ netsync: false
+ sprite: Constructible/Atmos/pump.rsi
+ layers:
+ - sprite: Constructible/Atmos/pipe.rsi
+ state: pipeStraight
+ - state: pumpVolume
+ - type: Appearance
+ visuals:
+ - type: PipeConnectorVisualizer
+ - type: GasVolumePump
+
+- type: entity
+ parent: GasBinaryBase
+ id: GasPassiveGate
+ name: passive gate
+ description: A one-way air valve that does not require power.
+ placement:
+ mode: SnapgridCenter
+ components:
+ - type: Sprite
+ netsync: false
+ sprite: Constructible/Atmos/pump.rsi
+ layers:
+ - sprite: Constructible/Atmos/pipe.rsi
+ state: pipeStraight
+ - state: pumpPassiveGate
+ - type: Appearance
+ visuals:
+ - type: PipeConnectorVisualizer
+ - type: GasPassiveGate
+
+- type: entity
+ parent: GasBinaryBase
+ id: GasValve
+ name: manual valve
+ description: A pipe with a valve that can be used to disable the flow of gas through it.
+ placement:
+ mode: SnapgridCenter
+ components:
+ # TODO ATMOS: Give unique sprite.
+ - type: Sprite
+ netsync: false
+ sprite: Constructible/Atmos/pump.rsi
+ layers:
+ - sprite: Constructible/Atmos/pipe.rsi
+ state: pipeStraight
+ - state: pumpPassiveGate
+ - type: Appearance
+ visuals:
+ - type: PipeConnectorVisualizer
+ - type: GasValve
+ - type: NodeContainer
+ nodes:
+ pipe:
+ !type:PipeNode
+ nodeGroupID: Pipe
+ pipeDirection: Longitudinal
+
+- type: entity
+ parent: GasBinaryBase
+ id: GasPort
+ name: connector port
+ description: For connecting portable devices related to atmospherics control.
+ placement:
+ mode: SnapgridCenter
+ components:
+ - type: Sprite
+ netsync: false
+ sprite: Constructible/Atmos/gascanisterport.rsi
+ layers:
+ - sprite: Constructible/Atmos/pipe.rsi
+ state: pipeHalf
+ - state: gasCanisterPort
+ - type: Appearance
+ visuals:
+ - type: PipeConnectorVisualizer
+ - type: GasPort
+ - type: NodeContainer
+ nodes:
+ connected:
+ !type:PipeNode
+ nodeGroupID: Pipe
+ pipeDirection: SPBend
diff --git a/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/gascanisters.yml b/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/gas_canisters.yml
similarity index 87%
rename from Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/gascanisters.yml
rename to Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/gas_canisters.yml
index 9cdb40b525..02a588c3d5 100644
--- a/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/gascanisters.yml
+++ b/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/gas_canisters.yml
@@ -1,6 +1,6 @@
- type: entity
abstract: true
- id: GasCanisterBase
+ id: GasCanister
name: gas canister
description: A canister that can contain any type of gas. It can be attached to connector ports using a wrench.
parent: BaseConstructibleDynamic
@@ -8,6 +8,39 @@
- type: InteractionOutline
- type: SnapGrid
- type: Sprite
+ netsync: false
+ sprite: Constructible/Atmos/canister.rsi
+ state: grey
+ - type: Appearance
+ visuals:
+ - type: GasPortableVisualizer
+ stateConnected: can-connector
+ - type: GasCanisterVisualizer
+ insertedTankState: can-open
+ pressureStates:
+ - can-o0
+ - can-o1
+ - can-o2
+ - can-o3
+ - type: UserInterface
+ interfaces:
+ - key: enum.GasCanisterUiKey.Key
+ type: GasCanisterBoundUserInterface
+ - type: Destructible
+ thresholds:
+ - trigger:
+ !type:DamageTrigger
+ damage: 300
+ behaviors:
+ - !type:PlaySoundBehavior
+ sound: /Audio/Effects/metalbreak.ogg
+ - !type:SpawnEntitiesBehavior
+ spawn:
+ GasCanisterBrokenBase:
+ min: 1
+ max: 1
+ - !type:DoActsBehavior
+ acts: [ "Destruction" ]
- type: Damageable
resistances: metallicResistances
- type: Physics
@@ -15,7 +48,7 @@
fixtures:
- shape:
!type:PhysShapeAabb
- bounds: "-0.5,-0.25,0.5,0.25"
+ bounds: "-0.25,-0.25,0.25,0.25"
mass: 25
mask:
- MobImpassable
@@ -24,54 +57,36 @@
- MobImpassable
- SmallImpassable
- VaultImpassable
- - type: Destructible
- thresholds:
- - trigger:
- !type:DamageTrigger
- damage: 100
- behaviors:
- - !type:DoActsBehavior
- acts: ["Destruction"]
+ - type: AtmosDevice
+ requireAnchored: false
+ - type: ContainerContainer
+ containers:
+ GasCanisterTankHolder: !type:ContainerSlot {}
+ - type: NodeContainer
+ nodes:
+ port:
+ !type:PipeNode
+ nodeGroupID: Pipe
+ pipeDirection: Connector
+ connectionsEnabled: false
+ needAnchored: false
+ rotationsEnabled: false
+ volume: 1000
+ tank:
+ !type:PipeNode
+ nodeGroupID: Pipe
+ pipeDirection: None
+ needAnchored: false
+ connectToContainedEntities: false
+ environmentalAir: true
+ rotationsEnabled: false
+ volume: 1
+ - type: GasPortable
- type: GasCanister
- - type: UserInterface
- - type: Appearance
-
-- type: entity
- parent: GasCanisterBase
- id: GasCanister
- components:
- - type: Sprite
- netsync: false
- sprite: Constructible/Atmos/canister.rsi
- state: grey
- - type: Appearance
- visuals:
- - type: GasCanisterVisualizer
- stateConnected: can-connector
- pressureStates:
- - can-o0
- - can-o1
- - can-o2
- - can-o3
- - type: UserInterface
- interfaces:
- - key: enum.GasCanisterUiKey.Key
- type: GasCanisterBoundUserInterface
- - type: Destructible
- thresholds:
- - trigger:
- !type:DamageTrigger
- damage: 300
- behaviors:
- - !type:PlaySoundBehavior
- sound: /Audio/Effects/metalbreak.ogg
- - !type:SpawnEntitiesBehavior
- spawn:
- GasCanisterBrokenBase:
- min: 1
- max: 1
- - !type:DoActsBehavior
- acts: [ "Destruction" ]
+ - type: GasPassiveGate
+ enabled: false
+ inlet: port
+ outlet: tank
- type: entity
parent: GasCanister
diff --git a/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/gascanisterports.yml b/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/gascanisterports.yml
deleted file mode 100644
index 6071b39208..0000000000
--- a/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/gascanisterports.yml
+++ /dev/null
@@ -1,44 +0,0 @@
-- type: entity
- abstract: true
- id: GasCanisterPortBase
- placement:
- mode: SnapgridCenter
- components:
- - type: Clickable
- - type: InteractionOutline
- - type: Physics
- - type: SnapGrid
- - type: Sprite
- netsync: false
- sprite: Constructible/Atmos/gascanisterport.rsi
- layers:
- - sprite: Constructible/Atmos/pipe.rsi
- state: pipeHalf
- - state: gasCanisterPort
- - type: Appearance
- visuals:
- - type: PipeConnectorVisualizer
- - type: Damageable
- - type: Destructible
- thresholds:
- - trigger:
- !type:DamageTrigger
- damage: 100
- behaviors:
- - !type:DoActsBehavior
- acts: ["Destruction"]
- - type: GasCanisterPort
- - type: PipeNetDevice
-
-- type: entity
- parent: GasCanisterPortBase
- id: GasCanisterPort
- name: Gas Canister Port
- description: "Connect a gas canister here to release gasses into a system."
- components:
- - type: NodeContainer
- nodes:
- pipe:
- !type:PipeNode
- nodeGroupID: Pipe
- pipeDirection: South
diff --git a/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/gasfilters.yml b/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/gasfilters.yml
deleted file mode 100644
index 72169c0f62..0000000000
--- a/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/gasfilters.yml
+++ /dev/null
@@ -1,57 +0,0 @@
-- type: entity
- abstract: true
- id: GasFilterBase
- placement:
- mode: SnapgridCenter
- components:
- - type: Clickable
- - type: InteractionOutline
- - type: Physics
- - type: SnapGrid
- - type: Damageable
- resistances: metallicResistances
- - type: Destructible
- thresholds:
- - trigger:
- !type:DamageTrigger
- damage: 100
- behaviors:
- - !type:DoActsBehavior
- acts: ["Destruction"]
- - type: Sprite
- netsync: false
- sprite: Constructible/Atmos/gasfilter.rsi
- layers:
- - sprite: Constructible/Atmos/pipe.rsi
- state: pipeTJunction
- - state: gasFilter
- - type: Appearance
- visuals:
- - type: PipeConnectorVisualizer
- - type: GasFilterVisualizer
- - type: PipeNetDevice
-
-- type: entity
- parent: GasFilterBase
- id: GasFilter
- name: gas filter
- description: It filters gases.
- components:
- - type: NodeContainer
- nodes:
- inlet:
- !type:PipeNode
- nodeGroupID: Pipe
- pipeDirection: West
- filter:
- !type:PipeNode
- nodeGroupID: Pipe
- pipeDirection: South
- outlet:
- !type:PipeNode
- nodeGroupID: Pipe
- pipeDirection: East
- - type: GasFilter
- inletDirection: West
- filterOutletDirection: South
- outletDirection: East
diff --git a/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/gasgenerator.yml b/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/gasgenerator.yml
deleted file mode 100644
index 866a2b1ce2..0000000000
--- a/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/gasgenerator.yml
+++ /dev/null
@@ -1,47 +0,0 @@
-- type: entity
- abstract: true
- id: GasGeneratorBase
- placement:
- mode: SnapgridCenter
- components:
- - type: Clickable
- - type: InteractionOutline
- - type: Physics
- bodyType: Static
- fixtures:
- - shape:
- !type:PhysShapeAabb
- bounds: "-0.5,-0.5,0.5,0.5"
- layer:
- - Impassable
- - MobImpassable
- - VaultImpassable
- - Opaque
- mask:
- - Impassable
- - MobImpassable
- - VaultImpassable
- - type: SnapGrid
- - type: GasGenerator
- - type: PipeNetDevice
-
-- type: entity
- parent: GasGeneratorBase
- id: GasGenerator
- name: gas generator
- description: Fabricates gas.
- components:
- - type: Sprite
- netsync: false
- sprite: Constructible/Atmos/gasgenerator.rsi
- layers:
- - sprite: Constructible/Atmos/pipe.rsi
- state: pipeFourway
- - state: gasGenerator
- - type: NodeContainer
- nodes:
- pipe:
- !type:PipeNode
- nodeGroupID: Pipe
- pipeDirection: Fourway
-
diff --git a/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/heaters.yml b/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/heaters.yml
deleted file mode 100644
index b54397ab50..0000000000
--- a/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/heaters.yml
+++ /dev/null
@@ -1,34 +0,0 @@
-- type: entity
- id: Heater
- name: heater
- description: Heats gas.
- placement:
- mode: SnapgridCenter
- components:
- - type: Clickable
- - type: InteractionOutline
- - type: Physics
- - type: SnapGrid
- - type: Damageable
- - type: Destructible
- thresholds:
- - trigger:
- !type:DamageTrigger
- damage: 100
- behaviors:
- - !type:DoActsBehavior
- acts: ["Destruction"]
- - type: Sprite
- netsync: false
- sprite: Constructible/Atmos/heater.rsi
- layers:
- - state: heater
- - state: heaterPipe
- - type: NodeContainer
- nodes:
- inlet:
- !type:PipeNode
- nodeGroupID: Pipe
- pipeDirection: East
- - type: PipeHeater
- - type: PipeNetDevice
diff --git a/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/miners.yml b/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/miners.yml
new file mode 100644
index 0000000000..c72bc79341
--- /dev/null
+++ b/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/miners.yml
@@ -0,0 +1,87 @@
+- type: entity
+ abstract: true
+ name: gas miner
+ description: Gases mined from the gas giant below (above?) flow out through this massive vent.
+ id: GasMinerBase
+ placement:
+ mode: SnapgridCenter
+ components:
+ - type: Clickable
+ - type: InteractionOutline
+ - type: Physics
+ - type: SnapGrid
+ - type: Damageable
+ - type: Destructible
+ thresholds:
+ - trigger:
+ !type:DamageTrigger
+ damage: 100
+ behaviors:
+ - !type:DoActsBehavior
+ acts: ["Destruction"]
+ - type: Sprite
+ netsync: false
+ sprite: Constructible/Atmos/miners.rsi
+ state: miner
+ - type: AtmosDevice
+ - type: GasMiner
+
+- type: entity
+ name: O2 gas miner
+ parent: GasMinerBase
+ id: GasMinerOxygen
+ placement:
+ mode: SnapgridCenter
+ components:
+ - type: GasMiner
+ spawnGas: Oxygen
+
+- type: entity
+ name: N2 gas miner
+ parent: GasMinerBase
+ id: GasMinerNitrogen
+ placement:
+ mode: SnapgridCenter
+ components:
+ - type: GasMiner
+ spawnGas: Nitrogen
+
+- type: entity
+ name: CO2 gas miner
+ parent: GasMinerBase
+ id: GasMinerCarbonDioxide
+ placement:
+ mode: SnapgridCenter
+ components:
+ - type: GasMiner
+ spawnGas: CarbonDioxide
+
+- type: entity
+ name: Plasma gas miner
+ parent: GasMinerBase
+ id: GasMinerPlasma
+ placement:
+ mode: SnapgridCenter
+ components:
+ - type: GasMiner
+ spawnGas: Plasma
+
+- type: entity
+ name: Tritium gas miner
+ parent: GasMinerBase
+ id: GasMinerTritium
+ placement:
+ mode: SnapgridCenter
+ components:
+ - type: GasMiner
+ spawnGas: Tritium
+
+- type: entity
+ name: Water Vapor gas miner
+ parent: GasMinerBase
+ id: GasMinerWaterVapor
+ placement:
+ mode: SnapgridCenter
+ components:
+ - type: GasMiner
+ spawnGas: WaterVapor
diff --git a/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/pipes.yml b/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/pipes.yml
index 5a8f4900e3..ac0c0e30f6 100644
--- a/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/pipes.yml
+++ b/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/pipes.yml
@@ -1,6 +1,6 @@
- type: entity
abstract: true
- id: PipeBase
+ id: GasPipeBase
name: pipe
description: Holds gas.
placement:
@@ -11,6 +11,9 @@
- type: Physics
- type: SnapGrid
- type: Damageable
+ - type: Anchorable
+ - type: Rotatable
+ - type: Pullable
- type: Destructible
thresholds:
- trigger:
@@ -20,19 +23,20 @@
- !type:DoActsBehavior
acts: ["Destruction"]
- type: Sprite
+ sprite: Constructible/Atmos/pipe.rsi
+ drawdepth: BelowFloor
netsync: false
- type: Appearance
visuals:
- - type: PipeVisualizer
- type: PipeConnectorVisualizer
- - type: Icon
- sprite: Constructible/Atmos/pipe.rsi
+ - type: NodeContainer
+ - type: AtmosUnsafeUnanchor
-#Note: The PipeDirection of the PipeNode should be the south-facing version, because the entity starts at an angle of 0 (east)
+#Note: The PipeDirection of the PipeNode should be the south-facing version, because the entity starts at an angle of 0 (south)
- type: entity
- parent: PipeBase
- id: PipeHalf
+ parent: GasPipeBase
+ id: GasPipeHalf
suffix: Half
components:
- type: NodeContainer
@@ -41,12 +45,12 @@
!type:PipeNode
nodeGroupID: Pipe
pipeDirection: South
- - type: Icon
+ - type: Sprite
state: pipeHalf
- type: entity
- parent: PipeBase
- id: PipeStraight
+ parent: GasPipeBase
+ id: GasPipeStraight
suffix: Straight
components:
- type: NodeContainer
@@ -55,12 +59,12 @@
!type:PipeNode
nodeGroupID: Pipe
pipeDirection: Longitudinal
- - type: Icon
+ - type: Sprite
state: pipeStraight
- type: entity
- parent: PipeBase
- id: PipeBend
+ parent: GasPipeBase
+ id: GasPipeBend
suffix: Bend
components:
- type: NodeContainer
@@ -69,12 +73,12 @@
!type:PipeNode
nodeGroupID: Pipe
pipeDirection: SWBend
- - type: Icon
+ - type: Sprite
state: pipeBend
- type: entity
- parent: PipeBase
- id: PipeTJunction
+ parent: GasPipeBase
+ id: GasPipeTJunction
suffix: TJunction
components:
- type: NodeContainer
@@ -83,12 +87,12 @@
!type:PipeNode
nodeGroupID: Pipe
pipeDirection: TSouth
- - type: Icon
+ - type: Sprite
state: pipeTJunction
- type: entity
- parent: PipeBase
- id: PipeFourway
+ parent: GasPipeBase
+ id: GasPipeFourway
suffix: Fourway
components:
- type: NodeContainer
@@ -97,5 +101,5 @@
!type:PipeNode
nodeGroupID: Pipe
pipeDirection: Fourway
- - type: Icon
+ - type: Sprite
state: pipeFourway
diff --git a/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/pumps.yml b/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/pumps.yml
deleted file mode 100644
index 1e66dc6370..0000000000
--- a/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/pumps.yml
+++ /dev/null
@@ -1,52 +0,0 @@
-- type: entity
- abstract: true
- id: PumpBase
- placement:
- mode: SnapgridCenter
- components:
- - type: Clickable
- - type: InteractionOutline
- - type: Physics
- - type: SnapGrid
- - type: Damageable
- resistances: metallicResistances
- - type: Destructible
- thresholds:
- - trigger:
- !type:DamageTrigger
- damage: 100
- behaviors:
- - !type:DoActsBehavior
- acts: ["Destruction"]
- - type: Sprite
- netsync: false
- sprite: Constructible/Atmos/pump.rsi
- layers:
- - sprite: Constructible/Atmos/pipe.rsi
- state: pipeStraight
- - state: pumpPressure
- - type: Appearance
- visuals:
- - type: PipeConnectorVisualizer
- - type: PumpVisualizer
- - type: PipeNetDevice
-
-- type: entity
- parent: PumpBase
- id: DebugPressurePump
- name: pressure pump
- suffix: DEBUG
- components:
- - type: NodeContainer
- nodes:
- inlet:
- !type:PipeNode
- nodeGroupID: Pipe
- pipeDirection: North
- outlet:
- !type:PipeNode
- nodeGroupID: Pipe
- pipeDirection: South
- - type: PressurePump
- initialInletDirection: North
- initialOutletDirection: South
diff --git a/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/scrubbers.yml b/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/scrubbers.yml
deleted file mode 100644
index 6d0f2810ab..0000000000
--- a/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/scrubbers.yml
+++ /dev/null
@@ -1,47 +0,0 @@
-- type: entity
- abstract: true
- id: ScrubberBase
- placement:
- mode: SnapgridCenter
- components:
- - type: Clickable
- - type: InteractionOutline
- - type: Physics
- - type: SnapGrid
- - type: Damageable
- resistances: metallicResistances
- - type: Destructible
- thresholds:
- - trigger:
- !type:DamageTrigger
- damage: 100
- behaviors:
- - !type:DoActsBehavior
- acts: ["Destruction"]
- - type: Sprite
- netsync: false
- sprite: Constructible/Atmos/scrubber.rsi
- layers:
- - sprite: Constructible/Atmos/pipe.rsi
- state: pipeHalf
- - state: scrubOff
- - type: Appearance
- visuals:
- - type: PipeConnectorVisualizer
- - type: SiphonVisualizer
- - type: PipeNetDevice
-
-- type: entity
- parent: ScrubberBase
- id: Scrubber
- name: scrubber
- description: Scrubs unwanted gasses out of the air.
- components:
- - type: NodeContainer
- nodes:
- pipe:
- !type:PipeNode
- nodeGroupID: Pipe
- pipeDirection: South
- - type: PressureSiphon
- scrubberOutletDirection: South
diff --git a/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/trinary.yml b/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/trinary.yml
new file mode 100644
index 0000000000..641ad7247e
--- /dev/null
+++ b/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/trinary.yml
@@ -0,0 +1,66 @@
+- type: entity
+ parent: GasPipeBase
+ abstract: true
+ id: GasTrinaryBase
+ placement:
+ mode: SnapgridCenter
+ components:
+ - type: AtmosDevice
+ - type: NodeContainer
+ nodes:
+ inlet:
+ !type:PipeNode
+ nodeGroupID: Pipe
+ pipeDirection: North
+ filter:
+ !type:PipeNode
+ nodeGroupID: Pipe
+ pipeDirection: East
+ outlet:
+ !type:PipeNode
+ nodeGroupID: Pipe
+ pipeDirection: South
+
+- type: entity
+ parent: GasTrinaryBase
+ id: GasFilter
+ name: gas filter
+ description: Very useful for filtering gases.
+ placement:
+ mode: SnapgridCenter
+ components:
+ # TODO ATMOS Improve this sprite and appearance...
+ - type: Sprite
+ netsync: false
+ sprite: Constructible/Atmos/gasfilter.rsi
+ layers:
+ - sprite: Constructible/Atmos/pipe.rsi
+ state: pipeTJunction
+ - state: gasFilter
+ - type: Appearance
+ visuals:
+ - type: PipeConnectorVisualizer
+ - type: GasFilter
+
+- type: entity
+ parent: GasTrinaryBase
+ id: GasMixer
+ name: gas mixer
+ description: Very useful for mixing gases.
+ placement:
+ mode: SnapgridCenter
+ components:
+ # TODO ATMOS Give this its actual sprite...
+ - type: Sprite
+ netsync: false
+ sprite: Constructible/Atmos/gasfilter.rsi
+ layers:
+ - sprite: Constructible/Atmos/pipe.rsi
+ state: pipeTJunction
+ - state: gasFilter
+ - type: Appearance
+ visuals:
+ - type: PipeConnectorVisualizer
+ - type: GasMixer
+ inletOne: inlet
+ inletTwo: filter
diff --git a/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/unary.yml b/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/unary.yml
new file mode 100644
index 0000000000..e46f0bfdb5
--- /dev/null
+++ b/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/unary.yml
@@ -0,0 +1,152 @@
+- type: entity
+ parent: GasPipeBase
+ abstract: true
+ id: GasUnaryBase
+ placement:
+ mode: SnapgridCenter
+ components:
+ - type: AtmosDevice
+ - type: NodeContainer
+ nodes:
+ pipe:
+ !type:PipeNode
+ nodeGroupID: Pipe
+ pipeDirection: South
+
+- type: entity
+ parent: GasUnaryBase
+ id: GasVentPump
+ name: air vent
+ description: Has a valve and a pump attached to it.
+ placement:
+ mode: SnapgridCenter
+ components:
+ - type: Sprite
+ netsync: false
+ sprite: Constructible/Atmos/vent.rsi
+ layers:
+ - sprite: Constructible/Atmos/pipe.rsi
+ state: pipeHalf
+ - state: vent_off
+ map: ["enum.VentVisualLayers.Vent"]
+ - type: Appearance
+ visuals:
+ - type: PipeConnectorVisualizer
+ - type: VentPumpVisualizer
+ - type: GasVentPump
+
+- type: entity
+ parent: GasUnaryBase
+ id: GasPassiveVent
+ name: passive vent
+ description: It is an open vent.
+ placement:
+ mode: SnapgridCenter
+ components:
+ # TODO ATMOS: Find sprite for this.
+ - type: Sprite
+ netsync: false
+ sprite: Constructible/Atmos/vent.rsi
+ layers:
+ - sprite: Constructible/Atmos/pipe.rsi
+ state: pipeHalf
+ - state: vent_off
+ - type: Appearance
+ visuals:
+ - type: PipeConnectorVisualizer
+ - type: GasPassiveVent
+
+- type: entity
+ parent: GasUnaryBase
+ id: GasVentScrubber
+ name: air scrubber
+ description: Has a valve and pump attached to it.
+ placement:
+ mode: SnapgridCenter
+ components:
+ - type: Sprite
+ netsync: false
+ sprite: Constructible/Atmos/scrubber.rsi
+ layers:
+ - sprite: Constructible/Atmos/pipe.rsi
+ state: pipeHalf
+ - state: scrub_off
+ map: ["enum.ScrubberVisualLayers.Scrubber"]
+ - type: Appearance
+ visuals:
+ - type: PipeConnectorVisualizer
+ - type: ScrubberVisualizer
+ - type: AtmosDevice
+ - type: GasVentScrubber
+
+- type: entity
+ parent: GasUnaryBase
+ id: GasOutletInjector
+ name: air injector
+ description: Has a valve and pump attached to it.
+ placement:
+ mode: SnapgridCenter
+ components:
+ - type: GasOutletInjector
+ # TODO ATMOS: Actual sprite for this.
+ - type: Sprite
+ netsync: false
+ sprite: Constructible/Atmos/pipe.rsi
+ state: pipeHalf
+
+
+- type: entity
+ parent: GasUnaryBase
+ id: GasThermoMachineBase
+ name: thermomachine
+ description: Heats or cools gas in connected pipes.
+ abstract: true
+ placement:
+ mode: SnapgridCenter
+ components:
+ - type: Sprite
+ netsync: false
+ sprite: Constructible/Atmos/thermomachine.rsi
+ - type: Appearance
+ visuals:
+ - type: PipeConnectorVisualizer
+ - type: GasThermoMachine
+
+- type: entity
+ parent: GasThermoMachineBase
+ id: GasThermoMachineFreezer
+ name: freezer
+ placement:
+ mode: SnapgridCenter
+ components:
+ - type: Sprite
+ layers:
+ - state: freezer_off
+ - state: pipe
+ - type: Appearance
+ visuals:
+ - type: ThermoMachineVisualizer
+ enabledState: freezer_on
+ - type: GasThermoMachine
+ mode: Freezer
+ minTemperature: 73.15
+
+- type: entity
+ parent: GasThermoMachineBase
+ id: GasThermoMachineHeater
+ name: heater
+ placement:
+ mode: SnapgridCenter
+ components:
+ - type: Sprite
+ layers:
+ - state: heater_off
+ - state: pipe
+ - type: Appearance
+ visuals:
+ - type: ThermoMachineVisualizer
+ enabledState: heater_on
+ - type: GasThermoMachine
+ mode: Heater
+ maxTemperature: 573.15 # This is changed when parts are refreshed.
+
diff --git a/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/vents.yml b/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/vents.yml
deleted file mode 100644
index f626eb112d..0000000000
--- a/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/vents.yml
+++ /dev/null
@@ -1,47 +0,0 @@
-- type: entity
- abstract: true
- id: VentBase
- placement:
- mode: SnapgridCenter
- components:
- - type: Clickable
- - type: InteractionOutline
- - type: Physics
- - type: SnapGrid
- - type: Damageable
- resistances: metallicResistances
- - type: Destructible
- thresholds:
- - trigger:
- !type:DamageTrigger
- damage: 100
- behaviors:
- - !type:DoActsBehavior
- acts: ["Destruction"]
- - type: Sprite
- netsync: false
- sprite: Constructible/Atmos/vent.rsi
- layers:
- - sprite: Constructible/Atmos/pipe.rsi
- state: pipeHalf
- - state: ventOff
- - type: Appearance
- visuals:
- - type: PipeConnectorVisualizer
- - type: VentVisualizer
- - type: PipeNetDevice
-
-- type: entity
- parent: VentBase
- id: Vent
- name: vent
- description: A vent that releases gas.
- components:
- - type: NodeContainer
- nodes:
- pipe:
- !type:PipeNode
- nodeGroupID: Pipe
- pipeDirection: South
- - type: PressureVent
- ventInletDirection: South
diff --git a/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml b/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml
index 4c93eab341..1d1c2f9de8 100644
--- a/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml
+++ b/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml
@@ -13,6 +13,15 @@
- type: Clothing
sprite: Objects/Tanks/generic.rsi
QuickEquip: false
+ - type: NodeContainer
+ nodes:
+ tank:
+ !type:PipeNode
+ nodeGroupID: Pipe
+ pipeDirection: None
+ connectionsEnabled: false
+ needAnchored: false
+ rotationsEnabled: false
- type: GasTank
- type: ItemActions
actions:
diff --git a/Resources/Textures/Constructible/Atmos/heater.rsi/meta.json b/Resources/Textures/Constructible/Atmos/heater.rsi/meta.json
deleted file mode 100644
index 3d46d2680e..0000000000
--- a/Resources/Textures/Constructible/Atmos/heater.rsi/meta.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "version":1,
- "size":{
- "x":32,
- "y":32
- },
- "license":"CC-BY-SA-3.0",
- "copyright":"Taken from https://github.com/tgstation/tgstation at commit 57cd1d59ca019dd0e7811ac451f295f818e573da",
- "states":[
- {
- "name":"heater",
- },
- {
- "name":"heaterOn",
- },
- {
- "name":"heaterPipe",
- "directions":4,
- }
- ]
-}
\ No newline at end of file
diff --git a/Resources/Textures/Constructible/Atmos/miners.rsi/broken.png b/Resources/Textures/Constructible/Atmos/miners.rsi/broken.png
new file mode 100644
index 0000000000..0167f63ebd
Binary files /dev/null and b/Resources/Textures/Constructible/Atmos/miners.rsi/broken.png differ
diff --git a/Resources/Textures/Constructible/Atmos/miners.rsi/meta.json b/Resources/Textures/Constructible/Atmos/miners.rsi/meta.json
new file mode 100644
index 0000000000..d8bdbb7c58
--- /dev/null
+++ b/Resources/Textures/Constructible/Atmos/miners.rsi/meta.json
@@ -0,0 +1 @@
+{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/b9982f69706135ceea703817586128b298cbf5e5", "states": [{"name": "broken", "directions": 1, "delays": [[0.5, 0.1, 0.3, 0.1]]}, {"name": "miner", "directions": 1, "delays": [[1.0]]}, {"name": "on", "directions": 1, "delays": [[0.1, 0.1, 0.1, 0.1]]}]}
\ No newline at end of file
diff --git a/Resources/Textures/Constructible/Atmos/miners.rsi/miner.png b/Resources/Textures/Constructible/Atmos/miners.rsi/miner.png
new file mode 100644
index 0000000000..5d1ec5d4bf
Binary files /dev/null and b/Resources/Textures/Constructible/Atmos/miners.rsi/miner.png differ
diff --git a/Resources/Textures/Constructible/Atmos/miners.rsi/on.png b/Resources/Textures/Constructible/Atmos/miners.rsi/on.png
new file mode 100644
index 0000000000..34de93d7f7
Binary files /dev/null and b/Resources/Textures/Constructible/Atmos/miners.rsi/on.png differ
diff --git a/Resources/Textures/Constructible/Atmos/scrubber.rsi/meta.json b/Resources/Textures/Constructible/Atmos/scrubber.rsi/meta.json
index 938ce0b273..3c43fab8d5 100644
--- a/Resources/Textures/Constructible/Atmos/scrubber.rsi/meta.json
+++ b/Resources/Textures/Constructible/Atmos/scrubber.rsi/meta.json
@@ -8,11 +8,27 @@
"copyright":"Taken from https://github.com/tgstation/tgstation at commit 57cd1d59ca019dd0e7811ac451f295f818e573da",
"states":[
{
- "name":"scrubOff",
+ "name":"scrub_off",
+ "directions": 4,
},
{
- "name":"scrubOn",
- "delays":[ [ 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08 ] ]
- }
+ "name":"scrub_welded",
+ "directions": 4,
+ },
+ {
+ "name":"scrub_on",
+ "directions": 4,
+ "delays": [[0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08], [0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08], [0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08], [0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08]]
+ },
+ {
+ "name": "scrub_purge",
+ "directions": 4,
+ "delays": [[0.2, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04], [0.2, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04], [0.2, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04], [0.2, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04]]
+ },
+ {
+ "name": "scrub_wide",
+ "directions": 4,
+ "delays": [[0.2, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04], [0.2, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04], [0.2, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04], [0.2, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04]]
+ },
]
}
diff --git a/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrubOff.png b/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrubOff.png
deleted file mode 100644
index f5a52006b5..0000000000
Binary files a/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrubOff.png and /dev/null differ
diff --git a/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrubOn.png b/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrubOn.png
deleted file mode 100644
index 06a975cc5a..0000000000
Binary files a/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrubOn.png and /dev/null differ
diff --git a/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrub_off.png b/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrub_off.png
new file mode 100644
index 0000000000..efc173d893
Binary files /dev/null and b/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrub_off.png differ
diff --git a/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrub_on.png b/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrub_on.png
new file mode 100644
index 0000000000..9bc5d8c0bf
Binary files /dev/null and b/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrub_on.png differ
diff --git a/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrub_purge.png b/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrub_purge.png
new file mode 100644
index 0000000000..75ba6d6de0
Binary files /dev/null and b/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrub_purge.png differ
diff --git a/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrub_welded.png b/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrub_welded.png
new file mode 100644
index 0000000000..96ab7b0825
Binary files /dev/null and b/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrub_welded.png differ
diff --git a/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrub_wide.png b/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrub_wide.png
new file mode 100644
index 0000000000..087777a888
Binary files /dev/null and b/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrub_wide.png differ
diff --git a/Resources/Textures/Constructible/Atmos/thermomachine.rsi/freezer_off.png b/Resources/Textures/Constructible/Atmos/thermomachine.rsi/freezer_off.png
new file mode 100644
index 0000000000..d47969aaeb
Binary files /dev/null and b/Resources/Textures/Constructible/Atmos/thermomachine.rsi/freezer_off.png differ
diff --git a/Resources/Textures/Constructible/Atmos/thermomachine.rsi/freezer_on.png b/Resources/Textures/Constructible/Atmos/thermomachine.rsi/freezer_on.png
new file mode 100644
index 0000000000..fdf6db8d6e
Binary files /dev/null and b/Resources/Textures/Constructible/Atmos/thermomachine.rsi/freezer_on.png differ
diff --git a/Resources/Textures/Constructible/Atmos/thermomachine.rsi/freezer_open.png b/Resources/Textures/Constructible/Atmos/thermomachine.rsi/freezer_open.png
new file mode 100644
index 0000000000..87e8042e84
Binary files /dev/null and b/Resources/Textures/Constructible/Atmos/thermomachine.rsi/freezer_open.png differ
diff --git a/Resources/Textures/Constructible/Atmos/heater.rsi/heater.png b/Resources/Textures/Constructible/Atmos/thermomachine.rsi/heater_off.png
similarity index 100%
rename from Resources/Textures/Constructible/Atmos/heater.rsi/heater.png
rename to Resources/Textures/Constructible/Atmos/thermomachine.rsi/heater_off.png
diff --git a/Resources/Textures/Constructible/Atmos/heater.rsi/heaterOn.png b/Resources/Textures/Constructible/Atmos/thermomachine.rsi/heater_on.png
similarity index 100%
rename from Resources/Textures/Constructible/Atmos/heater.rsi/heaterOn.png
rename to Resources/Textures/Constructible/Atmos/thermomachine.rsi/heater_on.png
diff --git a/Resources/Textures/Constructible/Atmos/thermomachine.rsi/heater_open.png b/Resources/Textures/Constructible/Atmos/thermomachine.rsi/heater_open.png
new file mode 100644
index 0000000000..9cbe10c974
Binary files /dev/null and b/Resources/Textures/Constructible/Atmos/thermomachine.rsi/heater_open.png differ
diff --git a/Resources/Textures/Constructible/Atmos/thermomachine.rsi/meta.json b/Resources/Textures/Constructible/Atmos/thermomachine.rsi/meta.json
new file mode 100644
index 0000000000..e523408dda
--- /dev/null
+++ b/Resources/Textures/Constructible/Atmos/thermomachine.rsi/meta.json
@@ -0,0 +1 @@
+{"version": 1, "size": {"x": 32, "y": 32}, "states": [{"name": "freezer_off", "directions": 1, "delays": [[1.0]]}, {"name": "freezer_open", "directions": 1, "delays": [[1.0]]}, {"name": "freezer_on", "directions": 1, "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]}, {"name": "heater_off", "directions": 1, "delays": [[1.0]]}, {"name": "heater_open", "directions": 1, "delays": [[1.0]]}, {"name": "heater_on", "directions": 1, "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]}, {"name": "pipe", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}]}
\ No newline at end of file
diff --git a/Resources/Textures/Constructible/Atmos/heater.rsi/heaterPipe.png b/Resources/Textures/Constructible/Atmos/thermomachine.rsi/pipe.png
similarity index 100%
rename from Resources/Textures/Constructible/Atmos/heater.rsi/heaterPipe.png
rename to Resources/Textures/Constructible/Atmos/thermomachine.rsi/pipe.png
diff --git a/Resources/Textures/Constructible/Atmos/vent.rsi/meta.json b/Resources/Textures/Constructible/Atmos/vent.rsi/meta.json
index d1c58a5057..2229d6a6ae 100644
--- a/Resources/Textures/Constructible/Atmos/vent.rsi/meta.json
+++ b/Resources/Textures/Constructible/Atmos/vent.rsi/meta.json
@@ -5,14 +5,25 @@
"y":32
},
"license":"CC-BY-SA-3.0",
- "copyright":"Taken from https://github.com/tgstation/tgstation at commit 57cd1d59ca019dd0e7811ac451f295f818e573da",
+ "copyright":"Taken from https://github.com/BeeStation/BeeStation-Hornet at commit 4ccd79de285e79e504308bcd6fa5908d6b7685f7",
"states":[
{
- "name":"ventOff",
+ "name":"vent_off",
+ "directions" : 4,
},
{
- "name":"ventOn",
- "delays":[ [ 0.08, 0.08, 0.08, 0.08 ] ]
+ "name":"vent_welded",
+ "directions" : 4,
+ },
+ {
+ "name":"vent_out",
+ "directions" : 4,
+ "delays":[ [ 0.08, 0.08, 0.08, 0.08 ], [ 0.08, 0.08, 0.08, 0.08 ], [ 0.08, 0.08, 0.08, 0.08 ], [ 0.08, 0.08, 0.08, 0.08 ] ]
+ },
+ {
+ "name":"vent_in",
+ "directions" : 4,
+ "delays":[ [ 0.08, 0.08, 0.08, 0.08 ], [ 0.08, 0.08, 0.08, 0.08 ], [ 0.08, 0.08, 0.08, 0.08 ], [ 0.08, 0.08, 0.08, 0.08 ] ]
}
]
}
\ No newline at end of file
diff --git a/Resources/Textures/Constructible/Atmos/vent.rsi/ventOff.png b/Resources/Textures/Constructible/Atmos/vent.rsi/ventOff.png
deleted file mode 100644
index 4b8d5db40e..0000000000
Binary files a/Resources/Textures/Constructible/Atmos/vent.rsi/ventOff.png and /dev/null differ
diff --git a/Resources/Textures/Constructible/Atmos/vent.rsi/ventOn.png b/Resources/Textures/Constructible/Atmos/vent.rsi/ventOn.png
deleted file mode 100644
index 33d42b8b10..0000000000
Binary files a/Resources/Textures/Constructible/Atmos/vent.rsi/ventOn.png and /dev/null differ
diff --git a/Resources/Textures/Constructible/Atmos/vent.rsi/vent_in.png b/Resources/Textures/Constructible/Atmos/vent.rsi/vent_in.png
new file mode 100644
index 0000000000..cf1b050c02
Binary files /dev/null and b/Resources/Textures/Constructible/Atmos/vent.rsi/vent_in.png differ
diff --git a/Resources/Textures/Constructible/Atmos/vent.rsi/vent_off.png b/Resources/Textures/Constructible/Atmos/vent.rsi/vent_off.png
new file mode 100644
index 0000000000..6208c59db7
Binary files /dev/null and b/Resources/Textures/Constructible/Atmos/vent.rsi/vent_off.png differ
diff --git a/Resources/Textures/Constructible/Atmos/vent.rsi/vent_out.png b/Resources/Textures/Constructible/Atmos/vent.rsi/vent_out.png
new file mode 100644
index 0000000000..e038706b0e
Binary files /dev/null and b/Resources/Textures/Constructible/Atmos/vent.rsi/vent_out.png differ
diff --git a/Resources/Textures/Constructible/Atmos/vent.rsi/vent_welded.png b/Resources/Textures/Constructible/Atmos/vent.rsi/vent_welded.png
new file mode 100644
index 0000000000..b45ae1cb5f
Binary files /dev/null and b/Resources/Textures/Constructible/Atmos/vent.rsi/vent_welded.png differ
diff --git a/SpaceStation14.sln.DotSettings b/SpaceStation14.sln.DotSettings
index 53475c1f5b..b12e94269e 100644
--- a/SpaceStation14.sln.DotSettings
+++ b/SpaceStation14.sln.DotSettings
@@ -142,6 +142,7 @@
True
True
True
+ True
True
True
True
@@ -166,6 +167,7 @@
True
True
True
+ True
True
True
True