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
@@ -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())
|
||||
return;
|
||||
var grid = _mapManager.GetGrid(Owner.Transform.GridID);
|
||||
UpdatePosition(Owner.Transform.GridID, grid.TileIndicesFor(Owner.Transform.Coordinates));
|
||||
}
|
||||
if (!Owner.Transform.Anchored || !Owner.Transform.GridID.IsValid())
|
||||
return;
|
||||
|
||||
var grid = _mapManager.GetGrid(Owner.Transform.GridID);
|
||||
_lastPosition = (Owner.Transform.GridID, grid.TileIndicesFor(Owner.Transform.Coordinates));
|
||||
InvalidatePosition(_lastPosition.Item1, _lastPosition.Item2);
|
||||
}
|
||||
|
||||
private void UpdatePosition(GridId gridId, Vector2i pos)
|
||||
private void InvalidatePosition(GridId gridId, Vector2i pos)
|
||||
{
|
||||
if (!gridId.IsValid())
|
||||
return;
|
||||
|
||||
var gridAtmos = _atmosphereSystem.GetGridAtmosphere(gridId);
|
||||
|
||||
gridAtmos?.UpdateAdjacentBits(pos);
|
||||
@@ -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)
|
||||
{
|
||||
// When a tile changes, we want to update it only if it's gone from
|
||||
// space -> not space or vice versa. So if the old tile is the
|
||||
// same as the new tile in terms of space-ness, ignore the change
|
||||
|
||||
if (eventArgs.NewTile.IsSpace() == eventArgs.OldTile.IsSpace())
|
||||
if (_exposedTimer >= ExposedUpdateDelay)
|
||||
{
|
||||
return;
|
||||
foreach (var exposed in EntityManager.ComponentManager.EntityQuery<AtmosExposedComponent>(true))
|
||||
{
|
||||
var tile = exposed.Owner.Transform.Coordinates.GetTileAtmosphere();
|
||||
if (tile == null) continue;
|
||||
exposed.Update(tile, _exposedTimer);
|
||||
}
|
||||
|
||||
_exposedTimer = 0;
|
||||
}
|
||||
|
||||
GetGridAtmosphere(eventArgs.NewTile.GridPosition(_mapManager))?.Invalidate(eventArgs.NewTile.GridIndices);
|
||||
}
|
||||
|
||||
private void OnMapCreated(object? sender, MapEventArgs e)
|
||||
{
|
||||
if (e.Map == MapId.Nullspace)
|
||||
return;
|
||||
|
||||
var map = _mapManager.GetMapEntity(e.Map);
|
||||
|
||||
if (!map.HasComponent<IGridAtmosphereComponent>())
|
||||
map.AddComponent<SpaceGridAtmosphereComponent>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using Content.Shared.Atmos;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.Atmos.Piping.Trinary.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class GasMixerComponent : Component
|
||||
{
|
||||
public override string Name => "GasMixer";
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool Enabled = true;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("inletOne")]
|
||||
public string InletOneName = "inletOne";
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("inletTwo")]
|
||||
public string InletTwoName = "inletTwo";
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("outlet")]
|
||||
public string OutletName = "outlet";
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float TargetPressure = Atmospherics.OneAtmosphere;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float InletOneConcentration = 0.5f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float InletTwoConcentration = 0.5f;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.Atmos.Piping.Trinary.Components;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Shared.Atmos;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Atmos.Piping.Trinary.EntitySystems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class GasFilterSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private IGameTiming _gameTiming = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<GasFilterComponent, AtmosDeviceUpdateEvent>(OnFilterUpdated);
|
||||
}
|
||||
|
||||
private void OnFilterUpdated(EntityUid uid, GasFilterComponent filter, AtmosDeviceUpdateEvent args)
|
||||
{
|
||||
if (!filter.Enabled)
|
||||
return;
|
||||
|
||||
if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
|
||||
return;
|
||||
|
||||
if (!ComponentManager.TryGetComponent(uid, out AtmosDeviceComponent? device))
|
||||
return;
|
||||
|
||||
if (!nodeContainer.TryGetNode(filter.InletName, out PipeNode? inletNode)
|
||||
|| !nodeContainer.TryGetNode(filter.FilterName, out PipeNode? filterNode)
|
||||
|| !nodeContainer.TryGetNode(filter.OutletName, out PipeNode? outletNode))
|
||||
return;
|
||||
|
||||
if (outletNode.Air.Pressure >= Atmospherics.MaxOutputPressure)
|
||||
return; // No need to transfer if target is full.
|
||||
|
||||
// We multiply the transfer rate in L/s by the seconds passed since the last process to get the liters.
|
||||
var transferRatio = (float)(filter.TransferRate * (_gameTiming.CurTime - device.LastProcess).TotalSeconds) / inletNode.Air.Volume;
|
||||
|
||||
if (transferRatio <= 0)
|
||||
return;
|
||||
|
||||
var removed = inletNode.Air.RemoveRatio(transferRatio);
|
||||
|
||||
if (filter.FilteredGas.HasValue)
|
||||
{
|
||||
var filteredOut = new GasMixture() {Temperature = removed.Temperature};
|
||||
|
||||
filteredOut.SetMoles(filter.FilteredGas.Value, removed.GetMoles(filter.FilteredGas.Value));
|
||||
removed.SetMoles(filter.FilteredGas.Value, 0f);
|
||||
|
||||
var target = filterNode.Air.Pressure < Atmospherics.MaxOutputPressure ? filterNode : inletNode;
|
||||
target.AssumeAir(filteredOut);
|
||||
}
|
||||
|
||||
outletNode.AssumeAir(removed);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.Atmos.Piping.Trinary.Components;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Shared.Atmos;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.Atmos.Piping.Trinary.EntitySystems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class GasMixerSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<GasMixerComponent, AtmosDeviceUpdateEvent>(OnMixerUpdated);
|
||||
}
|
||||
|
||||
private void OnMixerUpdated(EntityUid uid, GasMixerComponent mixer, AtmosDeviceUpdateEvent args)
|
||||
{
|
||||
// TODO ATMOS: Cache total moles since it's expensive.
|
||||
|
||||
if (!mixer.Enabled)
|
||||
return;
|
||||
|
||||
if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
|
||||
return;
|
||||
|
||||
if (!nodeContainer.TryGetNode(mixer.InletOneName, out PipeNode? inletOne)
|
||||
|| !nodeContainer.TryGetNode(mixer.InletTwoName, out PipeNode? inletTwo)
|
||||
|| !nodeContainer.TryGetNode(mixer.OutletName, out PipeNode? outlet))
|
||||
return;
|
||||
|
||||
var outputStartingPressure = outlet.Air.Pressure;
|
||||
|
||||
if (outputStartingPressure >= mixer.TargetPressure)
|
||||
return; // Target reached, no need to mix.
|
||||
|
||||
var generalTransfer = (mixer.TargetPressure - outputStartingPressure) * outlet.Air.Volume / Atmospherics.R;
|
||||
|
||||
var transferMolesOne = inletOne.Air.Temperature > 0 ? mixer.InletOneConcentration * generalTransfer / inletOne.Air.Temperature : 0f;
|
||||
var transferMolesTwo = inletTwo.Air.Temperature > 0 ? mixer.InletTwoConcentration * generalTransfer / inletTwo.Air.Temperature : 0f;
|
||||
|
||||
if (mixer.InletTwoConcentration <= 0f)
|
||||
{
|
||||
if (inletOne.Air.Temperature <= 0f)
|
||||
return;
|
||||
|
||||
transferMolesOne = MathF.Min(transferMolesOne, inletOne.Air.TotalMoles);
|
||||
transferMolesTwo = 0f;
|
||||
}
|
||||
|
||||
else if (mixer.InletOneConcentration <= 0)
|
||||
{
|
||||
if (inletTwo.Air.Temperature <= 0f)
|
||||
return;
|
||||
|
||||
transferMolesOne = 0f;
|
||||
transferMolesTwo = MathF.Min(transferMolesTwo, inletTwo.Air.TotalMoles);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (inletOne.Air.Temperature <= 0f || inletTwo.Air.Temperature <= 0f)
|
||||
return;
|
||||
|
||||
if (transferMolesOne <= 0 || transferMolesTwo <= 0)
|
||||
return;
|
||||
|
||||
if (inletOne.Air.TotalMoles < transferMolesOne || inletTwo.Air.TotalMoles < transferMolesTwo)
|
||||
{
|
||||
var ratio = MathF.Min(inletOne.Air.TotalMoles / transferMolesOne, inletTwo.Air.TotalMoles / transferMolesTwo);
|
||||
transferMolesOne *= ratio;
|
||||
transferMolesTwo *= ratio;
|
||||
}
|
||||
}
|
||||
|
||||
// Actually transfer the gas now.
|
||||
|
||||
if (transferMolesOne > 0f)
|
||||
{
|
||||
var removed = inletOne.Air.Remove(transferMolesOne);
|
||||
outlet.AssumeAir(removed);
|
||||
}
|
||||
|
||||
if (transferMolesTwo > 0f)
|
||||
{
|
||||
var removed = inletTwo.Air.Remove(transferMolesTwo);
|
||||
outlet.AssumeAir(removed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.Atmos.Piping.Unary.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class GasOutletInjectorComponent : Component
|
||||
{
|
||||
public override string Name => "GasOutletInjector";
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool Enabled { get; set; } = true;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool Injecting { get; set; } = false;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float VolumeRate { get; set; } = 50f;
|
||||
|
||||
[DataField("inlet")]
|
||||
public string InletName { get; set; } = "pipe";
|
||||
|
||||
// TODO ATMOS: Inject method.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Server.Atmos.Piping.Unary.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class GasPassiveVentComponent : Component
|
||||
{
|
||||
public override string Name => "GasPassiveVent";
|
||||
|
||||
[DataField("inlet")]
|
||||
public string InletName = "pipe";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.Atmos.Piping.Unary.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class GasPortableComponent : Component
|
||||
{
|
||||
public override string Name => "GasPortable";
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("port")]
|
||||
public string PortName { get; set; } = "port";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.Construction;
|
||||
using Content.Server.Construction.Components;
|
||||
using Content.Shared.Atmos;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.Atmos.Piping.Unary.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class GasThermoMachineComponent : Component, IRefreshParts, ISerializationHooks
|
||||
{
|
||||
public override string Name => "GasThermoMachine";
|
||||
|
||||
[DataField("inlet")]
|
||||
public string InletName { get; set; } = "pipe";
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool Enabled { get; set; } = true;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float HeatCapacity { get; set; } = 0;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float TargetTemperature { get; set; } = Atmospherics.T20C;
|
||||
|
||||
[DataField("mode")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public ThermoMachineMode Mode { get; set; } = ThermoMachineMode.Freezer;
|
||||
|
||||
[DataField("minTemperature")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float MinTemperature { get; set; } = Atmospherics.T20C;
|
||||
|
||||
[DataField("maxTemperature")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float MaxTemperature { get; set; } = Atmospherics.T20C;
|
||||
|
||||
public float InitialMinTemperature { get; private set; }
|
||||
public float InitialMaxTemperature { get; private set; }
|
||||
|
||||
void IRefreshParts.RefreshParts(IEnumerable<MachinePartComponent> parts)
|
||||
{
|
||||
var matterBinRating = 0;
|
||||
var laserRating = 0;
|
||||
|
||||
foreach (var part in parts)
|
||||
{
|
||||
switch (part.PartType)
|
||||
{
|
||||
case MachinePart.MatterBin:
|
||||
matterBinRating += part.Rating;
|
||||
break;
|
||||
case MachinePart.Laser:
|
||||
laserRating += part.Rating;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
HeatCapacity = 5000 * MathF.Pow((matterBinRating - 1), 2);
|
||||
|
||||
switch (Mode)
|
||||
{
|
||||
// 573.15K with stock parts.
|
||||
case ThermoMachineMode.Heater:
|
||||
MaxTemperature = Atmospherics.T20C + (InitialMaxTemperature * laserRating);
|
||||
break;
|
||||
// 73.15K with stock parts.
|
||||
case ThermoMachineMode.Freezer:
|
||||
MinTemperature = MathF.Max(Atmospherics.T0C - InitialMinTemperature + laserRating * 15f, Atmospherics.TCMB);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ISerializationHooks.AfterDeserialization()
|
||||
{
|
||||
InitialMinTemperature = MinTemperature;
|
||||
InitialMaxTemperature = MaxTemperature;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ThermoMachineMode : byte
|
||||
{
|
||||
Freezer = 0,
|
||||
Heater = 1,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using Content.Shared.Atmos;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.Atmos.Piping.Unary.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class GasVentPumpComponent : Component
|
||||
{
|
||||
public override string Name => "GasVentPump";
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool Enabled { get; set; } = true;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool Welded { get; set; } = false;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("inlet")]
|
||||
public string InletName { get; set; } = "pipe";
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public VentPumpDirection PumpDirection { get; set; } = VentPumpDirection.Releasing;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public VentPressureBound PressureChecks { get; set; } = VentPressureBound.ExternalBound;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float ExternalPressureBound { get; set; } = Atmospherics.OneAtmosphere;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float InternalPressureBound { get; set; } = 0f;
|
||||
}
|
||||
|
||||
public enum VentPumpDirection : sbyte
|
||||
{
|
||||
Siphoning = 0,
|
||||
Releasing = 1,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum VentPressureBound : sbyte
|
||||
{
|
||||
NoBound = 0,
|
||||
InternalBound = 1,
|
||||
ExternalBound = 2,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Atmos;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.Atmos.Piping.Unary.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class GasVentScrubberComponent : Component
|
||||
{
|
||||
public override string Name => "GasVentScrubber";
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool Enabled { get; set; } = true;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool Welded { get; set; } = false;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("outlet")]
|
||||
public string OutletName { get; set; } = "pipe";
|
||||
|
||||
[ViewVariables]
|
||||
public readonly HashSet<Gas> FilterGases = new()
|
||||
{
|
||||
Gas.CarbonDioxide
|
||||
};
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public ScrubberPumpDirection PumpDirection { get; set; } = ScrubberPumpDirection.Scrubbing;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float VolumeRate { get; set; } = 200f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool WideNet { get; set; } = false;
|
||||
}
|
||||
|
||||
public enum ScrubberPumpDirection : sbyte
|
||||
{
|
||||
Siphoning = 0,
|
||||
Scrubbing = 1,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.Atmos.Piping.Unary.Components;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Shared.Atmos;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.Atmos.Piping.Unary.EntitySystems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class GasOutletInjectorSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<GasOutletInjectorComponent, AtmosDeviceUpdateEvent>(OnOutletInjectorUpdated);
|
||||
}
|
||||
|
||||
private void OnOutletInjectorUpdated(EntityUid uid, GasOutletInjectorComponent injector, AtmosDeviceUpdateEvent args)
|
||||
{
|
||||
injector.Injecting = false;
|
||||
|
||||
if (!injector.Enabled)
|
||||
return;
|
||||
|
||||
if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
|
||||
return;
|
||||
|
||||
if (!nodeContainer.TryGetNode(injector.InletName, out PipeNode? inlet))
|
||||
return;
|
||||
|
||||
var environment = args.Atmosphere.GetTile(injector.Owner.Transform.Coordinates)!;
|
||||
|
||||
if (environment.Air == null)
|
||||
return;
|
||||
|
||||
if (inlet.Air.Temperature > 0)
|
||||
{
|
||||
var transferMoles = inlet.Air.Pressure * injector.VolumeRate / (inlet.Air.Temperature * Atmospherics.R);
|
||||
|
||||
var removed = inlet.Air.Remove(transferMoles);
|
||||
|
||||
environment.AssumeAir(removed);
|
||||
environment.Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.Atmos.Piping.Unary.Components;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Shared.Atmos;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.Atmos.Piping.Unary.EntitySystems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class GasPassiveVentSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<GasPassiveVentComponent, AtmosDeviceUpdateEvent>(OnPassiveVentUpdated);
|
||||
}
|
||||
|
||||
private void OnPassiveVentUpdated(EntityUid uid, GasPassiveVentComponent vent, AtmosDeviceUpdateEvent args)
|
||||
{
|
||||
var environment = args.Atmosphere.GetTile(vent.Owner.Transform.Coordinates)!;
|
||||
|
||||
if (environment.Air == null)
|
||||
return;
|
||||
|
||||
if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
|
||||
return;
|
||||
|
||||
if (!nodeContainer.TryGetNode(vent.InletName, out PipeNode? inlet))
|
||||
return;
|
||||
|
||||
var environmentPressure = environment.Air.Pressure;
|
||||
var pressureDelta = MathF.Abs(environmentPressure - inlet.Air.Pressure);
|
||||
|
||||
if ((environment.Air.Temperature > 0 || inlet.Air.Temperature > 0) && pressureDelta > 0.5f)
|
||||
{
|
||||
if (environmentPressure < inlet.Air.Pressure)
|
||||
{
|
||||
var airTemperature = environment.Temperature > 0 ? environment.Temperature : inlet.Air.Temperature;
|
||||
var transferMoles = pressureDelta * environment.Air.Volume / (airTemperature * Atmospherics.R);
|
||||
var removed = inlet.Air.Remove(transferMoles);
|
||||
environment.AssumeAir(removed);
|
||||
}
|
||||
else
|
||||
{
|
||||
var airTemperature = inlet.Air.Temperature > 0 ? inlet.Air.Temperature : environment.Temperature;
|
||||
var outputVolume = inlet.Air.Volume;
|
||||
var transferMoles = (pressureDelta * outputVolume) / (airTemperature * Atmospherics.R);
|
||||
transferMoles = MathF.Min(transferMoles, environment.Air.TotalMoles * inlet.Air.Volume / environment.Air.Volume);
|
||||
var removed = environment.Air.Remove(transferMoles);
|
||||
inlet.AssumeAir(removed);
|
||||
environment.Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Server.Anchor;
|
||||
using Content.Server.Atmos.Piping.Binary.Components;
|
||||
using Content.Server.Atmos.Piping.Unary.Components;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Shared.Atmos.Piping.Unary.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Server.Atmos.Piping.Unary.EntitySystems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class GasPortableSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<GasPortableComponent, AnchorAttemptEvent>(OnPortableAnchorAttempt);
|
||||
SubscribeLocalEvent<GasPortableComponent, AnchoredEvent>(OnPortableAnchored);
|
||||
SubscribeLocalEvent<GasPortableComponent, UnanchoredEvent>(OnPortableUnanchored);
|
||||
}
|
||||
|
||||
private void OnPortableAnchorAttempt(EntityUid uid, GasPortableComponent component, AnchorAttemptEvent args)
|
||||
{
|
||||
if (!ComponentManager.TryGetComponent(uid, out ITransformComponent? transform))
|
||||
return;
|
||||
|
||||
// If we can't find any ports, cancel the anchoring.
|
||||
if(!FindGasPortIn(transform.GridID, transform.Coordinates, out _))
|
||||
args.Cancel();
|
||||
}
|
||||
|
||||
private void OnPortableAnchored(EntityUid uid, GasPortableComponent portable, AnchoredEvent args)
|
||||
{
|
||||
if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
|
||||
return;
|
||||
|
||||
if (!nodeContainer.TryGetNode(portable.PortName, out PipeNode? portableNode))
|
||||
return;
|
||||
|
||||
portableNode.ConnectionsEnabled = true;
|
||||
|
||||
if (ComponentManager.TryGetComponent(uid, out AppearanceComponent? appearance))
|
||||
{
|
||||
appearance.SetData(GasPortableVisuals.ConnectedState, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPortableUnanchored(EntityUid uid, GasPortableComponent portable, UnanchoredEvent args)
|
||||
{
|
||||
if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
|
||||
return;
|
||||
|
||||
if (!nodeContainer.TryGetNode(portable.PortName, out PipeNode? portableNode))
|
||||
return;
|
||||
|
||||
portableNode.ConnectionsEnabled = false;
|
||||
|
||||
if (ComponentManager.TryGetComponent(uid, out AppearanceComponent? appearance))
|
||||
{
|
||||
appearance.SetData(GasPortableVisuals.ConnectedState, false);
|
||||
}
|
||||
}
|
||||
|
||||
private bool FindGasPortIn(GridId gridId, EntityCoordinates coordinates, [NotNullWhen(true)] out GasPortComponent? port)
|
||||
{
|
||||
port = null;
|
||||
|
||||
if (!gridId.IsValid())
|
||||
return false;
|
||||
|
||||
var grid = _mapManager.GetGrid(gridId);
|
||||
|
||||
foreach (var entityUid in grid.GetLocal(coordinates))
|
||||
{
|
||||
if (ComponentManager.TryGetComponent<GasPortComponent>(entityUid, out port))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.NodeContainer;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.Atmos.Piping.Unary.EntitySystems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class GasTankSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<GasTankComponent, ComponentStartup>(OnTankStartup);
|
||||
}
|
||||
|
||||
private void OnTankStartup(EntityUid uid, GasTankComponent tank, ComponentStartup args)
|
||||
{
|
||||
if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
|
||||
return;
|
||||
|
||||
if (!nodeContainer.TryGetNode(tank.TankName, out PipeNode? tankNode))
|
||||
return;
|
||||
|
||||
// Create a pipenet if we don't have one already.
|
||||
tankNode.TryAssignGroupIfNeeded();
|
||||
tankNode.AssumeAir(tank.InitialMixture);
|
||||
tankNode.Volume = tank.InitialMixture.Volume;
|
||||
tankNode.Air.Volume = tank.InitialMixture.Volume;
|
||||
tankNode.Air.Temperature = tank.InitialMixture.Temperature;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.Atmos.Piping.Unary.Components;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Shared.Atmos.Piping;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.Atmos.Piping.Unary.EntitySystems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class GasThermoMachineSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<GasThermoMachineComponent, AtmosDeviceUpdateEvent>(OnThermoMachineUpdated);
|
||||
SubscribeLocalEvent<GasThermoMachineComponent, AtmosDeviceDisabledEvent>(OnThermoMachineLeaveAtmosphere);
|
||||
}
|
||||
|
||||
private void OnThermoMachineUpdated(EntityUid uid, GasThermoMachineComponent thermoMachine, AtmosDeviceUpdateEvent args)
|
||||
{
|
||||
var appearance = thermoMachine.Owner.GetComponentOrNull<AppearanceComponent>();
|
||||
appearance?.SetData(ThermoMachineVisuals.Enabled, false);
|
||||
|
||||
if (!thermoMachine.Enabled)
|
||||
return;
|
||||
|
||||
if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
|
||||
return;
|
||||
|
||||
if (!nodeContainer.TryGetNode(thermoMachine.InletName, out PipeNode? inlet))
|
||||
return;
|
||||
|
||||
var airHeatCapacity = inlet.Air.HeatCapacity;
|
||||
var combinedHeatCapacity = airHeatCapacity + thermoMachine.HeatCapacity;
|
||||
var oldTemperature = inlet.Air.Temperature;
|
||||
|
||||
if (combinedHeatCapacity > 0)
|
||||
{
|
||||
appearance?.SetData(ThermoMachineVisuals.Enabled, true);
|
||||
var combinedEnergy = thermoMachine.HeatCapacity * thermoMachine.TargetTemperature + airHeatCapacity * inlet.Air.Temperature;
|
||||
inlet.Air.Temperature = combinedEnergy / combinedHeatCapacity;
|
||||
}
|
||||
|
||||
// TODO ATMOS: Active power usage.
|
||||
}
|
||||
|
||||
private void OnThermoMachineLeaveAtmosphere(EntityUid uid, GasThermoMachineComponent component, AtmosDeviceDisabledEvent args)
|
||||
{
|
||||
if (ComponentManager.TryGetComponent(uid, out AppearanceComponent? appearance))
|
||||
{
|
||||
appearance.SetData(ThermoMachineVisuals.Enabled, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.Atmos.Piping.Unary.Components;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.Visuals;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.Atmos.Piping.Unary.EntitySystems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class GasVentPumpSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<GasVentPumpComponent, AtmosDeviceUpdateEvent>(OnGasVentPumpUpdated);
|
||||
SubscribeLocalEvent<GasVentPumpComponent, AtmosDeviceDisabledEvent>(OnGasVentPumpLeaveAtmosphere);
|
||||
}
|
||||
|
||||
private void OnGasVentPumpUpdated(EntityUid uid, GasVentPumpComponent vent, AtmosDeviceUpdateEvent args)
|
||||
{
|
||||
var appearance = vent.Owner.GetComponentOrNull<AppearanceComponent>();
|
||||
|
||||
if (vent.Welded)
|
||||
{
|
||||
appearance?.SetData(VentPumpVisuals.State, VentPumpState.Welded);
|
||||
return;
|
||||
}
|
||||
|
||||
appearance?.SetData(VentPumpVisuals.State, VentPumpState.Off);
|
||||
|
||||
if (!vent.Enabled)
|
||||
return;
|
||||
|
||||
if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
|
||||
return;
|
||||
|
||||
if (!nodeContainer.TryGetNode(vent.InletName, out PipeNode? pipe))
|
||||
return;
|
||||
|
||||
var environment = args.Atmosphere.GetTile(vent.Owner.Transform.Coordinates)!;
|
||||
|
||||
// We're in an air-blocked tile... Do nothing.
|
||||
if (environment.Air == null)
|
||||
return;
|
||||
|
||||
if (vent.PumpDirection == VentPumpDirection.Releasing)
|
||||
{
|
||||
appearance?.SetData(VentPumpVisuals.State, VentPumpState.Out);
|
||||
var pressureDelta = 10000f;
|
||||
|
||||
if ((vent.PressureChecks & VentPressureBound.ExternalBound) != 0)
|
||||
pressureDelta = MathF.Min(pressureDelta, vent.ExternalPressureBound - environment.Air.Pressure);
|
||||
|
||||
if ((vent.PressureChecks & VentPressureBound.InternalBound) != 0)
|
||||
pressureDelta = MathF.Min(pressureDelta, pipe.Air.Pressure - vent.InternalPressureBound);
|
||||
|
||||
if (pressureDelta > 0 && pipe.Air.Temperature > 0)
|
||||
{
|
||||
var transferMoles = pressureDelta * environment.Air.Volume / (pipe.Air.Temperature * Atmospherics.R);
|
||||
|
||||
environment.AssumeAir(pipe.Air.Remove(transferMoles));
|
||||
}
|
||||
}
|
||||
else if (vent.PumpDirection == VentPumpDirection.Siphoning && environment.Air.Pressure > 0)
|
||||
{
|
||||
appearance?.SetData(VentPumpVisuals.State, VentPumpState.In);
|
||||
var ourMultiplier = pipe.Air.Volume / (environment.Air.Temperature * Atmospherics.R);
|
||||
var molesDelta = 10000f * ourMultiplier;
|
||||
|
||||
if ((vent.PressureChecks & VentPressureBound.ExternalBound) != 0)
|
||||
molesDelta = MathF.Min(molesDelta,
|
||||
(environment.Air.Pressure - vent.ExternalPressureBound) * environment.Air.Volume /
|
||||
(environment.Air.Temperature * Atmospherics.R));
|
||||
|
||||
if ((vent.PressureChecks & VentPressureBound.InternalBound) != 0)
|
||||
molesDelta = MathF.Min(molesDelta, (vent.InternalPressureBound - pipe.Air.Pressure) * ourMultiplier);
|
||||
|
||||
if (molesDelta > 0)
|
||||
{
|
||||
var removed = environment.Air.Remove(molesDelta);
|
||||
pipe.AssumeAir(removed);
|
||||
environment.Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGasVentPumpLeaveAtmosphere(EntityUid uid, GasVentPumpComponent component, AtmosDeviceDisabledEvent args)
|
||||
{
|
||||
if (ComponentManager.TryGetComponent(uid, out AppearanceComponent? appearance))
|
||||
{
|
||||
appearance.SetData(VentPumpVisuals.State, VentPumpState.Off);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
using System;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.Atmos.Piping.Unary.Components;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.Piping.Unary.Visuals;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.Server.Atmos.Piping.Unary.EntitySystems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class GasVentScrubberSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<GasVentScrubberComponent, AtmosDeviceUpdateEvent>(OnVentScrubberUpdated);
|
||||
SubscribeLocalEvent<GasVentScrubberComponent, AtmosDeviceDisabledEvent>(OnVentScrubberLeaveAtmosphere);
|
||||
}
|
||||
|
||||
private void OnVentScrubberUpdated(EntityUid uid, GasVentScrubberComponent scrubber, AtmosDeviceUpdateEvent args)
|
||||
{
|
||||
var appearance = scrubber.Owner.GetComponentOrNull<AppearanceComponent>();
|
||||
|
||||
if (scrubber.Welded)
|
||||
{
|
||||
appearance?.SetData(ScrubberVisuals.State, ScrubberState.Welded);
|
||||
return;
|
||||
}
|
||||
|
||||
appearance?.SetData(ScrubberVisuals.State, ScrubberState.Off);
|
||||
|
||||
if (!scrubber.Enabled)
|
||||
return;
|
||||
|
||||
if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
|
||||
return;
|
||||
|
||||
if (!nodeContainer.TryGetNode(scrubber.OutletName, out PipeNode? outlet))
|
||||
return;
|
||||
|
||||
var environment = args.Atmosphere.GetTile(scrubber.Owner.Transform.Coordinates)!;
|
||||
|
||||
Scrub(scrubber, appearance, environment, outlet);
|
||||
|
||||
if (!scrubber.WideNet) return;
|
||||
|
||||
// Scrub adjacent tiles too.
|
||||
foreach (var adjacent in environment.AdjacentTiles)
|
||||
{
|
||||
// Pass null appearance, we don't need to set it there.
|
||||
Scrub(scrubber, null, adjacent, outlet);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnVentScrubberLeaveAtmosphere(EntityUid uid, GasVentScrubberComponent component, AtmosDeviceDisabledEvent args)
|
||||
{
|
||||
if (ComponentManager.TryGetComponent(uid, out AppearanceComponent? appearance))
|
||||
{
|
||||
appearance.SetData(ScrubberVisuals.State, ScrubberState.Off);
|
||||
}
|
||||
}
|
||||
|
||||
private void Scrub(GasVentScrubberComponent scrubber, AppearanceComponent? appearance, TileAtmosphere? tile, PipeNode outlet)
|
||||
{
|
||||
// Cannot scrub if tile is null or air-blocked.
|
||||
if (tile?.Air == null)
|
||||
return;
|
||||
|
||||
// Cannot scrub if pressure too high.
|
||||
if (outlet.Air.Pressure >= 50 * Atmospherics.OneAtmosphere)
|
||||
return;
|
||||
|
||||
if (scrubber.PumpDirection == ScrubberPumpDirection.Scrubbing)
|
||||
{
|
||||
appearance?.SetData(ScrubberVisuals.State, scrubber.WideNet ? ScrubberState.WideScrub : ScrubberState.Scrub);
|
||||
var transferMoles = MathF.Min(1f, (scrubber.VolumeRate / tile.Air.Volume) * tile.Air.TotalMoles);
|
||||
|
||||
// Take a gas sample.
|
||||
var removed = tile.Air.Remove(transferMoles);
|
||||
|
||||
// Nothing left to remove from the tile.
|
||||
if (MathHelper.CloseTo(removed.TotalMoles, 0f))
|
||||
return;
|
||||
|
||||
removed.ScrubInto(outlet.Air, scrubber.FilterGases);
|
||||
|
||||
// Remix the gases.
|
||||
tile.AssumeAir(removed);
|
||||
}
|
||||
else if (scrubber.PumpDirection == ScrubberPumpDirection.Siphoning)
|
||||
{
|
||||
appearance?.SetData(ScrubberVisuals.State, ScrubberState.Siphon);
|
||||
var transferMoles = tile.Air.TotalMoles * (scrubber.VolumeRate / tile.Air.Volume);
|
||||
|
||||
var removed = tile.Air.Remove(transferMoles);
|
||||
|
||||
outlet.AssumeAir(removed);
|
||||
tile.Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
#nullable enable
|
||||
using Content.Server.Fluids.Components;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Chemistry.Solution;
|
||||
using Content.Shared.Maps;
|
||||
|
||||
@@ -4,9 +4,9 @@ using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Atmos.Reactions;
|
||||
using Content.Server.Coordinates.Helpers;
|
||||
using Content.Server.GameObjects.Components.Atmos;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Audio;
|
||||
@@ -72,6 +72,8 @@ namespace Content.Server.Atmos
|
||||
[ViewVariables]
|
||||
private readonly TileAtmosphere[] _adjacentTiles = new TileAtmosphere[Atmospherics.Directions];
|
||||
|
||||
public IReadOnlyList<TileAtmosphere> AdjacentTiles => _adjacentTiles;
|
||||
|
||||
private AtmosDirection _adjacentBits = AtmosDirection.Invalid;
|
||||
|
||||
[ViewVariables, UsedImplicitly]
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using Content.Server.Atmos;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Body.Circulatory;
|
||||
using Content.Server.Body.Respiratory;
|
||||
using Content.Server.GameObjects.Components.Atmos;
|
||||
using Content.Server.Notification;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Body.Components;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#nullable enable
|
||||
using Content.Server.GameObjects.Components.Atmos;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Chemistry.Solution;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Notification.Managers;
|
||||
using Content.Shared.Random.Helpers;
|
||||
using Content.Shared.Verbs;
|
||||
|
||||
@@ -4,7 +4,6 @@ using Content.Server.Weapon.Melee;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Notification;
|
||||
using Content.Shared.Notification.Managers;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
@@ -8,7 +8,6 @@ using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Chemistry.Solution.Components;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Helpers;
|
||||
using Content.Shared.Notification;
|
||||
using Content.Shared.Notification.Managers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Localization;
|
||||
|
||||
@@ -6,7 +6,6 @@ using Content.Shared.Body.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Helpers;
|
||||
using Content.Shared.Notification;
|
||||
using Content.Shared.Notification.Managers;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
@@ -13,7 +13,6 @@ using Content.Shared.Chemistry.Dispenser;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Chemistry.Solution;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Notification.Managers;
|
||||
using Content.Shared.Verbs;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Coordinates.Helpers;
|
||||
using Content.Server.GameObjects.Components.Atmos;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Chemistry.Solution;
|
||||
|
||||
@@ -4,7 +4,6 @@ using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Chemistry.Solution.Components;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Helpers;
|
||||
using Content.Shared.Notification;
|
||||
using Content.Shared.Notification.Managers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Localization;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.Chemistry.Components;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Chemistry.Solution;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects.Components.Atmos;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Chemistry.Solution;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects.Components.Atmos;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Chemistry.Solution;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.Nutrition.Components;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Chemistry.Solution;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
@@ -5,7 +5,6 @@ using Content.Shared.Clothing;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.NetIDs;
|
||||
using Content.Shared.Notification;
|
||||
using Content.Shared.Notification.Managers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Players;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable enable
|
||||
using Content.Server.Alert;
|
||||
using Content.Server.GameObjects.Components.Atmos;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Inventory.Components;
|
||||
using Content.Server.Items;
|
||||
using Content.Shared.ActionBlocker;
|
||||
@@ -10,7 +10,6 @@ using Content.Shared.Actions.Components;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Clothing;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Verbs;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#nullable enable
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.Atmos;
|
||||
using Content.Server.GameObjects.Components.Atmos;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable enable
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.GameObjects.Components.Atmos;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.Atmos;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#nullable enable
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.Atmos;
|
||||
using Content.Server.GameObjects.Components.Atmos;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.GameObjects.Components.Atmos;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.Atmos;
|
||||
using Robust.Server.Player;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#nullable enable
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.Atmos;
|
||||
using Content.Server.GameObjects.Components.Atmos;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.Atmos;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#nullable enable
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.Atmos;
|
||||
using Content.Server.GameObjects.Components.Atmos;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.Atmos;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable enable
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable enable
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.GameObjects.Components.Atmos;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable enable
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.GameObjects.Components.Atmos;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.Atmos;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable enable
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.GameObjects.Components.Atmos;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.Atmos;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable enable
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.GameObjects.EntitySystems.Atmos;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Stack;
|
||||
using Content.Shared.Construction;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
using Content.Shared.Stacks;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Server.Construction.Completions
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Stack;
|
||||
using Content.Shared.Construction;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
using Content.Shared.Prototypes;
|
||||
using Content.Shared.Stacks;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
@@ -121,6 +121,7 @@ namespace Content.Server.Construction.Components
|
||||
public void MapInit()
|
||||
{
|
||||
CreateBoardAndStockParts();
|
||||
RefreshParts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Content.Server.Conveyor
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("angle")]
|
||||
private Angle _angle;
|
||||
private Angle _angle = Angle.Zero;
|
||||
|
||||
public float Speed => _speed;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.Atmos.Components;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.Atmos;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Components;
|
||||
using Content.Shared.Damage.Resistances;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Content.Server.GameObjects.Components.Atmos;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Nutrition.Components;
|
||||
using Content.Server.Stunnable.Components;
|
||||
using Content.Shared.Damage.Components;
|
||||
|
||||
@@ -6,9 +6,9 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Anchor;
|
||||
using Content.Server.Atmos;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Disposal.Tube.Components;
|
||||
using Content.Server.DoAfter;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.Power.Components;
|
||||
@@ -19,7 +19,6 @@ using Content.Shared.Disposal.Components;
|
||||
using Content.Shared.DragDrop;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Movement;
|
||||
using Content.Shared.Notification;
|
||||
using Content.Shared.Notification.Managers;
|
||||
using Content.Shared.Throwing;
|
||||
using Content.Shared.Verbs;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user