diff --git a/Content.Client/Atmos/UI/GasPressurePumpBoundUserInterface.cs b/Content.Client/Atmos/UI/GasPressurePumpBoundUserInterface.cs
new file mode 100644
index 0000000000..95b305a99d
--- /dev/null
+++ b/Content.Client/Atmos/UI/GasPressurePumpBoundUserInterface.cs
@@ -0,0 +1,79 @@
+using System;
+using Content.Client.Atmos.EntitySystems;
+using Content.Shared.Atmos;
+using Content.Shared.Atmos.Piping.Binary.Components;
+using Content.Shared.Atmos.Piping.Trinary.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 GasPressurePumpBoundUserInterface : BoundUserInterface
+ {
+
+ private GasPressurePumpWindow? _window;
+ private const float MaxPressure = Atmospherics.MaxOutputPressure;
+
+ public GasPressurePumpBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
+ {
+ }
+
+ protected override void Open()
+ {
+ base.Open();
+
+ _window = new GasPressurePumpWindow();
+
+ if(State != null)
+ UpdateState(State);
+
+ _window.OpenCentered();
+
+ _window.OnClose += Close;
+
+ _window.ToggleStatusButtonPressed += OnToggleStatusButtonPressed;
+ _window.PumpOutputPressureChanged += OnPumpOutputPressurePressed;
+ }
+
+ private void OnToggleStatusButtonPressed()
+ {
+ if (_window is null) return;
+ SendMessage(new GasPressurePumpToggleStatusMessage(_window.PumpStatus));
+ }
+
+ private void OnPumpOutputPressurePressed(string value)
+ {
+ float pressure = float.TryParse(value, out var parsed) ? parsed : 0f;
+ if (pressure > MaxPressure) pressure = MaxPressure;
+
+ SendMessage(new GasPressurePumpChangeOutputPressureMessage(pressure));
+ }
+
+ ///
+ /// Update the UI state based on server-sent info
+ ///
+ ///
+ protected override void UpdateState(BoundUserInterfaceState state)
+ {
+ base.UpdateState(state);
+ if (_window == null || state is not GasPressurePumpBoundUserInterfaceState cast)
+ return;
+
+ _window.Title = (cast.PumpLabel);
+ _window.SetPumpStatus(cast.Enabled);
+ _window.SetOutputPressure(cast.OutputPressure);
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+ if (!disposing) return;
+ _window?.Dispose();
+ }
+ }
+}
diff --git a/Content.Client/Atmos/UI/GasPressurePumpWindow.xaml b/Content.Client/Atmos/UI/GasPressurePumpWindow.xaml
new file mode 100644
index 0000000000..94520a584d
--- /dev/null
+++ b/Content.Client/Atmos/UI/GasPressurePumpWindow.xaml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/Atmos/UI/GasPressurePumpWindow.xaml.cs b/Content.Client/Atmos/UI/GasPressurePumpWindow.xaml.cs
new file mode 100644
index 0000000000..05b3062aa6
--- /dev/null
+++ b/Content.Client/Atmos/UI/GasPressurePumpWindow.xaml.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using Content.Client.Atmos.EntitySystems;
+using Content.Shared.Atmos;
+using Content.Shared.Atmos.Prototypes;
+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 gas pressure pump.
+ ///
+ [GenerateTypedNameReferences]
+ public partial class GasPressurePumpWindow : SS14Window
+ {
+ public bool PumpStatus = true;
+
+ public event Action? ToggleStatusButtonPressed;
+ public event Action? PumpOutputPressureChanged;
+
+ public GasPressurePumpWindow()
+ {
+ RobustXamlLoader.Load(this);
+
+ ToggleStatusButton.OnPressed += _ => SetPumpStatus(!PumpStatus);
+ ToggleStatusButton.OnPressed += _ => ToggleStatusButtonPressed?.Invoke();
+
+ PumpPressureOutputInput.OnTextChanged += _ => SetOutputPressureButton.Disabled = false;
+ SetOutputPressureButton.OnPressed += _ =>
+ {
+ PumpOutputPressureChanged?.Invoke(PumpPressureOutputInput.Text ??= "");
+ SetOutputPressureButton.Disabled = true;
+ };
+
+ SetMaxPressureButton.OnPressed += _ =>
+ {
+ PumpPressureOutputInput.Text = Atmospherics.MaxOutputPressure.ToString(CultureInfo.InvariantCulture);
+ SetOutputPressureButton.Disabled = false;
+ };
+ }
+
+ public void SetOutputPressure(float pressure)
+ {
+ PumpPressureOutputInput.Text = pressure.ToString(CultureInfo.InvariantCulture);
+ }
+
+ public void SetPumpStatus(bool enabled)
+ {
+ PumpStatus = enabled;
+ if (enabled)
+ {
+ ToggleStatusButton.Text = Loc.GetString("comp-gas-pump-ui-status-enabled");
+ }
+ else
+ {
+ ToggleStatusButton.Text = Loc.GetString("comp-gas-pump-ui-status-disabled");
+ }
+ }
+ }
+}
diff --git a/Content.Client/Atmos/UI/GasVolumePumpBoundUserInterface.cs b/Content.Client/Atmos/UI/GasVolumePumpBoundUserInterface.cs
new file mode 100644
index 0000000000..6fa2b510c3
--- /dev/null
+++ b/Content.Client/Atmos/UI/GasVolumePumpBoundUserInterface.cs
@@ -0,0 +1,76 @@
+using Content.Shared.Atmos;
+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 GasVolumePumpBoundUserInterface : BoundUserInterface
+ {
+
+ private GasVolumePumpWindow? _window;
+ private const float MaxTransferRate = Atmospherics.MaxTransferRate;
+
+ public GasVolumePumpBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
+ {
+ }
+
+ protected override void Open()
+ {
+ base.Open();
+
+ _window = new GasVolumePumpWindow();
+
+ if(State != null)
+ UpdateState(State);
+
+ _window.OpenCentered();
+
+ _window.OnClose += Close;
+
+ _window.ToggleStatusButtonPressed += OnToggleStatusButtonPressed;
+ _window.PumpTransferRateChanged += OnPumpTransferRatePressed;
+ }
+
+ private void OnToggleStatusButtonPressed()
+ {
+ if (_window is null) return;
+ SendMessage(new GasVolumePumpToggleStatusMessage(_window.PumpStatus));
+ }
+
+ private void OnPumpTransferRatePressed(string value)
+ {
+ float rate = float.TryParse(value, out var parsed) ? parsed : 0f;
+ if (rate > MaxTransferRate) rate = MaxTransferRate;
+
+ SendMessage(new GasVolumePumpChangeTransferRateMessage(rate));
+ }
+
+ ///
+ /// Update the UI state based on server-sent info
+ ///
+ ///
+ protected override void UpdateState(BoundUserInterfaceState state)
+ {
+ base.UpdateState(state);
+ if (_window == null || state is not GasVolumePumpBoundUserInterfaceState cast)
+ return;
+
+ _window.Title = (cast.PumpLabel);
+ _window.SetPumpStatus(cast.Enabled);
+ _window.SetTransferRate(cast.TransferRate);
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+ if (!disposing) return;
+ _window?.Dispose();
+ }
+ }
+}
diff --git a/Content.Client/Atmos/UI/GasVolumePumpWindow.xaml b/Content.Client/Atmos/UI/GasVolumePumpWindow.xaml
new file mode 100644
index 0000000000..17ac96d702
--- /dev/null
+++ b/Content.Client/Atmos/UI/GasVolumePumpWindow.xaml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/Atmos/UI/GasVolumePumpWindow.xaml.cs b/Content.Client/Atmos/UI/GasVolumePumpWindow.xaml.cs
new file mode 100644
index 0000000000..aea59971ab
--- /dev/null
+++ b/Content.Client/Atmos/UI/GasVolumePumpWindow.xaml.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using Content.Client.Atmos.EntitySystems;
+using Content.Shared.Atmos;
+using Content.Shared.Atmos.Prototypes;
+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 gas volume pump.
+ ///
+ [GenerateTypedNameReferences]
+ public partial class GasVolumePumpWindow : SS14Window
+ {
+ public bool PumpStatus = true;
+
+ public event Action? ToggleStatusButtonPressed;
+ public event Action? PumpTransferRateChanged;
+
+ public GasVolumePumpWindow()
+ {
+ RobustXamlLoader.Load(this);
+
+ ToggleStatusButton.OnPressed += _ => SetPumpStatus(!PumpStatus);
+ ToggleStatusButton.OnPressed += _ => ToggleStatusButtonPressed?.Invoke();
+
+ PumpTransferRateInput.OnTextChanged += _ => SetTransferRateButton.Disabled = false;
+ SetTransferRateButton.OnPressed += _ =>
+ {
+ PumpTransferRateChanged?.Invoke(PumpTransferRateInput.Text ??= "");
+ SetTransferRateButton.Disabled = true;
+ };
+
+ SetMaxRateButton.OnPressed += _ =>
+ {
+ PumpTransferRateInput.Text = Atmospherics.MaxTransferRate.ToString(CultureInfo.InvariantCulture);
+ SetTransferRateButton.Disabled = false;
+ };
+ }
+
+ public void SetTransferRate(float rate)
+ {
+ PumpTransferRateInput.Text = rate.ToString(CultureInfo.InvariantCulture);
+ }
+
+ public void SetPumpStatus(bool enabled)
+ {
+ PumpStatus = enabled;
+ if (enabled)
+ {
+ ToggleStatusButton.Text = Loc.GetString("comp-gas-pump-ui-status-enabled");
+ }
+ else
+ {
+ ToggleStatusButton.Text = Loc.GetString("comp-gas-pump-ui-status-disabled");
+ }
+ }
+ }
+}
diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs
index 89baa911d1..fdb0b99f21 100644
--- a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs
+++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs
@@ -1,13 +1,17 @@
+using System;
using Content.Server.Atmos.Piping.Binary.Components;
using Content.Server.Atmos.Piping.Components;
using Content.Server.NodeContainer;
using Content.Server.NodeContainer.Nodes;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Piping;
+using Content.Shared.Atmos.Piping.Binary.Components;
using Content.Shared.Examine;
+using Content.Shared.Interaction;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
@@ -16,6 +20,8 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
[UsedImplicitly]
public class GasPressurePumpSystem : EntitySystem
{
+ [Dependency] private UserInterfaceSystem _userInterfaceSystem = default!;
+
public override void Initialize()
{
base.Initialize();
@@ -23,6 +29,10 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
SubscribeLocalEvent(OnPumpUpdated);
SubscribeLocalEvent(OnPumpLeaveAtmosphere);
SubscribeLocalEvent(OnExamined);
+ SubscribeLocalEvent(OnPumpInteractHand);
+ // Bound UI subscriptions
+ SubscribeLocalEvent(OnOutputPressureChangeMessage);
+ SubscribeLocalEvent(OnToggleStatusMessage);
}
private void OnExamined(EntityUid uid, GasPressurePumpComponent pump, ExaminedEvent args)
@@ -79,5 +89,37 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
}
}
+ private void OnPumpInteractHand(EntityUid uid, GasPressurePumpComponent component, InteractHandEvent args)
+ {
+ if (!args.User.TryGetComponent(out ActorComponent? actor))
+ return;
+
+ _userInterfaceSystem.TryOpen(uid, GasPressurePumpUiKey.Key, actor.PlayerSession);
+ DirtyUI(uid, component);
+
+ args.Handled = true;
+ }
+
+ private void OnToggleStatusMessage(EntityUid uid, GasPressurePumpComponent pump, GasPressurePumpToggleStatusMessage args)
+ {
+ pump.Enabled = args.Enabled;
+ DirtyUI(uid, pump);
+ }
+
+ private void OnOutputPressureChangeMessage(EntityUid uid, GasPressurePumpComponent pump, GasPressurePumpChangeOutputPressureMessage args)
+ {
+ pump.TargetPressure = Math.Clamp(args.Pressure, 0f, Atmospherics.MaxOutputPressure);
+ DirtyUI(uid, pump);
+
+ }
+
+ private void DirtyUI(EntityUid uid, GasPressurePumpComponent? pump)
+ {
+ if (!Resolve(uid, ref pump))
+ return;
+
+ _userInterfaceSystem.TrySetUiState(uid, GasPressurePumpUiKey.Key,
+ new GasPressurePumpBoundUserInterfaceState(pump.Owner.Name, pump.TargetPressure, pump.Enabled));
+ }
}
}
diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs
index 75b4d9162f..a10ba64dc9 100644
--- a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs
+++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs
@@ -1,10 +1,15 @@
+using System;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Atmos.Piping.Binary.Components;
using Content.Server.Atmos.Piping.Components;
using Content.Server.NodeContainer;
using Content.Server.NodeContainer.Nodes;
+using Content.Shared.Atmos;
+using Content.Shared.Atmos.Piping.Binary.Components;
using Content.Shared.Examine;
+using Content.Shared.Interaction;
using JetBrains.Annotations;
+using Robust.Server.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
@@ -17,6 +22,7 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
{
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
+ [Dependency] private UserInterfaceSystem _userInterfaceSystem = default!;
public override void Initialize()
{
@@ -24,6 +30,10 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
SubscribeLocalEvent(OnVolumePumpUpdated);
SubscribeLocalEvent(OnExamined);
+ SubscribeLocalEvent(OnPumpInteractHand);
+ // Bound UI subscriptions
+ SubscribeLocalEvent(OnTransferRateChangeMessage);
+ SubscribeLocalEvent(OnToggleStatusMessage);
}
private void OnExamined(EntityUid uid, GasVolumePumpComponent pump, ExaminedEvent args)
@@ -83,5 +93,38 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
outlet.AssumeAir(removed);
}
+
+ private void OnPumpInteractHand(EntityUid uid, GasVolumePumpComponent component, InteractHandEvent args)
+ {
+ if (!args.User.TryGetComponent(out ActorComponent? actor))
+ return;
+
+ _userInterfaceSystem.TryOpen(uid, GasVolumePumpUiKey.Key, actor.PlayerSession);
+ DirtyUI(uid, component);
+
+ args.Handled = true;
+ }
+
+ private void OnToggleStatusMessage(EntityUid uid, GasVolumePumpComponent pump, GasVolumePumpToggleStatusMessage args)
+ {
+ pump.Enabled = args.Enabled;
+ DirtyUI(uid, pump);
+ }
+
+ private void OnTransferRateChangeMessage(EntityUid uid, GasVolumePumpComponent pump, GasVolumePumpChangeTransferRateMessage args)
+ {
+ pump.TransferRate = Math.Clamp(args.TransferRate, 0f, Atmospherics.MaxTransferRate);
+ DirtyUI(uid, pump);
+
+ }
+
+ private void DirtyUI(EntityUid uid, GasVolumePumpComponent? pump)
+ {
+ if (!Resolve(uid, ref pump))
+ return;
+
+ _userInterfaceSystem.TrySetUiState(uid, GasVolumePumpUiKey.Key,
+ new GasVolumePumpBoundUserInterfaceState(pump.Owner.Name, pump.TransferRate, pump.Enabled));
+ }
}
}
diff --git a/Content.Shared/Atmos/Piping/Binary/Components/SharedGasPressurePumpComponent.cs b/Content.Shared/Atmos/Piping/Binary/Components/SharedGasPressurePumpComponent.cs
new file mode 100644
index 0000000000..4303c6977a
--- /dev/null
+++ b/Content.Shared/Atmos/Piping/Binary/Components/SharedGasPressurePumpComponent.cs
@@ -0,0 +1,49 @@
+using System;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Atmos.Piping.Binary.Components
+{
+ [Serializable, NetSerializable]
+ public enum GasPressurePumpUiKey
+ {
+ Key,
+ }
+
+ [Serializable, NetSerializable]
+ public class GasPressurePumpBoundUserInterfaceState : BoundUserInterfaceState
+ {
+ public string PumpLabel { get; }
+ public float OutputPressure { get; }
+ public bool Enabled { get; }
+
+ public GasPressurePumpBoundUserInterfaceState(string pumpLabel, float outputPressure, bool enabled)
+ {
+ PumpLabel = pumpLabel;
+ OutputPressure = outputPressure;
+ Enabled = enabled;
+ }
+ }
+
+ [Serializable, NetSerializable]
+ public class GasPressurePumpToggleStatusMessage : BoundUserInterfaceMessage
+ {
+ public bool Enabled { get; }
+
+ public GasPressurePumpToggleStatusMessage(bool enabled)
+ {
+ Enabled = enabled;
+ }
+ }
+
+ [Serializable, NetSerializable]
+ public class GasPressurePumpChangeOutputPressureMessage : BoundUserInterfaceMessage
+ {
+ public float Pressure { get; }
+
+ public GasPressurePumpChangeOutputPressureMessage(float pressure)
+ {
+ Pressure = pressure;
+ }
+ }
+}
diff --git a/Content.Shared/Atmos/Piping/Binary/Components/SharedGasVolumePumpComponent.cs b/Content.Shared/Atmos/Piping/Binary/Components/SharedGasVolumePumpComponent.cs
new file mode 100644
index 0000000000..50f13decf6
--- /dev/null
+++ b/Content.Shared/Atmos/Piping/Binary/Components/SharedGasVolumePumpComponent.cs
@@ -0,0 +1,49 @@
+using System;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Atmos.Piping.Binary.Components
+{
+ [Serializable, NetSerializable]
+ public enum GasVolumePumpUiKey
+ {
+ Key,
+ }
+
+ [Serializable, NetSerializable]
+ public class GasVolumePumpBoundUserInterfaceState : BoundUserInterfaceState
+ {
+ public string PumpLabel { get; }
+ public float TransferRate { get; }
+ public bool Enabled { get; }
+
+ public GasVolumePumpBoundUserInterfaceState(string pumpLabel, float transferRate, bool enabled)
+ {
+ PumpLabel = pumpLabel;
+ TransferRate = transferRate;
+ Enabled = enabled;
+ }
+ }
+
+ [Serializable, NetSerializable]
+ public class GasVolumePumpToggleStatusMessage : BoundUserInterfaceMessage
+ {
+ public bool Enabled { get; }
+
+ public GasVolumePumpToggleStatusMessage(bool enabled)
+ {
+ Enabled = enabled;
+ }
+ }
+
+ [Serializable, NetSerializable]
+ public class GasVolumePumpChangeTransferRateMessage : BoundUserInterfaceMessage
+ {
+ public float TransferRate { get; }
+
+ public GasVolumePumpChangeTransferRateMessage(float transferRate)
+ {
+ TransferRate = transferRate;
+ }
+ }
+}
diff --git a/Resources/Locale/en-US/components/gas-pump-component.ftl b/Resources/Locale/en-US/components/gas-pump-component.ftl
new file mode 100644
index 0000000000..f1fb95f812
--- /dev/null
+++ b/Resources/Locale/en-US/components/gas-pump-component.ftl
@@ -0,0 +1,10 @@
+comp-gas-pump-ui-pump-status = Status:
+comp-gas-pump-ui-status-enabled = On
+comp-gas-pump-ui-status-disabled = Off
+
+comp-gas-pump-ui-pump-set-rate = Set
+comp-gas-pump-ui-pump-set-max = Max
+
+comp-gas-pump-ui-pump-output-pressure = Output Pressure (kPa):
+
+comp-gas-pump-ui-pump-transfer-rate = Transfer Rate (L/s):
diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/binary.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/binary.yml
index c62a227933..fb79061722 100644
--- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/binary.yml
+++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/binary.yml
@@ -43,6 +43,10 @@
disabledState: pumpPressure
enabledState: pumpPressureOn
- type: GasPressurePump
+ - type: UserInterface
+ interfaces:
+ - key: enum.GasPressurePumpUiKey.Key
+ type: GasPressurePumpBoundUserInterface
- type: entity
parent: GasBinaryBase
@@ -67,6 +71,10 @@
- type: PipeConnectorVisualizer
- type: PipeColorVisualizer
- type: GasVolumePump
+ - type: UserInterface
+ interfaces:
+ - key: enum.GasVolumePumpUiKey.Key
+ type: GasVolumePumpBoundUserInterface
- type: entity
parent: GasBinaryBase