Make atmos Turing-complete (#10520)

* Add pneumatic valves

Pneumatic valves permit bidirectional flow between the inlet and outlet
if the pressure at the control port is high enough.

* Add construction recipe
This commit is contained in:
Kevin Zheng
2022-08-11 14:19:31 -07:00
committed by GitHub
parent 3d511900e9
commit 9cb7e0f6c4
8 changed files with 242 additions and 1 deletions

View File

@@ -0,0 +1,35 @@
using Content.Shared.Atmos;
namespace Content.Server.Atmos.Piping.Trinary.Components
{
[RegisterComponent]
public sealed class PressureControlledValveComponent : Component
{
[ViewVariables(VVAccess.ReadWrite)]
[DataField("inlet")]
public string InletName { get; set; } = "inlet";
[ViewVariables(VVAccess.ReadWrite)]
[DataField("control")]
public string ControlName { get; set; } = "control";
[ViewVariables(VVAccess.ReadWrite)]
[DataField("outlet")]
public string OutletName { get; set; } = "outlet";
[ViewVariables(VVAccess.ReadOnly)]
[DataField("enabled")]
public bool Enabled { get; set; } = false;
[ViewVariables(VVAccess.ReadWrite)]
[DataField("gain")]
public float Gain { get; set; } = 10;
[ViewVariables(VVAccess.ReadWrite)]
[DataField("threshold")]
public float Threshold { get; set; } = Atmospherics.OneAtmosphere;
[DataField("maxTransferRate")]
public float MaxTransferRate { get; set; } = Atmospherics.MaxTransferRate;
}
}

View File

@@ -0,0 +1,96 @@
using Content.Server.Atmos.EntitySystems;
using Content.Server.Atmos.Piping.Components;
using Content.Server.Atmos.Piping.Trinary.Components;
using Content.Server.NodeContainer;
using Content.Server.NodeContainer.Nodes;
using Content.Shared.Atmos.Piping;
using Content.Shared.Audio;
using JetBrains.Annotations;
using Robust.Shared.Timing;
namespace Content.Server.Atmos.Piping.Trinary.EntitySystems
{
[UsedImplicitly]
public sealed class PressureControlledValveSystem : EntitySystem
{
[Dependency] private IGameTiming _gameTiming = default!;
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
[Dependency] private readonly SharedAmbientSoundSystem _ambientSoundSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PressureControlledValveComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<PressureControlledValveComponent, AtmosDeviceUpdateEvent>(OnUpdate);
SubscribeLocalEvent<PressureControlledValveComponent, AtmosDeviceDisabledEvent>(OnFilterLeaveAtmosphere);
}
private void OnInit(EntityUid uid, PressureControlledValveComponent comp, ComponentInit args)
{
UpdateAppearance(uid, comp);
}
private void OnUpdate(EntityUid uid, PressureControlledValveComponent comp, AtmosDeviceUpdateEvent args)
{
if (!EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
|| !EntityManager.TryGetComponent(uid, out AtmosDeviceComponent? device)
|| !nodeContainer.TryGetNode(comp.InletName, out PipeNode? inletNode)
|| !nodeContainer.TryGetNode(comp.ControlName, out PipeNode? controlNode)
|| !nodeContainer.TryGetNode(comp.OutletName, out PipeNode? outletNode))
{
_ambientSoundSystem.SetAmbience(comp.Owner, false);
comp.Enabled = false;
return;
}
// If output is higher than input, flip input/output to enable bidirectional flow.
if (outletNode.Air.Pressure > inletNode.Air.Pressure)
{
PipeNode temp = outletNode;
outletNode = inletNode;
inletNode = temp;
}
float control = (controlNode.Air.Pressure - outletNode.Air.Pressure) - comp.Threshold;
float transferRate;
if (control < 0)
{
comp.Enabled = false;
transferRate = 0;
}
else
{
comp.Enabled = true;
transferRate = Math.Min(control * comp.Gain, comp.MaxTransferRate);
}
UpdateAppearance(uid, comp);
// We multiply the transfer rate in L/s by the seconds passed since the last process to get the liters.
var transferRatio = (float)(transferRate * (_gameTiming.CurTime - device.LastProcess).TotalSeconds) / inletNode.Air.Volume;
if (transferRatio <= 0)
{
_ambientSoundSystem.SetAmbience(comp.Owner, false);
return;
}
_ambientSoundSystem.SetAmbience(comp.Owner, true);
var removed = inletNode.Air.RemoveRatio(transferRatio);
_atmosphereSystem.Merge(outletNode.Air, removed);
}
private void OnFilterLeaveAtmosphere(EntityUid uid, PressureControlledValveComponent comp, AtmosDeviceDisabledEvent args)
{
comp.Enabled = false;
UpdateAppearance(uid, comp);
_ambientSoundSystem.SetAmbience(comp.Owner, false);
}
private void UpdateAppearance(EntityUid uid, PressureControlledValveComponent? comp = null, AppearanceComponent? appearance = null)
{
if (!Resolve(uid, ref comp, ref appearance, false))
return;
appearance.SetData(FilterVisuals.Enabled, comp.Enabled);
}
}
}

View File

@@ -198,3 +198,58 @@
!type:PipeNode !type:PipeNode
nodeGroupID: Pipe nodeGroupID: Pipe
pipeDirection: North pipeDirection: North
- type: entity
parent: GasPipeBase
id: PressureControlledValve
name: pneumatic valve
description: Valve controlled by pressure.
placement:
mode: SnapgridCenter
components:
- type: AtmosDevice
- type: SubFloorHide
blockInteractions: false
blockAmbience: false
- type: NodeContainer
nodes:
inlet:
!type:PipeNode
nodeGroupID: Pipe
pipeDirection: North
control:
!type:PipeNode
nodeGroupID: Pipe
pipeDirection: West
outlet:
!type:PipeNode
nodeGroupID: Pipe
pipeDirection: South
- type: Sprite
netsync: false
sprite: Structures/Piping/Atmospherics/pneumaticvalve.rsi
layers:
- sprite: Structures/Piping/Atmospherics/pipe.rsi
state: pipeTJunction
rotation: -90
map: [ "enum.PipeVisualLayers.Pipe" ]
- state: off
map: [ "enum.SubfloorLayers.FirstLayer", "enabled" ]
- type: Appearance
- type: GenericVisualizer
visuals:
enum.FilterVisuals.Enabled:
enabled:
True: { state: on }
False: { state: off }
- type: PipeColorVisuals
- type: PressureControlledValve
- type: AmbientSound
enabled: false
volume: -9
range: 5
sound:
path: /Audio/Ambience/Objects/gas_hiss.ogg
- type: Construction
graph: GasTrinary
node: pneumaticvalve

View File

@@ -16,6 +16,12 @@
amount: 2 amount: 2
doAfter: 1 doAfter: 1
- to: pneumaticvalve
steps:
- material: Steel
amount: 2
doAfter: 1
- node: filter - node: filter
entity: GasFilter entity: GasFilter
edges: edges:
@@ -47,3 +53,19 @@
steps: steps:
- tool: Welding - tool: Welding
doAfter: 1 doAfter: 1
- node: pneumaticvalve
entity: PressureControlledValve
edges:
- to: start
conditions:
- !type:EntityAnchored
anchored: false
completed:
- !type:SpawnPrototype
prototype: SheetSteel1
amount: 2
- !type:DeleteEntity
steps:
- tool: Welding
doAfter: 1

View File

@@ -12,7 +12,7 @@
state: camera state: camera
objectType: Structure objectType: Structure
placementMode: SnapgridCenter placementMode: SnapgridCenter
- type: construction - type: construction
name: telescreen name: telescreen
id: WallmountTelescreen id: WallmountTelescreen
@@ -511,3 +511,17 @@
conditions: conditions:
- !type:TileNotBlocked {} - !type:TileNotBlocked {}
- type: construction
id: PressureControlledValve
name: pneumatic valve
graph: GasTrinary
startNode: start
targetNode: pneumaticvalve
category: Utilities
placementMode: SnapgridCenter
canBuildInImpassable: false
icon:
sprite: Structures/Piping/Atmospherics/pneumaticvalve.rsi
state: off
conditions:
- !type:TileNotBlocked {}

View File

@@ -0,0 +1,19 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"copyright": "Kevin Zheng 2022",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "off",
"directions": 4
},
{
"name": "on",
"directions": 4
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB