Add radiators (#18728)
* Add radiators * Limit heat transfer to fluid heat capacity * Adjust datafield names * Fix material arbitrage * This code has been debugged, and so there are no more bugs. Debugging code is therefore unnecessary * Adjust radiator layer subfloor visibility * Cache CVars * No default Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * Like and unsubscribe * Fix CVar caching --------- Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
This commit is contained in:
36
Content.Server/Atmos/Components/HeatExchangerComponent.cs
Normal file
36
Content.Server/Atmos/Components/HeatExchangerComponent.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
namespace Content.Server.Atmos.Components;
|
||||||
|
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class HeatExchangerComponent : Component
|
||||||
|
{
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("inlet")]
|
||||||
|
public string InletName { get; set; } = "inlet";
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("outlet")]
|
||||||
|
public string OutletName { get; set; } = "outlet";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pipe conductivity (mols/kPa/sec).
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("conductivity")]
|
||||||
|
public float G { get; set; } = 1f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Thermal convection coefficient (J/degK/sec).
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("convectionCoefficient")]
|
||||||
|
public float K { get; set; } = 8000f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Thermal radiation coefficient. Number of "effective" tiles this
|
||||||
|
/// radiator radiates compared to superconductivity tile losses.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("radiationCoefficient")]
|
||||||
|
public float alpha { get; set; } = 400f;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -78,6 +78,16 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
return mixture.Temperature * cachedHeatCapacity;
|
return mixture.Temperature * cachedHeatCapacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add 'dQ' Joules of energy into 'mixture'.
|
||||||
|
/// </summary>
|
||||||
|
public void AddHeat(GasMixture mixture, float dQ)
|
||||||
|
{
|
||||||
|
var c = GetHeatCapacity(mixture);
|
||||||
|
float dT = dQ / c;
|
||||||
|
mixture.Temperature += dT;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Merges the <see cref="giver"/> gas mixture into the <see cref="receiver"/> gas mixture.
|
/// Merges the <see cref="giver"/> gas mixture into the <see cref="receiver"/> gas mixture.
|
||||||
/// The <see cref="giver"/> gas mixture is not modified by this method.
|
/// The <see cref="giver"/> gas mixture is not modified by this method.
|
||||||
|
|||||||
97
Content.Server/Atmos/EntitySystems/HeatExchangerSystem.cs
Normal file
97
Content.Server/Atmos/EntitySystems/HeatExchangerSystem.cs
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
using Content.Server.Atmos.EntitySystems;
|
||||||
|
using Content.Server.Atmos.Piping.Components;
|
||||||
|
using Content.Server.Atmos.Piping.Unary.Components;
|
||||||
|
using Content.Server.Atmos;
|
||||||
|
using Content.Server.Atmos.Components;
|
||||||
|
using Content.Server.NodeContainer.EntitySystems;
|
||||||
|
using Content.Server.NodeContainer.Nodes;
|
||||||
|
using Content.Server.NodeContainer;
|
||||||
|
using Content.Shared.Atmos.Piping;
|
||||||
|
using Content.Shared.Atmos;
|
||||||
|
using Content.Shared.CCVar;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Shared.Configuration;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
|
namespace Content.Server.Atmos.EntitySystems;
|
||||||
|
|
||||||
|
public sealed class HeatExchangerSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
||||||
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
|
[Dependency] private readonly NodeContainerSystem _nodeContainer = default!;
|
||||||
|
|
||||||
|
float tileLoss;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
SubscribeLocalEvent<HeatExchangerComponent, AtmosDeviceUpdateEvent>(OnAtmosUpdate);
|
||||||
|
|
||||||
|
// Getting CVars is expensive, don't do it every tick
|
||||||
|
_cfg.OnValueChanged(CCVars.SuperconductionTileLoss, CacheTileLoss, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Shutdown()
|
||||||
|
{
|
||||||
|
base.Shutdown();
|
||||||
|
_cfg.UnsubValueChanged(CCVars.SuperconductionTileLoss, CacheTileLoss);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CacheTileLoss(float val)
|
||||||
|
{
|
||||||
|
tileLoss = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnAtmosUpdate(EntityUid uid, HeatExchangerComponent comp, AtmosDeviceUpdateEvent args)
|
||||||
|
{
|
||||||
|
if (!EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
|
||||||
|
|| !_nodeContainer.TryGetNode(nodeContainer, comp.InletName, out PipeNode? inlet)
|
||||||
|
|| !_nodeContainer.TryGetNode(nodeContainer, comp.OutletName, out PipeNode? outlet))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Positive dN flows from inlet to outlet
|
||||||
|
var dt = 1/_atmosphereSystem.AtmosTickRate;
|
||||||
|
var dP = inlet.Air.Pressure - outlet.Air.Pressure;
|
||||||
|
var dN = comp.G*dP*dt;
|
||||||
|
|
||||||
|
GasMixture xfer;
|
||||||
|
if (dN > 0)
|
||||||
|
xfer = inlet.Air.Remove(dN);
|
||||||
|
else
|
||||||
|
xfer = outlet.Air.Remove(-dN);
|
||||||
|
|
||||||
|
var radTemp = Atmospherics.TCMB;
|
||||||
|
|
||||||
|
// Convection
|
||||||
|
var environment = _atmosphereSystem.GetContainingMixture(uid, true, true);
|
||||||
|
if (environment != null)
|
||||||
|
{
|
||||||
|
radTemp = environment.Temperature;
|
||||||
|
|
||||||
|
// Positive dT is from pipe to surroundings
|
||||||
|
var dT = xfer.Temperature - environment.Temperature;
|
||||||
|
var dE = comp.K * dT * dt;
|
||||||
|
var envLim = Math.Abs(_atmosphereSystem.GetHeatCapacity(environment) * dT * dt);
|
||||||
|
var xferLim = Math.Abs(_atmosphereSystem.GetHeatCapacity(xfer) * dT * dt);
|
||||||
|
var dEactual = Math.Sign(dE) * Math.Min(Math.Abs(dE), Math.Min(envLim, xferLim));
|
||||||
|
_atmosphereSystem.AddHeat(xfer, -dEactual);
|
||||||
|
_atmosphereSystem.AddHeat(environment, dEactual);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Radiation
|
||||||
|
float dTR = xfer.Temperature - radTemp;
|
||||||
|
float a0 = tileLoss / MathF.Pow(Atmospherics.T20C, 4);
|
||||||
|
float dER = comp.alpha * a0 * MathF.Pow(dTR, 4) * dt;
|
||||||
|
_atmosphereSystem.AddHeat(xfer, -dER);
|
||||||
|
|
||||||
|
if (dN > 0)
|
||||||
|
_atmosphereSystem.Merge(outlet.Air, xfer);
|
||||||
|
else
|
||||||
|
_atmosphereSystem.Merge(inlet.Air, xfer);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -937,6 +937,12 @@ namespace Content.Shared.CCVar
|
|||||||
public static readonly CVarDef<bool> Superconduction =
|
public static readonly CVarDef<bool> Superconduction =
|
||||||
CVarDef.Create("atmos.superconduction", false, CVar.SERVERONLY);
|
CVarDef.Create("atmos.superconduction", false, CVar.SERVERONLY);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Heat loss per tile due to radiation at 20 degC, in W.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly CVarDef<float> SuperconductionTileLoss =
|
||||||
|
CVarDef.Create("atmos.superconduction_tile_loss", 30f, CVar.SERVERONLY);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether excited groups will be processed and created.
|
/// Whether excited groups will be processed and created.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -379,3 +379,45 @@
|
|||||||
acts: ["Destruction"]
|
acts: ["Destruction"]
|
||||||
- type: Machine
|
- type: Machine
|
||||||
board: GasRecyclerMachineCircuitboard
|
board: GasRecyclerMachineCircuitboard
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: GasBinaryBase
|
||||||
|
id: HeatExchanger
|
||||||
|
name: radiator
|
||||||
|
description: Transfers heat between the pipe and its surroundings.
|
||||||
|
placement:
|
||||||
|
mode: SnapgridCenter
|
||||||
|
components:
|
||||||
|
- type: Rotatable
|
||||||
|
- type: Transform
|
||||||
|
noRot: false
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Structures/Piping/Atmospherics/heatexchanger.rsi
|
||||||
|
layers:
|
||||||
|
- sprite: Structures/Piping/Atmospherics/pipe.rsi
|
||||||
|
state: pipeStraight
|
||||||
|
map: [ "enum.PipeVisualLayers.Pipe" ]
|
||||||
|
- state: heStraight
|
||||||
|
map: [ "enum.SubfloorLayers.FirstLayer" ]
|
||||||
|
- type: SubFloorHide
|
||||||
|
visibleLayers:
|
||||||
|
- enum.SubfloorLayers.FirstLayer
|
||||||
|
- type: Appearance
|
||||||
|
- type: PipeColorVisuals
|
||||||
|
- type: AtmosDevice
|
||||||
|
- type: HeatExchanger
|
||||||
|
- type: NodeContainer
|
||||||
|
nodes:
|
||||||
|
inlet:
|
||||||
|
!type:PipeNode
|
||||||
|
nodeGroupID: Pipe
|
||||||
|
pipeDirection: North
|
||||||
|
outlet:
|
||||||
|
!type:PipeNode
|
||||||
|
nodeGroupID: Pipe
|
||||||
|
pipeDirection: South
|
||||||
|
- type: Construction
|
||||||
|
graph: GasBinary
|
||||||
|
node: radiator
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 50
|
||||||
|
|||||||
@@ -46,6 +46,12 @@
|
|||||||
amount: 2
|
amount: 2
|
||||||
doAfter: 1
|
doAfter: 1
|
||||||
|
|
||||||
|
- to: radiator
|
||||||
|
steps:
|
||||||
|
- material: Steel
|
||||||
|
amount: 8
|
||||||
|
doAfter: 1
|
||||||
|
|
||||||
- node: pressurepump
|
- node: pressurepump
|
||||||
entity: GasPressurePump
|
entity: GasPressurePump
|
||||||
edges:
|
edges:
|
||||||
@@ -159,3 +165,21 @@
|
|||||||
doAfter: 1
|
doAfter: 1
|
||||||
- tool: Welding
|
- tool: Welding
|
||||||
doAfter: 1
|
doAfter: 1
|
||||||
|
|
||||||
|
- node: radiator
|
||||||
|
entity: HeatExchanger
|
||||||
|
edges:
|
||||||
|
- to: start
|
||||||
|
conditions:
|
||||||
|
- !type:EntityAnchored
|
||||||
|
anchored: false
|
||||||
|
completed:
|
||||||
|
- !type:SpawnPrototype
|
||||||
|
prototype: SheetSteel1
|
||||||
|
amount: 8
|
||||||
|
- !type:DeleteEntity
|
||||||
|
steps:
|
||||||
|
- tool: Screwing
|
||||||
|
doAfter: 1
|
||||||
|
- tool: Welding
|
||||||
|
doAfter: 1
|
||||||
|
|||||||
@@ -663,6 +663,22 @@
|
|||||||
conditions:
|
conditions:
|
||||||
- !type:TileNotBlocked {}
|
- !type:TileNotBlocked {}
|
||||||
|
|
||||||
|
- type: construction
|
||||||
|
id: HeatExchanger
|
||||||
|
name: radiator
|
||||||
|
description: Transfers heat between the pipe and its surroundings.
|
||||||
|
graph: GasBinary
|
||||||
|
startNode: start
|
||||||
|
targetNode: radiator
|
||||||
|
category: construction-category-utilities
|
||||||
|
placementMode: SnapgridCenter
|
||||||
|
canBuildInImpassable: false
|
||||||
|
icon:
|
||||||
|
sprite: Structures/Piping/Atmospherics/heatexchanger.rsi
|
||||||
|
state: heStraight
|
||||||
|
conditions:
|
||||||
|
- !type:TileNotBlocked {}
|
||||||
|
|
||||||
# ATMOS TRINARY
|
# ATMOS TRINARY
|
||||||
- type: construction
|
- type: construction
|
||||||
id: GasFilter
|
id: GasFilter
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 929 B |
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"version":1,
|
||||||
|
"size":{
|
||||||
|
"x":32,
|
||||||
|
"y":32
|
||||||
|
},
|
||||||
|
"license":"CC-BY-SA-3.0",
|
||||||
|
"copyright":"Taken from https://github.com/tgstation/tgstation at commit 57cd1d59ca019dd0e7811ac451f295f818e573da and modified by BasedUser",
|
||||||
|
"states":[
|
||||||
|
{
|
||||||
|
"name":"heStraight",
|
||||||
|
"directions":4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"heBend",
|
||||||
|
"directions":4
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user