CatStation/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs
Rouden cc2c14f8e4
Device Network refactor part 1: API improvements (#44346)
* Refactor DeviceNetwork

* Singleton

* NetworkPayloads refactor

* Reorganize DeviceNetworkSystem

* Surveillance cameras

* Fix code

* Fix build

* Fix test fail by rewriting entire singleton logic

* Properly predict examine

* Update DeviceNetworkSystem.API.cs

* Update EntityTest.cs

* Update DeviceNetworkSystem.cs

* Alright I'll do this expensive check fine

* Fix disposals debug assert

* Implement device network static events support

* Use frozen dictionaries for performance

* Update SharedDeviceNetworkSystem.Payloads.cs

* Parallel payload handling support

* Fix some spagetti-code

* Optimize NetworkPayload cancellation

* Parallel payloads are now cancellable

* Fix screens

* Fix robotics console

* Allow new methods for shared

* Mail fix

* Turret fix

* Fix network system method usage + signal and borg fix

* finally fix atmos devices OH MY GOOOD

* Remove stupid parallelism from fax

* Fix surveiollance cameras

* Working on a single thing for 2 days straight award

* Fix the test?

* Update units.yml

* Add IDevice interface because why not

* Add more device network suffixes

* Fix camera router failing test

* yaml linter peak

* Improve docs for DeviceNetworkHandlers

* fix build

* Update CartridgeLoaderSystem.Relay.cs

* Remove parallel system and EntitySystem post init

* Add more docs and also events

* Remove unnecessary caching

* Update DevicePayloadComponentSystem.cs

* Back to entity events

* Implement DeviceData

* Remove serializable from payloads

* Update DeviceData.cs

* Add a prototype for a singleton

* Fix tests

* Fix air alarms

* Update DeviceNetworkSystem.cs

* Fix cameras

* Make camera router event-less

* Fix atmos sync payloads, add more docs

* Remove singleton + instant packets

* oops remove public access

* Fix tests?

* Why the hell overload effect makes puddle sparks

* Apparently it was redundant

* Update gates.yml

* Finish documentation

* Review

* Mark relay properties as obsolete

* Struct payloads support (#blazinglyfastmemorysafe)

* Update DeviceNetworkTest.cs

* Make device structs stuff better

* Move address prefix to DeviceNetworkComponent

* Locale fixes

* Fix tests

* Doesn't know boolean logic award

* Update AtmosAlarmableSystem.cs

* Fix address predicted examine

* Partial fix to air alarmables

* Fix deployable turrets UI

* Fix firelocks, maybe

* Apparently Activatable UI was enough lol

* Fix surveillance cameras

* Rename `QueuePacket` into `SendPacket`

* Simplify DeviceData as much as possible

* Update DeviceData.cs

* Update FaxMachineComponent.cs

* Remove DeviceData because its stupid

* Update ScreenSystem.cs

* Fix build (camera map broken still)

* Fix map

* fix usings

* Review changes

* Build fix
2026-08-31 19:42:56 +00:00

125 lines
5.4 KiB
C#

using Content.Server.Atmos.EntitySystems;
using Content.Server.Atmos.Monitor.Payloads;
using Content.Server.DeviceNetwork.Systems;
using Content.Server.NodeContainer.EntitySystems;
using Content.Server.NodeContainer.Nodes;
using Content.Server.Power.Components;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Piping.Unary.Components;
using JetBrains.Annotations;
using Content.Server.Power.EntitySystems;
using Content.Shared.Atmos.Components;
using Content.Shared.Atmos.Piping.Unary.Systems;
using Content.Shared.DeviceNetwork.Events;
namespace Content.Server.Atmos.Piping.Unary.EntitySystems
{
[UsedImplicitly]
public sealed partial class GasThermoMachineSystem : SharedGasThermoMachineSystem
{
[Dependency] private AtmosphereSystem _atmosphereSystem = default!;
[Dependency] private PowerReceiverSystem _power = default!;
[Dependency] private NodeContainerSystem _nodeContainer = default!;
[Dependency] private DeviceNetworkSystem _deviceNetwork = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<GasThermoMachineComponent, AtmosDeviceUpdateEvent>(OnThermoMachineUpdated);
}
private void OnThermoMachineUpdated(EntityUid uid, GasThermoMachineComponent thermoMachine, ref AtmosDeviceUpdateEvent args)
{
thermoMachine.LastEnergyDelta = 0f;
if (!(_power.IsPowered(uid) && TryComp<ApcPowerReceiverComponent>(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 = heatExchangeGasMixture.Temperature;
if (sign * temp >= sign * highTemp) // upper bound
thermoMachine.HysteresisState = false; // turn off
else if (sign * temp < sign * targetTemp) // lower bound
thermoMachine.HysteresisState = true; // turn on
if (thermoMachine.HysteresisState)
targetTemp = highTemp; // when on, target upper hysteresis bound
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.
//receiver.Load = 0f;
return;
}
// Multiply power in by coefficient of performance, add that heat to gas
float dQ = thermoMachine.HeatCapacity * thermoMachine.Cp * args.dt;
// Clamps the heat transferred to not overshoot
float Cin = _atmosphereSystem.GetHeatCapacity(heatExchangeGasMixture, true);
float dT = targetTemp - temp;
float dQLim = dT * Cin;
float scale = 1f;
if (Math.Abs(dQ) > Math.Abs(dQLim))
{
scale = dQLim / dQ; // reduce power consumption
thermoMachine.HysteresisState = false; // turn off
}
float dQActual = dQ * scale;
if (thermoMachine.Atmospheric)
{
_atmosphereSystem.AddHeat(heatExchangeGasMixture, dQActual);
thermoMachine.LastEnergyDelta = dQActual;
}
else
{
float dQLeak = dQActual * thermoMachine.EnergyLeakPercentage;
float dQPipe = dQActual - dQLeak;
_atmosphereSystem.AddHeat(heatExchangeGasMixture, dQPipe);
thermoMachine.LastEnergyDelta = dQPipe;
if (dQLeak != 0f && _atmosphereSystem.GetContainingMixture(uid, args.Grid, args.Map, excite: true) is { } containingMixture)
_atmosphereSystem.AddHeat(containingMixture, dQLeak);
}
receiver.Load = thermoMachine.HeatCapacity;// * scale; // we're not ready for dynamic load yet, see note above
}
/// <summary>
/// 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.
/// </summary>
private void GetHeatExchangeGasMixture(EntityUid uid, GasThermoMachineComponent thermoMachine, out GasMixture? heatExchangeGasMixture)
{
heatExchangeGasMixture = null;
if (thermoMachine.Atmospheric)
{
heatExchangeGasMixture = _atmosphereSystem.GetContainingMixture(uid, excite: true);
}
else
{
if (!_nodeContainer.TryGetNode(uid, thermoMachine.InletName, out PipeNode? inlet))
return;
heatExchangeGasMixture = inlet.Air;
}
}
[SubscribeLocalEvent]
private void OnSyncPayload(Entity<GasThermoMachineComponent> ent, ref DeviceNetworkPacketEvent<AtmosSyncPayload> args)
{
var data = new GasThermoMachineDataPayload
{
EnergyDelta = ent.Comp.LastEnergyDelta,
};
_deviceNetwork.SendPacket(ent.Owner, args.SenderAddress, ref data);
}
}
}