]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Predicted gas pumps (#33717)
authormetalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Sat, 7 Dec 2024 03:39:52 +0000 (14:39 +1100)
committerGitHub <noreply@github.com>
Sat, 7 Dec 2024 03:39:52 +0000 (14:39 +1100)
* Predicted gas pumps

I wanted to try out atmos and first thing I found.

* a

* Remove details range

26 files changed:
Content.Client/Atmos/EntitySystems/GasPressurePumpSystem.cs [new file with mode: 0644]
Content.Client/Atmos/UI/GasPressurePumpBoundUserInterface.cs
Content.Client/Atmos/UI/GasPressurePumpWindow.xaml
Content.Client/Atmos/UI/GasPressurePumpWindow.xaml.cs
Content.Server/Atmos/Monitor/Systems/AtmosMonitoringSystem.cs
Content.Server/Atmos/Piping/Binary/Components/GasPressurePumpComponent.cs [deleted file]
Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs
Content.Server/Atmos/Piping/Binary/EntitySystems/GasRecyclerSystem.cs
Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs
Content.Server/Atmos/Piping/Components/AtmosDeviceComponent.cs
Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs
Content.Server/Atmos/Piping/Trinary/EntitySystems/GasFilterSystem.cs
Content.Server/Atmos/Piping/Trinary/EntitySystems/GasMixerSystem.cs
Content.Server/Atmos/Piping/Trinary/EntitySystems/PressureControlledValveSystem.cs
Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs
Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs
Content.Shared/Atmos/Components/GasPressurePumpComponent.cs [new file with mode: 0644]
Content.Shared/Atmos/EntitySystems/SharedGasPressurePumpSystem.cs [new file with mode: 0644]
Content.Shared/Atmos/Piping/Binary/Components/SharedGasPressurePumpComponent.cs
Content.Shared/Atmos/Piping/Components/AtmosDeviceDisabledEvent.cs [new file with mode: 0644]
Content.Shared/Atmos/Piping/Components/AtmosDeviceEnabledEvent.cs [new file with mode: 0644]
Content.Shared/UserInterface/ActivatableUIRequiresAnchorComponent.cs [new file with mode: 0644]
Content.Shared/UserInterface/ActivatableUIRequiresAnchorSystem.cs [new file with mode: 0644]
Resources/Locale/en-US/components/gas-pump-component.ftl
Resources/Locale/en-US/ui/general.ftl
Resources/Prototypes/Entities/Structures/Piping/Atmospherics/binary.yml

diff --git a/Content.Client/Atmos/EntitySystems/GasPressurePumpSystem.cs b/Content.Client/Atmos/EntitySystems/GasPressurePumpSystem.cs
new file mode 100644 (file)
index 0000000..54e16bc
--- /dev/null
@@ -0,0 +1,23 @@
+using Content.Client.Atmos.UI;
+using Content.Shared.Atmos.Components;
+using Content.Shared.Atmos.EntitySystems;
+using Content.Shared.Atmos.Piping.Binary.Components;
+
+namespace Content.Client.Atmos.EntitySystems;
+
+public sealed class GasPressurePumpSystem : SharedGasPressurePumpSystem
+{
+    public override void Initialize()
+    {
+        base.Initialize();
+        SubscribeLocalEvent<GasPressurePumpComponent, AfterAutoHandleStateEvent>(OnPumpUpdate);
+    }
+
+    private void OnPumpUpdate(Entity<GasPressurePumpComponent> ent, ref AfterAutoHandleStateEvent args)
+    {
+        if (UserInterfaceSystem.TryGetOpenUi<GasPressurePumpBoundUserInterface>(ent.Owner, GasPressurePumpUiKey.Key, out var bui))
+        {
+            bui.Update();
+        }
+    }
+}
index 220fdbe875c929ad929080fbdc53fad5c963c06d..0c07eec4025c351a1f3eab85b611934ef92f476b 100644 (file)
@@ -1,65 +1,63 @@
 using Content.Shared.Atmos;
+using Content.Shared.Atmos.Components;
 using Content.Shared.Atmos.Piping.Binary.Components;
+using Content.Shared.IdentityManagement;
 using Content.Shared.Localizations;
 using JetBrains.Annotations;
-using Robust.Client.GameObjects;
 using Robust.Client.UserInterface;
 
-namespace Content.Client.Atmos.UI
+namespace Content.Client.Atmos.UI;
+
+/// <summary>
+/// Initializes a <see cref="GasPressurePumpWindow"/> and updates it when new server messages are received.
+/// </summary>
+[UsedImplicitly]
+public sealed class GasPressurePumpBoundUserInterface : BoundUserInterface
 {
-    /// <summary>
-    /// Initializes a <see cref="GasPressurePumpWindow"/> and updates it when new server messages are received.
-    /// </summary>
-    [UsedImplicitly]
-    public sealed class GasPressurePumpBoundUserInterface : BoundUserInterface
-    {
-        [ViewVariables]
-        private const float MaxPressure = Atmospherics.MaxOutputPressure;
+    [ViewVariables]
+    private const float MaxPressure = Atmospherics.MaxOutputPressure;
+
+    [ViewVariables]
+    private GasPressurePumpWindow? _window;
 
-        [ViewVariables]
-        private GasPressurePumpWindow? _window;
+    public GasPressurePumpBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
+    {
+    }
 
-        public GasPressurePumpBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
-        {
-        }
+    protected override void Open()
+    {
+        base.Open();
 
-        protected override void Open()
-        {
-            base.Open();
+        _window = this.CreateWindow<GasPressurePumpWindow>();
 
-            _window = this.CreateWindow<GasPressurePumpWindow>();
+        _window.ToggleStatusButtonPressed += OnToggleStatusButtonPressed;
+        _window.PumpOutputPressureChanged += OnPumpOutputPressurePressed;
+        Update();
+    }
 
-            _window.ToggleStatusButtonPressed += OnToggleStatusButtonPressed;
-            _window.PumpOutputPressureChanged += OnPumpOutputPressurePressed;
-        }
+    public void Update()
+    {
+        if (_window == null)
+            return;
 
-        private void OnToggleStatusButtonPressed()
-        {
-            if (_window is null) return;
-            SendMessage(new GasPressurePumpToggleStatusMessage(_window.PumpStatus));
-        }
+        _window.Title = Identity.Name(Owner, EntMan);
 
-        private void OnPumpOutputPressurePressed(string value)
-        {
-            var pressure = UserInputParser.TryFloat(value, out var parsed) ? parsed : 0f;
-            if (pressure > MaxPressure) pressure = MaxPressure;
+        if (!EntMan.TryGetComponent(Owner, out GasPressurePumpComponent? pump))
+            return;
 
-            SendMessage(new GasPressurePumpChangeOutputPressureMessage(pressure));
-        }
+        _window.SetPumpStatus(pump.Enabled);
+        _window.MaxPressure = pump.MaxTargetPressure;
+        _window.SetOutputPressure(pump.TargetPressure);
+    }
 
-        /// <summary>
-        /// Update the UI state based on server-sent info
-        /// </summary>
-        /// <param name="state"></param>
-        protected override void UpdateState(BoundUserInterfaceState state)
-        {
-            base.UpdateState(state);
-            if (_window == null || state is not GasPressurePumpBoundUserInterfaceState cast)
-                return;
+    private void OnToggleStatusButtonPressed()
+    {
+        if (_window is null) return;
+        SendPredictedMessage(new GasPressurePumpToggleStatusMessage(_window.PumpStatus));
+    }
 
-            _window.Title = (cast.PumpLabel);
-            _window.SetPumpStatus(cast.Enabled);
-            _window.SetOutputPressure(cast.OutputPressure);
-        }
+    private void OnPumpOutputPressurePressed(float value)
+    {
+        SendPredictedMessage(new GasPressurePumpChangeOutputPressureMessage(value));
     }
 }
index a0896a7b41e7b7971b5a3e8b642f4e820701c335..f2c2c7cec50862e3794b8ab1cf9dab4ddd62d4a1 100644 (file)
@@ -1,22 +1,18 @@
-<DefaultWindow xmlns="https://spacestation14.io"
+<controls:FancyWindow xmlns="https://spacestation14.io"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-            MinSize="200 120" Title="Pressure Pump">
+            xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
+            SetSize="340 110" MinSize="340 110" Title="Pressure Pump">
     <BoxContainer Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
         <BoxContainer Orientation="Horizontal" HorizontalExpand="True">
-            <Label Text="{Loc comp-gas-pump-ui-pump-status}"/>
-            <Control MinSize="5 0" />
+            <Label Text="{Loc comp-gas-pump-ui-pump-status}" Margin="0 0 5 0"/>
             <Button Name="ToggleStatusButton"/>
+            <Control HorizontalExpand="True"/>
+            <Button HorizontalAlignment="Right" Name="SetOutputPressureButton" Text="{Loc comp-gas-pump-ui-pump-set-rate}" Disabled="True" Margin="0 0 5 0"/>
+            <Button Name="SetMaxPressureButton" Text="{Loc comp-gas-pump-ui-pump-set-max}" />
         </BoxContainer>
-
         <BoxContainer Orientation="Horizontal" HorizontalExpand="True">
             <Label Text="{Loc comp-gas-pump-ui-pump-output-pressure}"/>
-            <Control MinSize="5 0" />
-            <LineEdit Name="PumpPressureOutputInput" MinSize="70 0" />
-            <Control MinSize="5 0" />
-            <Button Name="SetMaxPressureButton" Text="{Loc comp-gas-pump-ui-pump-set-max}" />
-            <Control MinSize="5 0" />
-            <Control HorizontalExpand="True" />
-            <Button Name="SetOutputPressureButton" Text="{Loc comp-gas-pump-ui-pump-set-rate}" HorizontalAlignment="Right" Disabled="True"/>
+            <FloatSpinBox HorizontalExpand="True" Name="PumpPressureOutputInput" MinSize="70 0" />
         </BoxContainer>
     </BoxContainer>
-</DefaultWindow>
+</controls:FancyWindow>
index b5ffcd10721e705a7c3e4deaf2bcec41919d1ba4..aa86a1aa03b38fe8014884947bdae927d7eaf0b4 100644 (file)
@@ -1,14 +1,8 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using Content.Client.Atmos.EntitySystems;
+using Content.Client.UserInterface.Controls;
 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
 {
@@ -16,12 +10,25 @@ namespace Content.Client.Atmos.UI
     /// Client-side UI used to control a gas pressure pump.
     /// </summary>
     [GenerateTypedNameReferences]
-    public sealed partial class GasPressurePumpWindow : DefaultWindow
+    public sealed partial class GasPressurePumpWindow : FancyWindow
     {
         public bool PumpStatus = true;
 
         public event Action? ToggleStatusButtonPressed;
-        public event Action<string>? PumpOutputPressureChanged;
+        public event Action<float>? PumpOutputPressureChanged;
+
+        public float MaxPressure
+        {
+            get => _maxPressure;
+            set
+            {
+                _maxPressure = value;
+
+                PumpPressureOutputInput.Value = MathF.Min(value, PumpPressureOutputInput.Value);
+            }
+        }
+
+        private float _maxPressure = Atmospherics.MaxOutputPressure;
 
         public GasPressurePumpWindow()
         {
@@ -30,23 +37,25 @@ namespace Content.Client.Atmos.UI
             ToggleStatusButton.OnPressed += _ => SetPumpStatus(!PumpStatus);
             ToggleStatusButton.OnPressed += _ => ToggleStatusButtonPressed?.Invoke();
 
-            PumpPressureOutputInput.OnTextChanged += _ => SetOutputPressureButton.Disabled = false;
+            PumpPressureOutputInput.OnValueChanged += _ => SetOutputPressureButton.Disabled = false;
+
             SetOutputPressureButton.OnPressed += _ =>
             {
-                PumpOutputPressureChanged?.Invoke(PumpPressureOutputInput.Text ??= "");
+                PumpPressureOutputInput.Value = Math.Clamp(PumpPressureOutputInput.Value, 0f, _maxPressure);
+                PumpOutputPressureChanged?.Invoke(PumpPressureOutputInput.Value);
                 SetOutputPressureButton.Disabled = true;
             };
 
             SetMaxPressureButton.OnPressed += _ =>
             {
-                PumpPressureOutputInput.Text = Atmospherics.MaxOutputPressure.ToString(CultureInfo.CurrentCulture);
+                PumpPressureOutputInput.Value = _maxPressure;
                 SetOutputPressureButton.Disabled = false;
             };
         }
 
         public void SetOutputPressure(float pressure)
         {
-            PumpPressureOutputInput.Text = pressure.ToString(CultureInfo.CurrentCulture);
+            PumpPressureOutputInput.Value = pressure;
         }
 
         public void SetPumpStatus(bool enabled)
index 17a24b1b0cb6b1e3e720f04b8fafea13b89f5d84..875d8ad1cda4531dc90c5bb759361c256eb38f7c 100644 (file)
@@ -11,6 +11,7 @@ using Content.Server.Power.Components;
 using Content.Server.Power.EntitySystems;
 using Content.Shared.Atmos;
 using Content.Shared.Atmos.Monitor;
+using Content.Shared.Atmos.Piping.Components;
 using Content.Shared.DeviceNetwork;
 using Content.Shared.Power;
 using Content.Shared.Tag;
diff --git a/Content.Server/Atmos/Piping/Binary/Components/GasPressurePumpComponent.cs b/Content.Server/Atmos/Piping/Binary/Components/GasPressurePumpComponent.cs
deleted file mode 100644 (file)
index 8816e1a..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-using Content.Shared.Atmos;
-
-namespace Content.Server.Atmos.Piping.Binary.Components
-{
-    [RegisterComponent]
-    public sealed partial class GasPressurePumpComponent : Component
-    {
-        [ViewVariables(VVAccess.ReadWrite)]
-        [DataField("enabled")]
-        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)]
-        [DataField("targetPressure")]
-        public float TargetPressure { get; set; } = Atmospherics.OneAtmosphere;
-
-        /// <summary>
-        ///     Max pressure of the target gas (NOT relative to source).
-        /// </summary>
-        [ViewVariables(VVAccess.ReadWrite)]
-        [DataField("maxTargetPressure")]
-        public float MaxTargetPressure = Atmospherics.MaxOutputPressure;
-    }
-}
index abd34396a0c78ad284dcd6c1db0cd32cfbe9d1e3..5f0092f3778c5a8dce39f9b922bc7c3202d4bf43 100644 (file)
-using Content.Server.Administration.Logs;
 using Content.Server.Atmos.EntitySystems;
-using Content.Server.Atmos.Piping.Binary.Components;
 using Content.Server.Atmos.Piping.Components;
 using Content.Server.NodeContainer.EntitySystems;
 using Content.Server.NodeContainer.Nodes;
 using Content.Server.Power.Components;
 using Content.Shared.Atmos;
-using Content.Shared.Atmos.Piping;
-using Content.Shared.Atmos.Piping.Binary.Components;
+using Content.Shared.Atmos.Components;
+using Content.Shared.Atmos.EntitySystems;
 using Content.Shared.Audio;
-using Content.Shared.Database;
-using Content.Shared.Examine;
-using Content.Shared.Interaction;
-using Content.Shared.Popups;
-using Content.Shared.Power;
 using JetBrains.Annotations;
-using Robust.Server.GameObjects;
-using Robust.Shared.Player;
 
-namespace Content.Server.Atmos.Piping.Binary.EntitySystems
-{
-    [UsedImplicitly]
-    public sealed class GasPressurePumpSystem : EntitySystem
-    {
-        [Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
-        [Dependency] private readonly IAdminLogManager _adminLogger = default!;
-        [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
-        [Dependency] private readonly SharedAmbientSoundSystem _ambientSoundSystem = default!;
-        [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
-        [Dependency] private readonly NodeContainerSystem _nodeContainer = default!;
-        [Dependency] private readonly SharedPopupSystem _popup = default!;
-
-        public override void Initialize()
-        {
-            base.Initialize();
-
-            SubscribeLocalEvent<GasPressurePumpComponent, ComponentInit>(OnInit);
-            SubscribeLocalEvent<GasPressurePumpComponent, AtmosDeviceUpdateEvent>(OnPumpUpdated);
-            SubscribeLocalEvent<GasPressurePumpComponent, AtmosDeviceDisabledEvent>(OnPumpLeaveAtmosphere);
-            SubscribeLocalEvent<GasPressurePumpComponent, ExaminedEvent>(OnExamined);
-            SubscribeLocalEvent<GasPressurePumpComponent, ActivateInWorldEvent>(OnPumpActivate);
-            SubscribeLocalEvent<GasPressurePumpComponent, PowerChangedEvent>(OnPowerChanged);
-            // Bound UI subscriptions
-            SubscribeLocalEvent<GasPressurePumpComponent, GasPressurePumpChangeOutputPressureMessage>(OnOutputPressureChangeMessage);
-            SubscribeLocalEvent<GasPressurePumpComponent, GasPressurePumpToggleStatusMessage>(OnToggleStatusMessage);
-        }
-
-        private void OnInit(EntityUid uid, GasPressurePumpComponent pump, ComponentInit args)
-        {
-            UpdateAppearance(uid, pump);
-        }
-
-        private void OnExamined(EntityUid uid, GasPressurePumpComponent pump, ExaminedEvent args)
-        {
-            if (!EntityManager.GetComponent<TransformComponent>(uid).Anchored || !args.IsInDetailsRange) // Not anchored? Out of range? No status.
-                return;
-
-            if (Loc.TryGetString("gas-pressure-pump-system-examined", out var str,
-                    ("statusColor", "lightblue"), // TODO: change with pressure?
-                    ("pressure", pump.TargetPressure)
-                ))
-            {
-                args.PushMarkup(str);
-            }
-        }
-
-        private void OnPowerChanged(EntityUid uid, GasPressurePumpComponent component, ref PowerChangedEvent args)
-        {
-            UpdateAppearance(uid, component);
-        }
-
-        private void OnPumpUpdated(EntityUid uid, GasPressurePumpComponent pump, ref AtmosDeviceUpdateEvent args)
-        {
-            if (!pump.Enabled
-                || (TryComp<ApcPowerReceiverComponent>(uid, out var power) && !power.Powered)
-                || !_nodeContainer.TryGetNodes(uid, pump.InletName, pump.OutletName, out PipeNode? inlet, out PipeNode? outlet))
-            {
-                _ambientSoundSystem.SetAmbience(uid, false);
-                return;
-            }
-
-            var outputStartingPressure = outlet.Air.Pressure;
+namespace Content.Server.Atmos.Piping.Binary.EntitySystems;
 
-            if (outputStartingPressure >= pump.TargetPressure)
-            {
-                _ambientSoundSystem.SetAmbience(uid, false);
-                return; // No need to pump gas if target has been reached.
-            }
-
-            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 = pump.TargetPressure - outputStartingPressure;
-                var transferMoles = (pressureDelta * outlet.Air.Volume) / (inlet.Air.Temperature * Atmospherics.R);
-
-                var removed = inlet.Air.Remove(transferMoles);
-                _atmosphereSystem.Merge(outlet.Air, removed);
-                _ambientSoundSystem.SetAmbience(uid, removed.TotalMoles > 0f);
-            }
-        }
-
-        private void OnPumpLeaveAtmosphere(EntityUid uid, GasPressurePumpComponent pump, ref AtmosDeviceDisabledEvent args)
-        {
-            pump.Enabled = false;
-            UpdateAppearance(uid, pump);
-
-            DirtyUI(uid, pump);
-            _userInterfaceSystem.CloseUi(uid, GasPressurePumpUiKey.Key);
-        }
-
-        private void OnPumpActivate(EntityUid uid, GasPressurePumpComponent pump, ActivateInWorldEvent args)
-        {
-            if (args.Handled || !args.Complex)
-                return;
-
-            if (!EntityManager.TryGetComponent(args.User, out ActorComponent? actor))
-                return;
+[UsedImplicitly]
+public sealed class GasPressurePumpSystem : SharedGasPressurePumpSystem
+{
+    [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
+    [Dependency] private readonly SharedAmbientSoundSystem _ambientSoundSystem = default!;
+    [Dependency] private readonly NodeContainerSystem _nodeContainer = default!;
 
-            if (Transform(uid).Anchored)
-            {
-                _userInterfaceSystem.OpenUi(uid, GasPressurePumpUiKey.Key, actor.PlayerSession);
-                DirtyUI(uid, pump);
-            }
-            else
-            {
-                _popup.PopupCursor(Loc.GetString("comp-gas-pump-ui-needs-anchor"), args.User);
-            }
+    public override void Initialize()
+    {
+        base.Initialize();
 
-            args.Handled = true;
-        }
+        SubscribeLocalEvent<GasPressurePumpComponent, AtmosDeviceUpdateEvent>(OnPumpUpdated);
+    }
 
-        private void OnToggleStatusMessage(EntityUid uid, GasPressurePumpComponent pump, GasPressurePumpToggleStatusMessage args)
+    private void OnPumpUpdated(EntityUid uid, GasPressurePumpComponent pump, ref AtmosDeviceUpdateEvent args)
+    {
+        if (!pump.Enabled
+            || (TryComp<ApcPowerReceiverComponent>(uid, out var power) && !power.Powered)
+            || !_nodeContainer.TryGetNodes(uid, pump.InletName, pump.OutletName, out PipeNode? inlet, out PipeNode? outlet))
         {
-            pump.Enabled = args.Enabled;
-            _adminLogger.Add(LogType.AtmosPowerChanged, LogImpact.Medium,
-                $"{ToPrettyString(args.Actor):player} set the power on {ToPrettyString(uid):device} to {args.Enabled}");
-            DirtyUI(uid, pump);
-            UpdateAppearance(uid, pump);
+            _ambientSoundSystem.SetAmbience(uid, false);
+            return;
         }
 
-        private void OnOutputPressureChangeMessage(EntityUid uid, GasPressurePumpComponent pump, GasPressurePumpChangeOutputPressureMessage args)
-        {
-            pump.TargetPressure = Math.Clamp(args.Pressure, 0f, Atmospherics.MaxOutputPressure);
-            _adminLogger.Add(LogType.AtmosPressureChanged, LogImpact.Medium,
-                $"{ToPrettyString(args.Actor):player} set the pressure on {ToPrettyString(uid):device} to {args.Pressure}kPa");
-            DirtyUI(uid, pump);
-
-        }
+        var outputStartingPressure = outlet.Air.Pressure;
 
-        private void DirtyUI(EntityUid uid, GasPressurePumpComponent? pump)
+        if (outputStartingPressure >= pump.TargetPressure)
         {
-            if (!Resolve(uid, ref pump))
-                return;
-
-            _userInterfaceSystem.SetUiState(uid, GasPressurePumpUiKey.Key,
-                new GasPressurePumpBoundUserInterfaceState(EntityManager.GetComponent<MetaDataComponent>(uid).EntityName, pump.TargetPressure, pump.Enabled));
+            _ambientSoundSystem.SetAmbience(uid, false);
+            return; // No need to pump gas if target has been reached.
         }
 
-        private void UpdateAppearance(EntityUid uid, GasPressurePumpComponent? pump = null, AppearanceComponent? appearance = null)
+        if (inlet.Air.TotalMoles > 0 && inlet.Air.Temperature > 0)
         {
-            if (!Resolve(uid, ref pump, ref appearance, false))
-                return;
+            // 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);
 
-            bool pumpOn = pump.Enabled && (TryComp<ApcPowerReceiverComponent>(uid, out var power) && power.Powered);
-            _appearance.SetData(uid, PumpVisuals.Enabled, pumpOn, appearance);
+            var removed = inlet.Air.Remove(transferMoles);
+            _atmosphereSystem.Merge(outlet.Air, removed);
+            _ambientSoundSystem.SetAmbience(uid, removed.TotalMoles > 0f);
         }
     }
 }
index 3ebc50949263f420ec1a3bce2ebdfcd3a53f3ea8..f77897940962563e8634494140e668e01cb18a5e 100644 (file)
@@ -6,6 +6,7 @@ using Content.Server.NodeContainer.EntitySystems;
 using Content.Server.NodeContainer.Nodes;
 using Content.Shared.Atmos;
 using Content.Shared.Atmos.Piping;
+using Content.Shared.Atmos.Piping.Components;
 using Content.Shared.Audio;
 using Content.Shared.Examine;
 using JetBrains.Annotations;
index 9ddd7dce67d5a1f71a874761bbbc45774cc68367..d593324b190412679e7dc84ce01fc07dd8fec6ce 100644 (file)
@@ -10,6 +10,7 @@ using Content.Server.NodeContainer.EntitySystems;
 using Content.Server.NodeContainer.Nodes;
 using Content.Server.Power.Components;
 using Content.Shared.Atmos.Piping.Binary.Components;
+using Content.Shared.Atmos.Piping.Components;
 using Content.Shared.Atmos.Visuals;
 using Content.Shared.Audio;
 using Content.Shared.Database;
index b70262e857b01a2ab067ec9d430e27c181d665fd..5b55d9d3b6747400f40989977e05efd8fb937e87 100644 (file)
@@ -67,15 +67,3 @@ public readonly struct AtmosDeviceUpdateEvent(float dt, Entity<GridAtmosphereCom
     /// </summary>
     public readonly Entity<MapAtmosphereComponent?>? Map = map;
 }
-
-/// <summary>
-///     Raised directed on an atmos device when it is enabled.
-/// </summary>
-[ByRefEvent]
-public record struct AtmosDeviceEnabledEvent;
-
-/// <summary>
-///     Raised directed on an atmos device when it is enabled.
-/// </summary>
-[ByRefEvent]
-public record struct AtmosDeviceDisabledEvent;
index f932ef36208e5e4c89487fb2a1d797871074ae31..3feaf79eb73a2e7b6ab827715ec46a174d8d1ab8 100644 (file)
@@ -1,6 +1,7 @@
 using Content.Server.Atmos.Components;
 using Content.Server.Atmos.EntitySystems;
 using Content.Server.Atmos.Piping.Components;
+using Content.Shared.Atmos.Piping.Components;
 using JetBrains.Annotations;
 using Robust.Shared.Timing;
 using Robust.Shared.Utility;
index 752d1e9eb83511d5ca6d7fd43888734513841631..c5a91895b2e277509e653303b622cb1cb2acfa68 100644 (file)
@@ -7,6 +7,7 @@ using Content.Server.NodeContainer.EntitySystems;
 using Content.Server.NodeContainer.Nodes;
 using Content.Shared.Atmos;
 using Content.Shared.Atmos.Piping;
+using Content.Shared.Atmos.Piping.Components;
 using Content.Shared.Atmos.Piping.Trinary.Components;
 using Content.Shared.Audio;
 using Content.Shared.Database;
index 178caeaa4a92044a24f8c8e0a590f8b869f7fc5f..0852051487bbe04351d43d8701887dc602c00b88 100644 (file)
@@ -7,6 +7,7 @@ using Content.Server.NodeContainer.EntitySystems;
 using Content.Server.NodeContainer.Nodes;
 using Content.Shared.Atmos;
 using Content.Shared.Atmos.Piping;
+using Content.Shared.Atmos.Piping.Components;
 using Content.Shared.Atmos.Piping.Trinary.Components;
 using Content.Shared.Audio;
 using Content.Shared.Database;
index 1bab2abd8e9e84d9a45c73e6e0a44d7522f5d4af..d1570b11292bad67a1807bab92224cd31e1e2333 100644 (file)
@@ -5,6 +5,7 @@ using Content.Server.NodeContainer;
 using Content.Server.NodeContainer.EntitySystems;
 using Content.Server.NodeContainer.Nodes;
 using Content.Shared.Atmos.Piping;
+using Content.Shared.Atmos.Piping.Components;
 using Content.Shared.Audio;
 using JetBrains.Annotations;
 
index 9d9862ff1dde880b22fa6a0166b85b6cf3ab8f00..23016debeb6bbec54c3b329d14739d489bf2fd47 100644 (file)
@@ -11,6 +11,7 @@ using Content.Server.NodeContainer.EntitySystems;
 using Content.Server.NodeContainer.Nodes;
 using Content.Shared.Atmos;
 using Content.Shared.Atmos.Monitor;
+using Content.Shared.Atmos.Piping.Components;
 using Content.Shared.Atmos.Piping.Unary;
 using Content.Shared.Atmos.Piping.Unary.Components;
 using Content.Shared.Atmos.Visuals;
index a35cf6c2e30592f7c12460a0515464906e5fae93..a633d29e41dc8b3d7297e32fc6d20f2517560bd2 100644 (file)
@@ -13,6 +13,7 @@ using Content.Server.Power.Components;
 using Content.Shared.Atmos;
 using Content.Shared.Atmos.Piping.Unary.Visuals;
 using Content.Shared.Atmos.Monitor;
+using Content.Shared.Atmos.Piping.Components;
 using Content.Shared.Atmos.Piping.Unary.Components;
 using Content.Shared.Audio;
 using Content.Shared.DeviceNetwork;
diff --git a/Content.Shared/Atmos/Components/GasPressurePumpComponent.cs b/Content.Shared/Atmos/Components/GasPressurePumpComponent.cs
new file mode 100644 (file)
index 0000000..ca6b4d4
--- /dev/null
@@ -0,0 +1,25 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Atmos.Components;
+
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class GasPressurePumpComponent : Component
+{
+    [DataField, AutoNetworkedField]
+    public bool Enabled = true;
+
+    [DataField("inlet")]
+    public string InletName = "inlet";
+
+    [DataField("outlet")]
+    public string OutletName = "outlet";
+
+    [DataField, AutoNetworkedField]
+    public float TargetPressure = Atmospherics.OneAtmosphere;
+
+    /// <summary>
+    ///     Max pressure of the target gas (NOT relative to source).
+    /// </summary>
+    [DataField]
+    public float MaxTargetPressure = Atmospherics.MaxOutputPressure;
+}
diff --git a/Content.Shared/Atmos/EntitySystems/SharedGasPressurePumpSystem.cs b/Content.Shared/Atmos/EntitySystems/SharedGasPressurePumpSystem.cs
new file mode 100644 (file)
index 0000000..77444eb
--- /dev/null
@@ -0,0 +1,97 @@
+using Content.Shared.Administration.Logs;
+using Content.Shared.Atmos.Components;
+using Content.Shared.Atmos.Piping;
+using Content.Shared.Atmos.Piping.Binary.Components;
+using Content.Shared.Atmos.Piping.Components;
+using Content.Shared.Database;
+using Content.Shared.Examine;
+using Content.Shared.Popups;
+using Content.Shared.Power;
+using Content.Shared.Power.Components;
+using Content.Shared.Power.EntitySystems;
+using Content.Shared.UserInterface;
+
+namespace Content.Shared.Atmos.EntitySystems;
+
+public abstract class SharedGasPressurePumpSystem : EntitySystem
+{
+    [Dependency] private   readonly ISharedAdminLogManager _adminLogger = default!;
+    [Dependency] protected readonly SharedAppearanceSystem Appearance = default!;
+    [Dependency] private   readonly SharedPowerReceiverSystem _receiver = default!;
+    [Dependency] protected readonly SharedUserInterfaceSystem UserInterfaceSystem = default!;
+
+    // TODO: Check enabled for activatableUI
+    // TODO: Add activatableUI to it.
+
+    public override void Initialize()
+    {
+        base.Initialize();
+        SubscribeLocalEvent<GasPressurePumpComponent, ComponentInit>(OnInit);
+        SubscribeLocalEvent<GasPressurePumpComponent, PowerChangedEvent>(OnPowerChanged);
+
+        SubscribeLocalEvent<GasPressurePumpComponent, GasPressurePumpChangeOutputPressureMessage>(OnOutputPressureChangeMessage);
+        SubscribeLocalEvent<GasPressurePumpComponent, GasPressurePumpToggleStatusMessage>(OnToggleStatusMessage);
+
+        SubscribeLocalEvent<GasPressurePumpComponent, AtmosDeviceDisabledEvent>(OnPumpLeaveAtmosphere);
+        SubscribeLocalEvent<GasPressurePumpComponent, ExaminedEvent>(OnExamined);
+    }
+
+    private void OnExamined(EntityUid uid, GasPressurePumpComponent pump, ExaminedEvent args)
+    {
+        if (!Transform(uid).Anchored)
+            return;
+
+        if (Loc.TryGetString("gas-pressure-pump-system-examined", out var str,
+                ("statusColor", "lightblue"), // TODO: change with pressure?
+                ("pressure", pump.TargetPressure)
+            ))
+        {
+            args.PushMarkup(str);
+        }
+    }
+
+    private void OnInit(EntityUid uid, GasPressurePumpComponent pump, ComponentInit args)
+    {
+        UpdateAppearance(uid, pump);
+    }
+
+    private void OnPowerChanged(EntityUid uid, GasPressurePumpComponent component, ref PowerChangedEvent args)
+    {
+        UpdateAppearance(uid, component);
+    }
+
+    private void UpdateAppearance(EntityUid uid, GasPressurePumpComponent? pump = null, AppearanceComponent? appearance = null)
+    {
+        if (!Resolve(uid, ref pump, ref appearance, false))
+            return;
+
+        var pumpOn = pump.Enabled && _receiver.IsPowered(uid);
+        Appearance.SetData(uid, PumpVisuals.Enabled, pumpOn, appearance);
+    }
+
+    private void OnToggleStatusMessage(EntityUid uid, GasPressurePumpComponent pump, GasPressurePumpToggleStatusMessage args)
+    {
+        pump.Enabled = args.Enabled;
+        _adminLogger.Add(LogType.AtmosPowerChanged, LogImpact.Medium,
+            $"{ToPrettyString(args.Actor):player} set the power on {ToPrettyString(uid):device} to {args.Enabled}");
+        Dirty(uid, pump);
+        UpdateAppearance(uid, pump);
+    }
+
+    private void OnOutputPressureChangeMessage(EntityUid uid, GasPressurePumpComponent pump, GasPressurePumpChangeOutputPressureMessage args)
+    {
+        pump.TargetPressure = Math.Clamp(args.Pressure, 0f, Atmospherics.MaxOutputPressure);
+        _adminLogger.Add(LogType.AtmosPressureChanged, LogImpact.Medium,
+            $"{ToPrettyString(args.Actor):player} set the pressure on {ToPrettyString(uid):device} to {args.Pressure}kPa");
+        Dirty(uid, pump);
+    }
+
+    private void OnPumpLeaveAtmosphere(EntityUid uid, GasPressurePumpComponent pump, ref AtmosDeviceDisabledEvent args)
+    {
+        pump.Enabled = false;
+        Dirty(uid, pump);
+        UpdateAppearance(uid, pump);
+
+        UserInterfaceSystem.CloseUi(uid, GasPressurePumpUiKey.Key);
+    }
+}
index 217d81e972ffe614060a52dfb93d053e141f7c20..041708dde04bbf0b7a2187df7004e96e236bbc4f 100644 (file)
@@ -1,47 +1,21 @@
 using Robust.Shared.Serialization;
 
-namespace Content.Shared.Atmos.Piping.Binary.Components
-{
-    [Serializable, NetSerializable]
-    public enum GasPressurePumpUiKey
-    {
-        Key,
-    }
-
-    [Serializable, NetSerializable]
-    public sealed 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;
-        }
-    }
+namespace Content.Shared.Atmos.Piping.Binary.Components;
 
-    [Serializable, NetSerializable]
-    public sealed class GasPressurePumpToggleStatusMessage : BoundUserInterfaceMessage
-    {
-        public bool Enabled { get; }
-
-        public GasPressurePumpToggleStatusMessage(bool enabled)
-        {
-            Enabled = enabled;
-        }
-    }
+[Serializable, NetSerializable]
+public enum GasPressurePumpUiKey : byte
+{
+    Key,
+}
 
-    [Serializable, NetSerializable]
-    public sealed class GasPressurePumpChangeOutputPressureMessage : BoundUserInterfaceMessage
-    {
-        public float Pressure { get; }
+[Serializable, NetSerializable]
+public sealed class GasPressurePumpToggleStatusMessage(bool enabled) : BoundUserInterfaceMessage
+{
+    public bool Enabled { get; } = enabled;
+}
 
-        public GasPressurePumpChangeOutputPressureMessage(float pressure)
-        {
-            Pressure = pressure;
-        }
-    }
+[Serializable, NetSerializable]
+public sealed class GasPressurePumpChangeOutputPressureMessage(float pressure) : BoundUserInterfaceMessage
+{
+    public float Pressure { get; } = pressure;
 }
diff --git a/Content.Shared/Atmos/Piping/Components/AtmosDeviceDisabledEvent.cs b/Content.Shared/Atmos/Piping/Components/AtmosDeviceDisabledEvent.cs
new file mode 100644 (file)
index 0000000..6fe5d86
--- /dev/null
@@ -0,0 +1,7 @@
+namespace Content.Shared.Atmos.Piping.Components;
+
+/// <summary>
+///     Raised directed on an atmos device when it is enabled.
+/// </summary>
+[ByRefEvent]
+public readonly record struct AtmosDeviceDisabledEvent;
\ No newline at end of file
diff --git a/Content.Shared/Atmos/Piping/Components/AtmosDeviceEnabledEvent.cs b/Content.Shared/Atmos/Piping/Components/AtmosDeviceEnabledEvent.cs
new file mode 100644 (file)
index 0000000..d656367
--- /dev/null
@@ -0,0 +1,7 @@
+namespace Content.Shared.Atmos.Piping.Components;
+
+/// <summary>
+///     Raised directed on an atmos device when it is enabled.
+/// </summary>
+[ByRefEvent]
+public readonly record struct AtmosDeviceEnabledEvent;
\ No newline at end of file
diff --git a/Content.Shared/UserInterface/ActivatableUIRequiresAnchorComponent.cs b/Content.Shared/UserInterface/ActivatableUIRequiresAnchorComponent.cs
new file mode 100644 (file)
index 0000000..89bcae7
--- /dev/null
@@ -0,0 +1,13 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.UserInterface;
+
+/// <summary>
+/// Specifies the entity as requiring anchoring to keep the ActivatableUI open.
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+public sealed partial class ActivatableUIRequiresAnchorComponent : Component
+{
+    [DataField]
+    public LocId? Popup = "ui-needs-anchor";
+}
diff --git a/Content.Shared/UserInterface/ActivatableUIRequiresAnchorSystem.cs b/Content.Shared/UserInterface/ActivatableUIRequiresAnchorSystem.cs
new file mode 100644 (file)
index 0000000..1d45333
--- /dev/null
@@ -0,0 +1,41 @@
+using Content.Shared.Popups;
+
+namespace Content.Shared.UserInterface;
+
+/// <summary>
+/// <see cref="ActivatableUIRequiresAnchorComponent"/>
+/// </summary>
+public sealed class ActivatableUIRequiresAnchorSystem : EntitySystem
+{
+    [Dependency] private readonly SharedPopupSystem _popup = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+        SubscribeLocalEvent<ActivatableUIRequiresAnchorComponent, ActivatableUIOpenAttemptEvent>(OnActivatableUIOpenAttempt);
+        SubscribeLocalEvent<ActivatableUIRequiresAnchorComponent, BoundUserInterfaceCheckRangeEvent>(OnUICheck);
+    }
+
+    private void OnUICheck(Entity<ActivatableUIRequiresAnchorComponent> ent, ref BoundUserInterfaceCheckRangeEvent args)
+    {
+        if (args.Result == BoundUserInterfaceRangeResult.Fail)
+            return;
+
+        if (!Transform(ent.Owner).Anchored)
+        {
+            args.Result = BoundUserInterfaceRangeResult.Fail;
+        }
+    }
+
+    private void OnActivatableUIOpenAttempt(Entity<ActivatableUIRequiresAnchorComponent> ent, ref ActivatableUIOpenAttemptEvent args)
+    {
+        if (args.Cancelled)
+            return;
+
+        if (!Transform(ent.Owner).Anchored)
+        {
+            _popup.PopupClient(Loc.GetString("comp-gas-pump-ui-needs-anchor"), args.User);
+            args.Cancel();
+        }
+    }
+}
index ad03ac6be60c2c56f915df7b7f4591d2ca5e9ef8..f1fb95f812a8c4ee1b3f5428af780e3f6c5868a0 100644 (file)
@@ -8,5 +8,3 @@ 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):
-
-comp-gas-pump-ui-needs-anchor = Anchor it first!
index 1471261dcb78aa315693e7cbcceca0f4f058c657..753ae9c8da85c1d22f4da4fc9981d3192ee78c70 100644 (file)
@@ -1,3 +1,5 @@
 ### Loc for the various UI-related verbs
 ui-verb-toggle-open = Toggle UI
 verb-instrument-openui = Play Music
+
+ui-needs-anchor = Anchor it first!
index 9f21e45a9635c60b2f1d291182aeb7798370ef8c..90e48d8be67d7b9d2f136b198aaa3bbb530fc48e 100644 (file)
   - type: PipeColorVisuals
   - type: GasPressurePump
     enabled: false
+  - type: ActivatableUI
+    key: enum.GasPressurePumpUiKey.Key
+  - type: ActivatableUIRequiresAnchor
   - type: UserInterface
     interfaces:
-        enum.GasPressurePumpUiKey.Key:
-          type: GasPressurePumpBoundUserInterface
+      enum.GasPressurePumpUiKey.Key:
+        type: GasPressurePumpBoundUserInterface
   - type: Construction
     graph: GasBinary
     node: pressurepump