Add atmos.speedup which is effectively a atmos-only time compression CVar. This adjusts heat capacities and transfer rates to effectively globally speed up the time constants of atmos. This allows faster response to heating/cooling changes and faster cleanups (by buffing scrubbers, pumps, and everything else) that is tunable through one global time compression CVar. It also achieves this without any thermodynamic unsoundness.
214 lines
9.3 KiB
C#
214 lines
9.3 KiB
C#
using Content.Server.Administration.Logs;
|
|
using Content.Server.Atmos.EntitySystems;
|
|
using Content.Server.Atmos.Monitor.Systems;
|
|
using Content.Server.Atmos.Piping.Binary.Components;
|
|
using Content.Server.Atmos.Piping.Components;
|
|
using Content.Server.DeviceNetwork;
|
|
using Content.Server.DeviceNetwork.Components;
|
|
using Content.Server.DeviceNetwork.Systems;
|
|
using Content.Server.NodeContainer;
|
|
using Content.Server.NodeContainer.EntitySystems;
|
|
using Content.Server.NodeContainer.Nodes;
|
|
using Content.Shared.Atmos.Piping.Binary.Components;
|
|
using Content.Shared.Atmos.Visuals;
|
|
using Content.Shared.Audio;
|
|
using Content.Shared.Database;
|
|
using Content.Shared.Examine;
|
|
using Content.Shared.Interaction;
|
|
using Content.Shared.Popups;
|
|
using JetBrains.Annotations;
|
|
using Robust.Server.GameObjects;
|
|
using Robust.Shared.Player;
|
|
|
|
namespace Content.Server.Atmos.Piping.Binary.EntitySystems
|
|
{
|
|
[UsedImplicitly]
|
|
public sealed class GasVolumePumpSystem : EntitySystem
|
|
{
|
|
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
|
[Dependency] private readonly TransformSystem _transformSystem = default!;
|
|
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
|
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
|
|
[Dependency] private readonly SharedAmbientSoundSystem _ambientSoundSystem = default!;
|
|
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
|
[Dependency] private readonly NodeContainerSystem _nodeContainer = default!;
|
|
[Dependency] private readonly DeviceNetworkSystem _deviceNetwork = default!;
|
|
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
|
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
|
|
SubscribeLocalEvent<GasVolumePumpComponent, ComponentInit>(OnInit);
|
|
SubscribeLocalEvent<GasVolumePumpComponent, AtmosDeviceUpdateEvent>(OnVolumePumpUpdated);
|
|
SubscribeLocalEvent<GasVolumePumpComponent, AtmosDeviceDisabledEvent>(OnVolumePumpLeaveAtmosphere);
|
|
SubscribeLocalEvent<GasVolumePumpComponent, ExaminedEvent>(OnExamined);
|
|
SubscribeLocalEvent<GasVolumePumpComponent, ActivateInWorldEvent>(OnPumpActivate);
|
|
// Bound UI subscriptions
|
|
SubscribeLocalEvent<GasVolumePumpComponent, GasVolumePumpChangeTransferRateMessage>(OnTransferRateChangeMessage);
|
|
SubscribeLocalEvent<GasVolumePumpComponent, GasVolumePumpToggleStatusMessage>(OnToggleStatusMessage);
|
|
|
|
SubscribeLocalEvent<GasVolumePumpComponent, DeviceNetworkPacketEvent>(OnPacketRecv);
|
|
}
|
|
|
|
private void OnInit(EntityUid uid, GasVolumePumpComponent pump, ComponentInit args)
|
|
{
|
|
UpdateAppearance(uid, pump);
|
|
}
|
|
|
|
private void OnExamined(EntityUid uid, GasVolumePumpComponent pump, ExaminedEvent args)
|
|
{
|
|
if (!EntityManager.GetComponent<TransformComponent>(uid).Anchored || !args.IsInDetailsRange) // Not anchored? Out of range? No status.
|
|
return;
|
|
|
|
if (Loc.TryGetString("gas-volume-pump-system-examined", out var str,
|
|
("statusColor", "lightblue"), // TODO: change with volume?
|
|
("rate", pump.TransferRate)
|
|
))
|
|
args.PushMarkup(str);
|
|
}
|
|
|
|
private void OnVolumePumpUpdated(EntityUid uid, GasVolumePumpComponent pump, AtmosDeviceUpdateEvent args)
|
|
{
|
|
if (!pump.Enabled
|
|
|| !TryComp(uid, out NodeContainerComponent? nodeContainer)
|
|
|| !TryComp(uid, out AtmosDeviceComponent? device)
|
|
|| !_nodeContainer.TryGetNode(nodeContainer, pump.InletName, out PipeNode? inlet)
|
|
|| !_nodeContainer.TryGetNode(nodeContainer, pump.OutletName, out PipeNode? outlet))
|
|
{
|
|
_ambientSoundSystem.SetAmbience(uid, false);
|
|
return;
|
|
}
|
|
|
|
var inputStartingPressure = inlet.Air.Pressure;
|
|
var outputStartingPressure = outlet.Air.Pressure;
|
|
|
|
var previouslyBlocked = pump.Blocked;
|
|
pump.Blocked = false;
|
|
|
|
// 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)
|
|
{
|
|
pump.Blocked = true;
|
|
}
|
|
|
|
// Overclocked pumps can only force gas a certain amount.
|
|
if ((outputStartingPressure - inputStartingPressure > pump.OverclockThreshold) && pump.Overclocked)
|
|
{
|
|
pump.Blocked = true;
|
|
}
|
|
|
|
if (previouslyBlocked != pump.Blocked)
|
|
UpdateAppearance(uid, pump);
|
|
if (pump.Blocked)
|
|
return;
|
|
|
|
// We multiply the transfer rate in L/s by the seconds passed since the last process to get the liters.
|
|
var removed = inlet.Air.RemoveVolume(pump.TransferRate * _atmosphereSystem.PumpSpeedup() * args.dt);
|
|
|
|
// Some of the gas from the mixture leaks when overclocked.
|
|
if (pump.Overclocked)
|
|
{
|
|
var tile = _atmosphereSystem.GetTileMixture(uid, excite: true);
|
|
|
|
if (tile != null)
|
|
{
|
|
var leaked = removed.RemoveRatio(pump.LeakRatio);
|
|
_atmosphereSystem.Merge(tile, leaked);
|
|
}
|
|
}
|
|
|
|
pump.LastMolesTransferred = removed.TotalMoles;
|
|
|
|
_atmosphereSystem.Merge(outlet.Air, removed);
|
|
_ambientSoundSystem.SetAmbience(uid, removed.TotalMoles > 0f);
|
|
}
|
|
|
|
private void OnVolumePumpLeaveAtmosphere(EntityUid uid, GasVolumePumpComponent pump, AtmosDeviceDisabledEvent args)
|
|
{
|
|
pump.Enabled = false;
|
|
UpdateAppearance(uid, pump);
|
|
|
|
DirtyUI(uid, pump);
|
|
_userInterfaceSystem.TryCloseAll(uid, GasVolumePumpUiKey.Key);
|
|
}
|
|
|
|
private void OnPumpActivate(EntityUid uid, GasVolumePumpComponent pump, ActivateInWorldEvent args)
|
|
{
|
|
if (!EntityManager.TryGetComponent(args.User, out ActorComponent? actor))
|
|
return;
|
|
|
|
if (Transform(uid).Anchored)
|
|
{
|
|
_userInterfaceSystem.TryOpen(uid, GasVolumePumpUiKey.Key, actor.PlayerSession);
|
|
DirtyUI(uid, pump);
|
|
}
|
|
else
|
|
{
|
|
_popup.PopupCursor(Loc.GetString("comp-gas-pump-ui-needs-anchor"), args.User);
|
|
}
|
|
|
|
args.Handled = true;
|
|
}
|
|
|
|
private void OnToggleStatusMessage(EntityUid uid, GasVolumePumpComponent pump, GasVolumePumpToggleStatusMessage args)
|
|
{
|
|
pump.Enabled = args.Enabled;
|
|
_adminLogger.Add(LogType.AtmosPowerChanged, LogImpact.Medium,
|
|
$"{ToPrettyString(args.Session.AttachedEntity!.Value):player} set the power on {ToPrettyString(uid):device} to {args.Enabled}");
|
|
DirtyUI(uid, pump);
|
|
UpdateAppearance(uid, pump);
|
|
}
|
|
|
|
private void OnTransferRateChangeMessage(EntityUid uid, GasVolumePumpComponent pump, GasVolumePumpChangeTransferRateMessage args)
|
|
{
|
|
pump.TransferRate = Math.Clamp(args.TransferRate, 0f, pump.MaxTransferRate);
|
|
_adminLogger.Add(LogType.AtmosVolumeChanged, LogImpact.Medium,
|
|
$"{ToPrettyString(args.Session.AttachedEntity!.Value):player} set the transfer rate on {ToPrettyString(uid):device} to {args.TransferRate}");
|
|
DirtyUI(uid, pump);
|
|
}
|
|
|
|
private void DirtyUI(EntityUid uid, GasVolumePumpComponent? pump)
|
|
{
|
|
if (!Resolve(uid, ref pump))
|
|
return;
|
|
|
|
_userInterfaceSystem.TrySetUiState(uid, GasVolumePumpUiKey.Key,
|
|
new GasVolumePumpBoundUserInterfaceState(Name(uid), pump.TransferRate, pump.Enabled));
|
|
}
|
|
|
|
private void UpdateAppearance(EntityUid uid, GasVolumePumpComponent? pump = null, AppearanceComponent? appearance = null)
|
|
{
|
|
if (!Resolve(uid, ref pump, ref appearance, false))
|
|
return;
|
|
|
|
if (!pump.Enabled)
|
|
_appearance.SetData(uid, GasVolumePumpVisuals.State, GasVolumePumpState.Off, appearance);
|
|
else if (pump.Blocked)
|
|
_appearance.SetData(uid, GasVolumePumpVisuals.State, GasVolumePumpState.Blocked, appearance);
|
|
else
|
|
_appearance.SetData(uid, GasVolumePumpVisuals.State, GasVolumePumpState.On, appearance);
|
|
}
|
|
|
|
private void OnPacketRecv(EntityUid uid, GasVolumePumpComponent component, DeviceNetworkPacketEvent args)
|
|
{
|
|
if (!TryComp(uid, out DeviceNetworkComponent? netConn)
|
|
|| !args.Data.TryGetValue(DeviceNetworkConstants.Command, out var cmd))
|
|
return;
|
|
|
|
var payload = new NetworkPayload();
|
|
|
|
switch (cmd)
|
|
{
|
|
case AtmosDeviceNetworkSystem.SyncData:
|
|
payload.Add(DeviceNetworkConstants.Command, AtmosDeviceNetworkSystem.SyncData);
|
|
payload.Add(AtmosDeviceNetworkSystem.SyncData, new GasVolumePumpData(component.LastMolesTransferred));
|
|
|
|
_deviceNetwork.QueuePacket(uid, args.SenderAddress, payload, device: netConn);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|