Atmos pipe rework (#3833)
* Initial * Cleanup a bunch of things * some changes dunno * RequireAnchored * a * stuff * more work * Lots of progress * delete pipe visualizer * a * b * pipenet and pipenode cleanup * Fixes * Adds GasValve * Adds GasMiner * Fix stuff, maybe? * More fixes * Ignored components on the client * Adds thermomachine behavior, change a bunch of stuff * Remove Anchored * some work, but it's shitcode * significantly more ECS * ECS AtmosDevices * Cleanup * fix appearance * when the pipe direction is sus * Gas tanks and canisters * pipe anchoring and stuff * coding is my passion * Unsafe pipes take longer to unanchor * turns out we're no longer using eris canisters * Gas canister inserted tank appearance, improvements * Work on a bunch of appearances * Scrubber appearance * Reorganize AtmosphereSystem.Piping into a bunch of different systems * Appearance for vent/scrubber/pump turns off when leaving atmosphere * ThermoMachine appearance * Cleanup gas tanks * Remove passive gate unused imports * remove old canister UI functionality * PipeNode environment air, make everything use AssumeAir instead of merging manually * a * Reorganize atmos to follow new structure * ????? * Canister UI, restructure client * Restructure shared * Fix build tho * listen, at least the canister UI works entirely... * fix build : ) * Atmos device prototypes have names and descriptions * gas canister ui slider doesn't jitter * trinary prototypes * sprite for miners * ignore components * fix YAML * Fix port system doing useless thing * Fix build * fix thinking moment * fix build again because * canister direction * pipenode is a word * GasTank Air will throw on invalid states * fix build.... * Unhardcode volume pump thresholds * Volume pump and filter take time into account * Rename Join/Leave atmosphere events to AtmosDeviceEnabled/Disabled Event * Gas tank node volume is set by initial mixtuer * I love node container
This commit is contained in:
committed by
GitHub
parent
cfc3f2e7fc
commit
a2b737d945
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
39
Content.Client/Atmos/Piping/EnabledAtmosDeviceVisualizer.cs
Normal file
39
Content.Client/Atmos/Piping/EnabledAtmosDeviceVisualizer.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
18
Content.Client/Atmos/Piping/OutletInjectorVisualizer.cs
Normal file
18
Content.Client/Atmos/Piping/OutletInjectorVisualizer.cs
Normal file
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
18
Content.Client/Atmos/Piping/PassiveVentVisualizer.cs
Normal file
18
Content.Client/Atmos/Piping/PassiveVentVisualizer.cs
Normal file
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
18
Content.Client/Atmos/Piping/PressurePumpVisualizer.cs
Normal file
18
Content.Client/Atmos/Piping/PressurePumpVisualizer.cs
Normal file
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
52
Content.Client/Atmos/Piping/ScrubberVisualizer.cs
Normal file
52
Content.Client/Atmos/Piping/ScrubberVisualizer.cs
Normal file
@@ -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,
|
||||
}
|
||||
}
|
||||
18
Content.Client/Atmos/Piping/ThermoMachineVisualizer.cs
Normal file
18
Content.Client/Atmos/Piping/ThermoMachineVisualizer.cs
Normal file
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
47
Content.Client/Atmos/Piping/VentPumpVisualizer.cs
Normal file
47
Content.Client/Atmos/Piping/VentPumpVisualizer.cs
Normal file
@@ -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,
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
86
Content.Client/Atmos/UI/GasCanisterBoundUserInterface.cs
Normal file
86
Content.Client/Atmos/UI/GasCanisterBoundUserInterface.cs
Normal file
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a <see cref="GasCanisterWindow"/> and updates it when new server messages are received.
|
||||
/// </summary>
|
||||
[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));
|
||||
}
|
||||
|
||||
/// <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 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
52
Content.Client/Atmos/UI/GasCanisterWindow.xaml
Normal file
52
Content.Client/Atmos/UI/GasCanisterWindow.xaml
Normal file
@@ -0,0 +1,52 @@
|
||||
<SS14Window xmlns="https://spacestation14.io"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:s="clr-namespace:Content.Client.Stylesheets"
|
||||
MinSize="480 400" Title="Canister">
|
||||
<VBoxContainer Margin="5 5 5 5" SeparationOverride="10">
|
||||
<VBoxContainer VerticalExpand="True">
|
||||
<Label Text="{Loc comp-gas-canister-ui-canister-status}" FontColorOverride="{x:Static s:StyleNano.NanoGold}" StyleClasses="LabelBig"/>
|
||||
<HBoxContainer>
|
||||
<Label Text="{Loc comp-gas-canister-ui-canister-pressure}"/>
|
||||
<Label Name="CanisterPressureLabel" Align="Center" HorizontalExpand="True"/>
|
||||
</HBoxContainer>
|
||||
<HBoxContainer>
|
||||
<Label Text="{Loc comp-gas-canister-ui-port-status}"/>
|
||||
<Label Name="PortStatusLabel" Align="Center" HorizontalExpand="True"/>
|
||||
</HBoxContainer>
|
||||
</VBoxContainer>
|
||||
|
||||
<VBoxContainer VerticalExpand="True">
|
||||
<Label Text="{Loc comp-gas-canister-ui-holding-tank-status}" FontColorOverride="{x:Static s:StyleNano.NanoGold}" StyleClasses="LabelBig"/>
|
||||
<HBoxContainer>
|
||||
<Label Text="{Loc comp-gas-canister-ui-holding-tank-label}"/>
|
||||
<Label Name="TankLabelLabel" Text="{Loc comp-gas-canister-ui-holding-tank-label-empty}" Align="Center" HorizontalExpand="True"/>
|
||||
<Button Name="TankEjectButton" Text="{Loc comp-gas-canister-ui-holding-tank-eject}"/>
|
||||
</HBoxContainer>
|
||||
<HBoxContainer>
|
||||
<Label Text="{Loc comp-gas-canister-ui-holding-tank-pressure}"/>
|
||||
<Label Name="TankPressureLabel" Align="Center" HorizontalExpand="True"/>
|
||||
</HBoxContainer>
|
||||
</VBoxContainer>
|
||||
|
||||
<VBoxContainer VerticalExpand="True">
|
||||
<Label Text="{Loc comp-gas-canister-ui-release-valve-status}" FontColorOverride="{x:Static s:StyleNano.NanoGold}" StyleClasses="LabelBig"/>
|
||||
<HBoxContainer>
|
||||
<VBoxContainer>
|
||||
<Label Text="{Loc comp-gas-canister-ui-release-pressure}"/>
|
||||
<Control VerticalExpand="True"/>
|
||||
</VBoxContainer>
|
||||
<VBoxContainer HorizontalExpand="True" Margin="15 0 0 15" SeparationOverride="5">
|
||||
<Slider Name="ReleasePressureSlider" HorizontalExpand="True"/>
|
||||
<Label Name="ReleasePressureLabel" Align="Center" HorizontalExpand="True"/>
|
||||
</VBoxContainer>
|
||||
</HBoxContainer>
|
||||
<HBoxContainer>
|
||||
<Label Text="{Loc comp-gas-canister-ui-release-valve}"/>
|
||||
<Control HorizontalExpand="True"/>
|
||||
<Button Name="ReleaseValveOpenButton" Text="{Loc comp-gas-canister-ui-release-valve-open}" ToggleMode="True"/>
|
||||
<Button Name="ReleaseValveCloseButton" Text="{Loc comp-gas-canister-ui-release-valve-close}" ToggleMode="True"/>
|
||||
<Control HorizontalExpand="True"/>
|
||||
</HBoxContainer>
|
||||
</VBoxContainer>
|
||||
</VBoxContainer>
|
||||
</SS14Window>
|
||||
98
Content.Client/Atmos/UI/GasCanisterWindow.xaml.cs
Normal file
98
Content.Client/Atmos/UI/GasCanisterWindow.xaml.cs
Normal file
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Client-side UI used to control a canister.
|
||||
/// </summary>
|
||||
[GenerateTypedNameReferences]
|
||||
public partial class GasCanisterWindow : SS14Window
|
||||
{
|
||||
private readonly ButtonGroup _buttonGroup = new();
|
||||
|
||||
public event Action? TankEjectButtonPressed;
|
||||
public event Action<float>? 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
54
Content.Client/Atmos/Visualizers/GasCanisterVisualizer.cs
Normal file
54
Content.Client/Atmos/Visualizers/GasCanisterVisualizer.cs
Normal file
@@ -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<ISpriteComponent>();
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#nullable enable
|
||||
using Content.Client.GameObjects.EntitySystems;
|
||||
using Content.Shared;
|
||||
using Content.Shared.CCVar;
|
||||
using Robust.Shared.Configuration;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a <see cref="GasCanisterWindow"/> and updates it when new server messages are received.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public class GasCanisterBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
|
||||
private GasCanisterWindow? _window;
|
||||
|
||||
public GasCanisterBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// When a button is pressed, send a network message to the server
|
||||
/// </summary>
|
||||
/// <param name="button">Which button has been pressed, as an enum item</param>
|
||||
private void ButtonPressed(UiButton button)
|
||||
{
|
||||
SendMessage(new UiButtonPressedMessage(button));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// When the release pressure is changed
|
||||
/// </summary>
|
||||
/// <param name="value">The pressure value</param>
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Called when the edit label button is pressed
|
||||
/// </summary>
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
/// <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 (!(state is GasCanisterBoundUserInterfaceState cast))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_window?.UpdateState(cast);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (!disposing) return;
|
||||
_window?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Client-side UI used to control a <see cref="SharedGasCanisterComponent"/>
|
||||
/// </summary>
|
||||
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<ReleasePressureButton> 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<ReleasePressureButton>();
|
||||
foreach (var control in releasePressureButtons.Children.ToList())
|
||||
{
|
||||
var btn = (ReleasePressureButton) control;
|
||||
ReleasePressureButtons.Add(btn);
|
||||
}
|
||||
|
||||
// Reset the editable label
|
||||
LabelInputEditable = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the UI based on <see cref="GasCanisterBoundUserInterfaceState"/>
|
||||
/// </summary>
|
||||
/// <param name="state">The state the UI should reflect</param>
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Special button class which stores a numerical value and has it as a label
|
||||
/// </summary>
|
||||
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() {}
|
||||
}
|
||||
}
|
||||
@@ -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<ISpriteComponent>(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<ISpriteComponent>(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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the state of the sprite based on what shape of pipe it is.
|
||||
/// </summary>
|
||||
[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<IResourceCache>();
|
||||
|
||||
if (resourceCache.TryGetResource(rsiPath, out RSIResource? rsi))
|
||||
{
|
||||
_pipeRSI = rsi.RSI;
|
||||
}
|
||||
}
|
||||
|
||||
public override void InitializeEntity(IEntity entity)
|
||||
{
|
||||
base.InitializeEntity(entity);
|
||||
if (!entity.TryGetComponent<ISpriteComponent>(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<ISpriteComponent>(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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void MapInit()
|
||||
{
|
||||
if (Owner.Transform.Anchored)
|
||||
{
|
||||
var grid = _mapManager.GetGrid(Owner.Transform.GridID);
|
||||
_lastPosition = (Owner.Transform.GridID, grid.TileIndicesFor(Owner.Transform.Coordinates));
|
||||
}
|
||||
|
||||
UpdatePosition();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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())
|
||||
if (!Owner.Transform.Anchored || !Owner.Transform.GridID.IsValid())
|
||||
return;
|
||||
|
||||
var grid = _mapManager.GetGrid(Owner.Transform.GridID);
|
||||
UpdatePosition(Owner.Transform.GridID, grid.TileIndicesFor(Owner.Transform.Coordinates));
|
||||
}
|
||||
_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);
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents that entity can be exposed to Atmos
|
||||
@@ -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
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Barotrauma: injury because of changes in air pressure.
|
||||
@@ -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;
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Used in internals as breath tool.
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Companion component to ServerDoorComponent that handles firelock-specific behavior -- primarily prying, and not being openable on open-hand click.
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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<NodeContainerComponent>();
|
||||
|
||||
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();
|
||||
|
||||
/// <summary>
|
||||
/// Distributed pressure.
|
||||
@@ -88,6 +118,12 @@ namespace Content.Server.GameObjects.Components.Atmos
|
||||
[DataField("tankFragmentScale")]
|
||||
public float TankFragmentScale { get; set; } = 10 * Atmospherics.OneAtmosphere;
|
||||
|
||||
/// <summary>
|
||||
/// NodeContainer node.
|
||||
/// </summary>
|
||||
[DataField("tank")]
|
||||
public string TankName { get; set; } = "tank";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 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<PipeNetDeviceComponent> _pipeNetDevices = new();
|
||||
private readonly HashSet<AtmosDeviceComponent> _atmosDevices = new();
|
||||
|
||||
[ViewVariables]
|
||||
private double _pipeNetDevicesLastProcess;
|
||||
private double _atmosDevicesLastProcess;
|
||||
|
||||
[ViewVariables]
|
||||
private Queue<TileAtmosphere> _currentRunTiles = new();
|
||||
@@ -143,7 +144,7 @@ namespace Content.Server.GameObjects.Components.Atmos
|
||||
private Queue<IPipeNet> _currentRunPipeNet = new();
|
||||
|
||||
[ViewVariables]
|
||||
private Queue<PipeNetDeviceComponent> _currentRunPipeNetDevice = new();
|
||||
private Queue<AtmosDeviceComponent> _currentRunAtmosDevices = new();
|
||||
|
||||
[ViewVariables]
|
||||
private ProcessState _state = ProcessState.TileEqualize;
|
||||
@@ -162,7 +163,7 @@ namespace Content.Server.GameObjects.Components.Atmos
|
||||
Hotspots,
|
||||
Superconductivity,
|
||||
PipeNet,
|
||||
PipeNetDevices,
|
||||
AtmosDevices,
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -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<PipeNetDeviceComponent>(_pipeNetDevices);
|
||||
_currentRunAtmosDevices = new Queue<AtmosDeviceComponent>(_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;
|
||||
}
|
||||
|
||||
@@ -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<TileAtmosphere>
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether this atmosphere is simulated or not.
|
||||
/// </summary>
|
||||
bool Simulated { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of times <see cref="Update"/> has been called.
|
||||
/// </summary>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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))]
|
||||
@@ -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;
|
||||
}
|
||||
26
Content.Server/Atmos/EntitySystems/AirtightSystem.cs
Normal file
26
Content.Server/Atmos/EntitySystems/AirtightSystem.cs
Normal file
@@ -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<AirtightComponent, SnapGridPositionChangedEvent>(OnAirtightPositionChanged);
|
||||
SubscribeLocalEvent<AirtightComponent, RotateEvent>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
24
Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs
Normal file
24
Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs
Normal file
34
Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs
Normal file
@@ -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<GasReactionPrototype>();
|
||||
private float[] _gasSpecificHeats = new float[Atmospherics.TotalNumberOfGases];
|
||||
|
||||
/// <summary>
|
||||
/// List of gas reactions ordered by priority.
|
||||
/// </summary>
|
||||
public IEnumerable<GasReactionPrototype> GasReactions => _gasReactions!;
|
||||
public float[] GasSpecificHeats => _gasSpecificHeats;
|
||||
|
||||
private void InitializeGases()
|
||||
{
|
||||
_gasReactions = _protoMan.EnumeratePrototypes<GasReactionPrototype>().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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<GasReactionPrototype>();
|
||||
|
||||
private GridTileLookupSystem? _gridTileLookup = null;
|
||||
|
||||
/// <summary>
|
||||
/// List of gas reactions ordered by priority.
|
||||
/// </summary>
|
||||
public IEnumerable<GasReactionPrototype> 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<GridTileLookupSystem>();
|
||||
|
||||
@@ -48,71 +33,16 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_gasReactions = _protoMan.EnumeratePrototypes<GasReactionPrototype>().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>(RotateEvent);
|
||||
SubscribeLocalEvent<AirtightComponent, SnapGridPositionChangedEvent>(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<IGridAtmosphereComponent>())
|
||||
map.AddComponent<SpaceGridAtmosphereComponent>();
|
||||
}
|
||||
|
||||
#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<IGridAtmosphereComponent>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unlike <see cref="GetGridAtmosphere"/>, this doesn't return space grid when not found.
|
||||
/// </summary>
|
||||
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<IMapGridComponent, IGridAtmosphereComponent>(true))
|
||||
{
|
||||
if (_pauseManager.IsGridPaused(mapGridComponent.GridIndex)) continue;
|
||||
|
||||
gridAtmosphereComponent.Update(frameTime);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTileChanged(object? sender, TileChangedEventArgs eventArgs)
|
||||
if (_exposedTimer >= ExposedUpdateDelay)
|
||||
{
|
||||
// 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())
|
||||
foreach (var exposed in EntityManager.ComponentManager.EntityQuery<AtmosExposedComponent>(true))
|
||||
{
|
||||
return;
|
||||
var tile = exposed.Owner.Transform.Coordinates.GetTileAtmosphere();
|
||||
if (tile == null) continue;
|
||||
exposed.Update(tile, _exposedTimer);
|
||||
}
|
||||
|
||||
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<IGridAtmosphereComponent>())
|
||||
map.AddComponent<SpaceGridAtmosphereComponent>();
|
||||
_exposedTimer = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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<Gas> filterGases)
|
||||
{
|
||||
var buffer = new GasMixture(Volume){Temperature = Temperature};
|
||||
|
||||
foreach (var gas in filterGases)
|
||||
{
|
||||
buffer.AdjustMoles(gas, GetMoles(gas));
|
||||
SetMoles(gas, 0f);
|
||||
}
|
||||
|
||||
destination.Merge(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
|
||||
/// <summary>
|
||||
/// Container name for the gas tank holder.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("container")]
|
||||
public string ContainerName { get; set; } = "GasCanisterTankHolder";
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("gasMixture")]
|
||||
public GasMixture InitialMixture { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Stores the last pressure the tank had, for appearance-updating purposes.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public float LastPressure { get; set; } = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// Minimum release pressure possible for the release valve.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("minReleasePressure")]
|
||||
public float MinReleasePressure { get; set; } = Atmospherics.OneAtmosphere / 10;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum release pressure possible for the release valve.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
[DataField("maxReleasePressure")]
|
||||
public float MaxReleasePressure { get; set; } = Atmospherics.OneAtmosphere * 10;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// This is the minimum difference needed to overcome the friction in the mechanism.
|
||||
/// </summary>
|
||||
[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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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<ActionBlockerSystem>().CanInteract(eventArgs.User))
|
||||
Toggle();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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<GasCanisterComponent, ComponentStartup>(OnCanisterStartup);
|
||||
SubscribeLocalEvent<GasCanisterComponent, AtmosDeviceUpdateEvent>(OnCanisterUpdated);
|
||||
SubscribeLocalEvent<GasCanisterComponent, ActivateInWorldEvent>(OnCanisterActivate);
|
||||
SubscribeLocalEvent<GasCanisterComponent, InteractHandEvent>(OnCanisterInteractHand);
|
||||
SubscribeLocalEvent<GasCanisterComponent, InteractUsingEvent>(OnCanisterInteractUsing);
|
||||
SubscribeLocalEvent<GasCanisterComponent, EntInsertedIntoContainerMessage>(OnCanisterContainerInserted);
|
||||
SubscribeLocalEvent<GasCanisterComponent, EntRemovedFromContainerMessage>(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<ActionBlockerSystem>().CanInteract(entity)
|
||||
|| !Get<ActionBlockerSystem>().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<ContainerSlot>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<GasPassiveGateComponent, AtmosDeviceUpdateEvent>(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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<GasPressurePumpComponent, AtmosDeviceUpdateEvent>(OnPumpUpdated);
|
||||
SubscribeLocalEvent<GasPressurePumpComponent, AtmosDeviceDisabledEvent>(OnPumpLeaveAtmosphere);
|
||||
}
|
||||
|
||||
private void OnPumpUpdated(EntityUid uid, GasPressurePumpComponent pump, AtmosDeviceUpdateEvent args)
|
||||
{
|
||||
var appearance = pump.Owner.GetComponentOrNull<AppearanceComponent>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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<GasVolumePumpComponent, AtmosDeviceUpdateEvent>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds itself to a <see cref="IGridAtmosphereComponent"/> to be updated by.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public class AtmosDeviceComponent : Component
|
||||
{
|
||||
public override string Name => "AtmosDevice";
|
||||
|
||||
/// <summary>
|
||||
/// Whether this device requires being anchored to join an atmosphere.
|
||||
/// </summary>
|
||||
[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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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<AtmosDeviceComponent, ComponentInit>(OnDeviceInitialize);
|
||||
SubscribeLocalEvent<AtmosDeviceComponent, ComponentShutdown>(OnDeviceShutdown);
|
||||
SubscribeLocalEvent<AtmosDeviceComponent, PhysicsBodyTypeChangedEvent>(OnDeviceBodyTypeChanged);
|
||||
SubscribeLocalEvent<AtmosDeviceComponent, EntParentChangedMessage>(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<AtmosphereSystem>().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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<AtmosUnsafeUnanchorComponent, BeforeUnanchoredEvent>(OnBeforeUnanchored);
|
||||
SubscribeLocalEvent<AtmosUnsafeUnanchorComponent, UnanchorAttemptEvent>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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<GasMinerComponent, AtmosDeviceUpdateEvent>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user