From ce4bd8568cba4d64fb19e80d3182e21f010a86c1 Mon Sep 17 00:00:00 2001 From: Menshin Date: Thu, 15 Feb 2024 02:00:21 +0100 Subject: [PATCH] Allow thermomachines to exchange with air instead of inlet (#25247) Add purely atmospheric heat exchange to the gas thermomachine component (in preparation for space heaters). --- .../Components/GasThermoMachineComponent.cs | 6 ++ .../EntitySystems/GasThermoMachineSystem.cs | 57 ++++++++++++++----- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/Content.Server/Atmos/Piping/Unary/Components/GasThermoMachineComponent.cs b/Content.Server/Atmos/Piping/Unary/Components/GasThermoMachineComponent.cs index 93d973d123..5da4ec9fdf 100644 --- a/Content.Server/Atmos/Piping/Unary/Components/GasThermoMachineComponent.cs +++ b/Content.Server/Atmos/Piping/Unary/Components/GasThermoMachineComponent.cs @@ -64,5 +64,11 @@ namespace Content.Server.Atmos.Piping.Unary.Components /// [DataField, ViewVariables(VVAccess.ReadWrite)] public float EnergyLeakPercentage; + + /// + /// If true, heat is exclusively exchanged with the local atmosphere instead of the inlet pipe air + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public bool Atmospheric = false; } } diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs index 645b2ecc45..2900082623 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs @@ -55,17 +55,17 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems private void OnThermoMachineUpdated(EntityUid uid, GasThermoMachineComponent thermoMachine, ref AtmosDeviceUpdateEvent args) { - if (!(_power.IsPowered(uid) && TryComp(uid, out var receiver)) - || !TryComp(uid, out var nodeContainer) - || !_nodeContainer.TryGetNode(nodeContainer, thermoMachine.InletName, out PipeNode? inlet)) - { + if (!(_power.IsPowered(uid) && TryComp(uid, out var receiver))) + return; + + GetHeatExchangeGasMixture(uid, thermoMachine, out var heatExchangeGasMixture); + if (heatExchangeGasMixture == null) return; - } float sign = Math.Sign(thermoMachine.Cp); // 1 if heater, -1 if freezer float targetTemp = thermoMachine.TargetTemperature; float highTemp = targetTemp + sign * thermoMachine.TemperatureTolerance; - float temp = inlet.Air.Temperature; + float temp = heatExchangeGasMixture.Temperature; if (sign * temp >= sign * highTemp) // upper bound thermoMachine.HysteresisState = false; // turn off @@ -74,8 +74,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems if (thermoMachine.HysteresisState) targetTemp = highTemp; // when on, target upper hysteresis bound - - if (!thermoMachine.HysteresisState) // Hysteresis is the same as "Should this be on?" + else // Hysteresis is the same as "Should this be on?" { // Turn dynamic load back on when power has been adjusted to not cause lights to // blink every time this heater comes on. @@ -87,7 +86,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems float dQ = thermoMachine.HeatCapacity * thermoMachine.Cp * args.dt; // Clamps the heat transferred to not overshoot - float Cin = _atmosphereSystem.GetHeatCapacity(inlet.Air, true); + float Cin = _atmosphereSystem.GetHeatCapacity(heatExchangeGasMixture, true); float dT = targetTemp - temp; float dQLim = dT * Cin; float scale = 1f; @@ -96,17 +95,45 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems scale = dQLim / dQ; // reduce power consumption thermoMachine.HysteresisState = false; // turn off } - float dQActual = dQ * scale; - float dQLeak = dQActual * thermoMachine.EnergyLeakPercentage; - float dQPipe = dQActual - dQLeak; - _atmosphereSystem.AddHeat(inlet.Air, dQPipe); - if (_atmosphereSystem.GetContainingMixture(uid) is { } containingMixture) - _atmosphereSystem.AddHeat(containingMixture, dQLeak); + float dQActual = dQ * scale; + if (thermoMachine.Atmospheric) + { + _atmosphereSystem.AddHeat(heatExchangeGasMixture, dQActual); + } + else + { + float dQLeak = dQActual * thermoMachine.EnergyLeakPercentage; + float dQPipe = dQActual - dQLeak; + _atmosphereSystem.AddHeat(heatExchangeGasMixture, dQPipe); + + if (dQLeak != 0f && _atmosphereSystem.GetContainingMixture(uid) is { } containingMixture) + _atmosphereSystem.AddHeat(containingMixture, dQLeak); + } receiver.Load = thermoMachine.HeatCapacity;// * scale; // we're not ready for dynamic load yet, see note above } + /// + /// Returns the gas mixture with which the thermomachine will exchange heat (the local atmosphere if atmospheric or the inlet pipe + /// air if not). Returns null if no gas mixture is found. + /// + private void GetHeatExchangeGasMixture(EntityUid uid, GasThermoMachineComponent thermoMachine, out GasMixture? heatExchangeGasMixture) + { + heatExchangeGasMixture = null; + if (thermoMachine.Atmospheric) + { + heatExchangeGasMixture = _atmosphereSystem.GetContainingMixture(uid); + } + else + { + if (!TryComp(uid, out var nodeContainer) + || !_nodeContainer.TryGetNode(nodeContainer, thermoMachine.InletName, out PipeNode? inlet)) + return; + heatExchangeGasMixture = inlet.Air; + } + } + private bool IsHeater(GasThermoMachineComponent comp) { return comp.Cp >= 0;