Files

490 lines
21 KiB
C#
Raw Permalink Normal View History

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
2021-06-19 13:25:05 +02:00
using System.Linq;
using System.Runtime.CompilerServices;
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
2021-06-19 13:25:05 +02:00
using Content.Server.Atmos.Reactions;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Reactions;
using Robust.Shared.Prototypes;
using DependencyAttribute = Robust.Shared.IoC.DependencyAttribute;
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
2021-06-19 13:25:05 +02:00
namespace Content.Server.Atmos.EntitySystems
{
public sealed partial class AtmosphereSystem
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
2021-06-19 13:25:05 +02:00
{
[Dependency] private readonly IPrototypeManager _protoMan = default!;
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
2021-06-19 13:25:05 +02:00
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;
2022-01-13 15:18:17 +01:00
/// <summary>
/// Cached array of gas specific heats.
/// </summary>
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
2021-06-19 13:25:05 +02:00
public float[] GasSpecificHeats => _gasSpecificHeats;
public string?[] GasReagents = new string[Atmospherics.TotalNumberOfGases];
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
2021-06-19 13:25:05 +02:00
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 / HeatScale;
GasReagents[i] = GasPrototypes[i].Reagent;
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
2021-06-19 13:25:05 +02:00
}
}
2022-01-13 15:18:17 +01:00
/// <summary>
/// Calculates the heat capacity for a gas mixture.
/// </summary>
2023-12-15 17:02:21 -05:00
/// <param name="mixture">The mixture whose heat capacity should be calculated</param>
/// <param name="applyScaling"> Whether the internal heat capacity scaling should be applied. This should not be
/// used outside of atmospheric related heat transfer.</param>
/// <returns></returns>
public float GetHeatCapacity(GasMixture mixture, bool applyScaling)
{
2023-12-15 17:02:21 -05:00
var scale = GetHeatCapacityCalculation(mixture.Moles, mixture.Immutable);
// By default GetHeatCapacityCalculation() has the heat-scale divisor pre-applied.
// So if we want the un-scaled heat capacity, we have to multiply by the scale.
return applyScaling ? scale : scale * HeatScale;
}
2023-12-15 17:02:21 -05:00
private float GetHeatCapacity(GasMixture mixture)
=> GetHeatCapacityCalculation(mixture.Moles, mixture.Immutable);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
Refactors the AtmosphereSystem public-facing API to allow for multiple atmos backends. (#8134) * Refactors the entirety of the AtmosphereSystem public-facing API to allow for multiple atmos backends. * actually compiles * Remove commented out code * funny bracket * Move archived moles, temperature from GasMixture to TileAtmosphere. * WIP customizable map default mixture still VERY buggy * broken mess aaaaaaaaaaaaa * Fix lattice, etc not being considered space * visualization for "IsSpace" * help * Update Content.Client/Atmos/Overlays/AtmosDebugOverlay.cs Co-authored-by: Moony <moonheart08@users.noreply.github.com> * Holy SHIT it compiles AGAIN * Fix AtmosDeviceSystem crash at shutdown * Fix immutable tiles on map blueprints not being fixed by fixgridatmos/revalidate. * Use space instead of gasmixture immutable for heat capacity calculations * Remove all LINDA-specific code from GasMixture, move it to TileAtmosphere/AtmosphereSystem instead. * Fix roundstart tiles not processing * Update Content.Server/Atmos/Commands/SetTemperatureCommand.cs Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * Update Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs Changed Files tab is so large I can't commit both suggestions at once mfw Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Co-authored-by: Moony <moonheart08@users.noreply.github.com> Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2022-07-04 16:51:34 +02:00
private float GetHeatCapacityCalculation(float[] moles, bool space)
{
// Little hack to make space gas mixtures have heat capacity, therefore allowing them to cool down rooms.
Refactors the AtmosphereSystem public-facing API to allow for multiple atmos backends. (#8134) * Refactors the entirety of the AtmosphereSystem public-facing API to allow for multiple atmos backends. * actually compiles * Remove commented out code * funny bracket * Move archived moles, temperature from GasMixture to TileAtmosphere. * WIP customizable map default mixture still VERY buggy * broken mess aaaaaaaaaaaaa * Fix lattice, etc not being considered space * visualization for "IsSpace" * help * Update Content.Client/Atmos/Overlays/AtmosDebugOverlay.cs Co-authored-by: Moony <moonheart08@users.noreply.github.com> * Holy SHIT it compiles AGAIN * Fix AtmosDeviceSystem crash at shutdown * Fix immutable tiles on map blueprints not being fixed by fixgridatmos/revalidate. * Use space instead of gasmixture immutable for heat capacity calculations * Remove all LINDA-specific code from GasMixture, move it to TileAtmosphere/AtmosphereSystem instead. * Fix roundstart tiles not processing * Update Content.Server/Atmos/Commands/SetTemperatureCommand.cs Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * Update Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs Changed Files tab is so large I can't commit both suggestions at once mfw Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Co-authored-by: Moony <moonheart08@users.noreply.github.com> Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2022-07-04 16:51:34 +02:00
if (space && MathHelper.CloseTo(NumericsHelpers.HorizontalAdd(moles), 0f))
{
return Atmospherics.SpaceHeatCapacity;
}
Span<float> tmp = stackalloc float[moles.Length];
NumericsHelpers.Multiply(moles, GasSpecificHeats, tmp);
// Adjust heat capacity by speedup, because this is primarily what
// determines how quickly gases heat up/cool.
return MathF.Max(NumericsHelpers.HorizontalAdd(tmp), Atmospherics.MinimumHeatCapacity);
}
/// <summary>
/// Return speedup factor for pumped or flow-based devices that depend on MaxTransferRate.
/// </summary>
public float PumpSpeedup()
{
return Speedup;
}
2022-01-13 15:18:17 +01:00
/// <summary>
/// Calculates the thermal energy for a gas mixture.
/// </summary>
public float GetThermalEnergy(GasMixture mixture)
{
return mixture.Temperature * GetHeatCapacity(mixture);
}
2022-01-13 15:18:17 +01:00
/// <summary>
/// Calculates the thermal energy for a gas mixture, using a cached heat capacity value.
/// </summary>
public float GetThermalEnergy(GasMixture mixture, float 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;
}
2022-01-13 15:18:17 +01:00
/// <summary>
/// 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.
/// </summary>
public void Merge(GasMixture receiver, GasMixture giver)
{
if (receiver.Immutable) return;
if (MathF.Abs(receiver.Temperature - giver.Temperature) > Atmospherics.MinimumTemperatureDeltaToConsider)
{
var receiverHeatCapacity = GetHeatCapacity(receiver);
var giverHeatCapacity = GetHeatCapacity(giver);
var combinedHeatCapacity = receiverHeatCapacity + giverHeatCapacity;
2023-12-22 17:10:33 -08:00
if (combinedHeatCapacity > Atmospherics.MinimumHeatCapacity)
{
receiver.Temperature = (GetThermalEnergy(giver, giverHeatCapacity) + GetThermalEnergy(receiver, receiverHeatCapacity)) / combinedHeatCapacity;
}
}
NumericsHelpers.Add(receiver.Moles, giver.Moles);
}
2022-06-03 22:09:51 +12:00
/// <summary>
/// Divides a source gas mixture into several recipient mixtures, scaled by their relative volumes. Does not
/// modify the source gas mixture. Used for pipe network splitting. Note that the total destination volume
/// may be larger or smaller than the source mixture.
/// </summary>
public void DivideInto(GasMixture source, List<GasMixture> receivers)
{
var totalVolume = 0f;
foreach (var receiver in receivers)
{
if (!receiver.Immutable)
totalVolume += receiver.Volume;
}
float? sourceHeatCapacity = null;
var buffer = new float[Atmospherics.AdjustedNumberOfGases];
foreach (var receiver in receivers)
{
if (receiver.Immutable)
continue;
var fraction = receiver.Volume / totalVolume;
// Set temperature, if necessary.
if (MathF.Abs(receiver.Temperature - source.Temperature) > Atmospherics.MinimumTemperatureDeltaToConsider)
{
// Often this divides a pipe net into new and completely empty pipe nets
Refactors the AtmosphereSystem public-facing API to allow for multiple atmos backends. (#8134) * Refactors the entirety of the AtmosphereSystem public-facing API to allow for multiple atmos backends. * actually compiles * Remove commented out code * funny bracket * Move archived moles, temperature from GasMixture to TileAtmosphere. * WIP customizable map default mixture still VERY buggy * broken mess aaaaaaaaaaaaa * Fix lattice, etc not being considered space * visualization for "IsSpace" * help * Update Content.Client/Atmos/Overlays/AtmosDebugOverlay.cs Co-authored-by: Moony <moonheart08@users.noreply.github.com> * Holy SHIT it compiles AGAIN * Fix AtmosDeviceSystem crash at shutdown * Fix immutable tiles on map blueprints not being fixed by fixgridatmos/revalidate. * Use space instead of gasmixture immutable for heat capacity calculations * Remove all LINDA-specific code from GasMixture, move it to TileAtmosphere/AtmosphereSystem instead. * Fix roundstart tiles not processing * Update Content.Server/Atmos/Commands/SetTemperatureCommand.cs Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * Update Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs Changed Files tab is so large I can't commit both suggestions at once mfw Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Co-authored-by: Moony <moonheart08@users.noreply.github.com> Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2022-07-04 16:51:34 +02:00
if (receiver.TotalMoles == 0)
2022-06-03 22:09:51 +12:00
receiver.Temperature = source.Temperature;
else
{
sourceHeatCapacity ??= GetHeatCapacity(source);
var receiverHeatCapacity = GetHeatCapacity(receiver);
var combinedHeatCapacity = receiverHeatCapacity + sourceHeatCapacity.Value * fraction;
2023-12-22 17:10:33 -08:00
if (combinedHeatCapacity > Atmospherics.MinimumHeatCapacity)
2022-06-03 22:09:51 +12:00
receiver.Temperature = (GetThermalEnergy(source, sourceHeatCapacity.Value * fraction) + GetThermalEnergy(receiver, receiverHeatCapacity)) / combinedHeatCapacity;
}
}
// transfer moles
NumericsHelpers.Multiply(source.Moles, fraction, buffer);
NumericsHelpers.Add(receiver.Moles, buffer);
}
}
/// <summary>
/// Releases gas from this mixture to the output mixture.
/// If the output mixture is null, then this is being released into space.
/// It can't transfer air to a mixture with higher pressure.
/// </summary>
public bool ReleaseGasTo(GasMixture mixture, GasMixture? output, float targetPressure)
{
var outputStartingPressure = output?.Pressure ?? 0;
var inputStartingPressure = mixture.Pressure;
if (outputStartingPressure >= MathF.Min(targetPressure, inputStartingPressure - 10))
// No need to pump gas if the target is already reached or input pressure is too low.
// Need at least 10 kPa difference to overcome friction in the mechanism.
return false;
if (!(mixture.TotalMoles > 0) || !(mixture.Temperature > 0)) return false;
// We calculate the necessary moles to transfer with the ideal gas law.
var pressureDelta = MathF.Min(targetPressure - outputStartingPressure, (inputStartingPressure - outputStartingPressure) / 2f);
var transferMoles = pressureDelta * (output?.Volume ?? Atmospherics.CellVolume) / (mixture.Temperature * Atmospherics.R);
// And now we transfer the gas.
var removed = mixture.Remove(transferMoles);
if(output != null)
Merge(output, removed);
return true;
}
/// <summary>
/// Pump gas from this mixture to the output mixture.
/// Amount depends on target pressure.
/// </summary>
/// <param name="mixture">The mixture to pump the gas from</param>
/// <param name="output">The mixture to pump the gas to</param>
/// <param name="targetPressure">The target pressure to reach</param>
/// <returns>Whether we could pump air to the output or not</returns>
public bool PumpGasTo(GasMixture mixture, GasMixture output, float targetPressure)
{
var outputStartingPressure = output.Pressure;
var pressureDelta = targetPressure - outputStartingPressure;
if (pressureDelta < 0.01)
// No need to pump gas, we've reached the target.
return false;
if (!(mixture.TotalMoles > 0) || !(mixture.Temperature > 0)) return false;
// We calculate the necessary moles to transfer with the ideal gas law.
var transferMoles = pressureDelta * output.Volume / (mixture.Temperature * Atmospherics.R);
// And now we transfer the gas.
var removed = mixture.Remove(transferMoles);
Merge(output, removed);
return true;
}
2022-01-13 15:18:17 +01:00
/// <summary>
/// Scrubs specified gases from a gas mixture into a <see cref="destination"/> gas mixture.
/// </summary>
public void ScrubInto(GasMixture mixture, GasMixture destination, IReadOnlyCollection<Gas> filterGases)
{
var buffer = new GasMixture(mixture.Volume){Temperature = mixture.Temperature};
foreach (var gas in filterGases)
{
buffer.AdjustMoles(gas, mixture.GetMoles(gas));
mixture.SetMoles(gas, 0f);
}
Merge(destination, buffer);
}
Pressure Relief Valve (#36708) * initial system (this math is probably WRONG) * General code cleanup and OnExamined support (holy moly this code sucks) * UICode and related events foundation TODO: - Actually write the XAML UI and the underlying system - Un-shitcode the entire thing - Actually test everything... * Working UI code TODO: Make predicted, as this certainly isn't predicted. Even though I said it was. It isn't. * Remove one TODO for unshitcoding the examine code * Add reminder yea * Make predicted (defenitely isn't) (also defenitely isn't a copypaste from pressure pump code) * It's predicted! TODO: - Give it snazzy predicted visuals! - Have a different field for pressure entry, lest it gets bulldozed every UI update. * Improve gas pressure relief valve UI TODO: Reminder to reduce amount of dirties using deltafields * Implement DirtyField prediction * Entity<T> cleanup A lot of Entity<T> conversions and lukewarm cleanup. Also got caught copy pasting code in 4K UHD but it's not like you couldn't tell. * More cleanup and comments * Remove TODO comment on bulldozing window title * """refactoring""" - Move appearance out of shared and finally fix it. Pointless to predict appearance in this instance. - More Entity<T> conversions because I like them. - Move UI creation handling over entirely to the ActivatableUI system. - Fix a hardcoded locale string (why????). * Add visuals * Revert debugging variable replacememt yea * Revert skissue * Remove unused using directives and remove TODO * Localize, cleanup, document * Fix adminlogging discrepancy * Add ability to construct, add guidebook entry * Clear up comment * Add guidebook tooltip to valve * Convert GasPressureReliefValveBoundUserInterface declaration into primary constructor * Adds more input handling and adds autofill on open * Un-deepfry input validator shitcode Genuinely what was I smoking * improve visuals logic * Refactor again - Update math to the correct implementation - Moved code that could be re-used in the future into a helper method under AtmosphereSystem.Gases.cs * I'm sorry but I hate warnings * Remove unused using directive in AtmosphereSystem.Gases.cs * Review and cleanup * Lukewarm UI glossup * Maintainer for the upstream project btw * Remove redundant state sets and messy logic * Unduplicate valve updater code * Redo UI (im sorry Slarti) * run tests * Test refactored UI messaging * Second round of UI improvements - God please find a way to improve this system. Feels bad. * Update loop implementation * Further predict UI * Clear up SetToCurrentThreshold * cleanup * Update to master + pipe layers and bug fixes want to run tests * fixes * Deploy rename pipebomb * Documentation and requested changes * Rename the method that wiggled away * Undo rounding changes * Fix comment * Rename and cleanup * Apply suggestions from code review --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2025-07-03 09:00:34 -07:00
/// <summary>
/// Calculates the dimensionless fraction of gas required to equalize pressure between two gas mixtures.
/// </summary>
/// <param name="gasMixture1">The first gas mixture involved in the pressure equalization.
/// This mixture should be the one you always expect to be the highest pressure.</param>
/// <param name="gasMixture2">The second gas mixture involved in the pressure equalization.</param>
/// <returns>A float (from 0 to 1) representing the dimensionless fraction of gas that needs to be transferred from the
/// mixture of higher pressure to the mixture of lower pressure.</returns>
/// <remarks>
/// <para>
/// This properly takes into account the effect
/// of gas merging from inlet to outlet affecting the temperature
/// (and possibly increasing the pressure) in the outlet.
/// </para>
/// <para>
/// The gas is assumed to expand freely,
/// so the temperature of the gas with the greater pressure is not changing.
/// </para>
/// </remarks>
/// <example>
/// If you want to calculate the moles required to equalize pressure between an inlet and an outlet,
/// multiply the fraction returned by the source moles.
/// </example>
public float FractionToEqualizePressure(GasMixture gasMixture1, GasMixture gasMixture2)
{
/*
Problem: the gas being merged from the inlet to the outlet could affect the
temp. of the gas and cause a pressure rise.
We want the pressure to be equalized, so we have to account for this.
For clarity, let's assume that gasMixture1 is the inlet and gasMixture2 is the outlet.
We require mechanical equilibrium, so \( P_1' = P_2' \)
Before the transfer, we have:
\( P_1 = \frac{n_1 R T_1}{V_1} \)
\( P_2 = \frac{n_2 R T_2}{V_2} \)
After removing fraction \( x \) moles from the inlet, we have:
\( P_1' = \frac{(1 - x) n_1 R T_1}{V_1} \)
The outlet will gain the same \( x n_1 \) moles of gas.
So \( n_2' = n_2 + x n_1 \)
After mixing, the outlet temperature will be changed.
Denote the new mixture temperature as \( T_2' \).
Volume is constant.
So we have:
\( P_2' = \frac{(n_2 + x n_1) R T_2}{V_2} \)
The total energy of the incoming inlet to outlet gas at \( T_1 \) plus the existing energy of the outlet gas at \( T_2 \)
will be equal to the energy of the new outlet gas at \( T_2' \).
This leads to the following derivation:
\( x n_1 C_1 T_1 + n_2 C_2 T_2 = (x n_1 C_1 + n_2 C_2) T_2' \)
Where \( C_1 \) and \( C_2 \) are the heat capacities of the inlet and outlet gases, respectively.
Solving for \( T_2' \) gives us:
\( T_2' = \frac{x n_1 C_1 T_1 + n_2 C_2 T_2}{x n_1 C_1 + n_2 C_2} \)
Once again, we require mechanical equilibrium (\( P_1' = P_2' \)),
so we can substitute \( T_2' \) into the pressure equation:
\( \frac{(1 - x) n_1 R T_1}{V_1} =
\frac{(n_2 + x n_1) R}{V_2} \cdot
\frac{x n_1 C_1 T_1 + n_2 C_2 T_2}
{x n_1 C_1 + n_2 C_2} \)
Now it's a matter of solving for \( x \).
Not going to show the full derivation here, just steps.
1. Cancel common factor \( R \).
2. Multiply both sides by \( x n_1 C_1 + n_2 C_2 \), so that everything
becomes a polynomial in terms of \( x \).
3. Expand both sides.
4. Collect like powers of \( x \).
5. After collecting, you should end up with a polynomial of the form:
\( (-n_1 C_1 T_1 (1 + \frac{V_2}{V_1})) x^2 +
(n_1 T_1 \frac{V_2}{V_1} (C_1 - C_2) - n_2 C_1 T_1 - n_1 C_2 T_2) x +
(n_1 T_1 \frac{V_2}{V_1} C_2 - n_2 C_2 T_2) = 0 \)
Divide through by \( n_1 C_1 T_1 \) and replace each ratio with a symbol for clarity:
\( k_V = \frac{V_2}{V_1} \)
\( k_n = \frac{n_2}{n_1} \)
\( k_T = \frac{T_2}{T_1} \)
\( k_C = \frac{C_2}{C_1} \)
*/
// Ensure that P_1 > P_2 so the quadratic works out.
if (gasMixture1.Pressure < gasMixture2.Pressure)
{
(gasMixture1, gasMixture2) = (gasMixture2, gasMixture1);
}
// Establish the dimensionless ratios.
var volumeRatio = gasMixture2.Volume / gasMixture1.Volume;
var molesRatio = gasMixture2.TotalMoles / gasMixture1.TotalMoles;
var temperatureRatio = gasMixture2.Temperature / gasMixture1.Temperature;
var heatCapacityRatio = GetHeatCapacity(gasMixture2) / GetHeatCapacity(gasMixture1);
// The quadratic equation is solved for the transfer fraction.
var quadraticA = 1 + volumeRatio;
var quadraticB = molesRatio - volumeRatio + heatCapacityRatio * (temperatureRatio + volumeRatio);
var quadraticC = heatCapacityRatio * (molesRatio * temperatureRatio - volumeRatio);
return (-quadraticB + MathF.Sqrt(quadraticB * quadraticB - 4 * quadraticA * quadraticC)) / (2 * quadraticA);
}
/// <summary>
/// Determines the number of moles that need to be removed from a <see cref="GasMixture"/> to reach a target pressure threshold.
/// </summary>
/// <param name="gasMixture">The gas mixture whose moles and properties will be used in the calculation.</param>
/// <param name="targetPressure">The target pressure threshold to calculate against.</param>
/// <returns>The difference in moles required to reach the target pressure threshold.</returns>
/// <remarks>The temperature of the gas is assumed to be not changing due to a free expansion.</remarks>
public static float MolesToPressureThreshold(GasMixture gasMixture, float targetPressure)
{
// Kid named PV = nRT.
return gasMixture.TotalMoles -
targetPressure * gasMixture.Volume / (Atmospherics.R * gasMixture.Temperature);
}
Refactors the AtmosphereSystem public-facing API to allow for multiple atmos backends. (#8134) * Refactors the entirety of the AtmosphereSystem public-facing API to allow for multiple atmos backends. * actually compiles * Remove commented out code * funny bracket * Move archived moles, temperature from GasMixture to TileAtmosphere. * WIP customizable map default mixture still VERY buggy * broken mess aaaaaaaaaaaaa * Fix lattice, etc not being considered space * visualization for "IsSpace" * help * Update Content.Client/Atmos/Overlays/AtmosDebugOverlay.cs Co-authored-by: Moony <moonheart08@users.noreply.github.com> * Holy SHIT it compiles AGAIN * Fix AtmosDeviceSystem crash at shutdown * Fix immutable tiles on map blueprints not being fixed by fixgridatmos/revalidate. * Use space instead of gasmixture immutable for heat capacity calculations * Remove all LINDA-specific code from GasMixture, move it to TileAtmosphere/AtmosphereSystem instead. * Fix roundstart tiles not processing * Update Content.Server/Atmos/Commands/SetTemperatureCommand.cs Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * Update Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs Changed Files tab is so large I can't commit both suggestions at once mfw Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Co-authored-by: Moony <moonheart08@users.noreply.github.com> Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2022-07-04 16:51:34 +02:00
/// <summary>
/// Checks whether a gas mixture is probably safe.
/// This only checks temperature and pressure, not gas composition.
/// </summary>
/// <param name="air">Mixture to be checked.</param>
/// <returns>Whether the mixture is probably safe.</returns>
public bool IsMixtureProbablySafe(GasMixture? air)
{
// Note that oxygen mix isn't checked, but survival boxes make that not necessary.
if (air == null)
return false;
switch (air.Pressure)
{
case <= Atmospherics.WarningLowPressure:
case >= Atmospherics.WarningHighPressure:
return false;
}
switch (air.Temperature)
{
case <= 260:
case >= 360:
return false;
}
return true;
}
/// <summary>
/// Compares two TileAtmospheres to see if they are within acceptable ranges for group processing to be enabled.
/// </summary>
public GasCompareResult CompareExchange(TileAtmosphere sample, TileAtmosphere otherSample)
{
if (sample.AirArchived == null || otherSample.AirArchived == null)
return GasCompareResult.NoExchange;
return CompareExchange(sample.AirArchived, otherSample.AirArchived);
}
Refactors the AtmosphereSystem public-facing API to allow for multiple atmos backends. (#8134) * Refactors the entirety of the AtmosphereSystem public-facing API to allow for multiple atmos backends. * actually compiles * Remove commented out code * funny bracket * Move archived moles, temperature from GasMixture to TileAtmosphere. * WIP customizable map default mixture still VERY buggy * broken mess aaaaaaaaaaaaa * Fix lattice, etc not being considered space * visualization for "IsSpace" * help * Update Content.Client/Atmos/Overlays/AtmosDebugOverlay.cs Co-authored-by: Moony <moonheart08@users.noreply.github.com> * Holy SHIT it compiles AGAIN * Fix AtmosDeviceSystem crash at shutdown * Fix immutable tiles on map blueprints not being fixed by fixgridatmos/revalidate. * Use space instead of gasmixture immutable for heat capacity calculations * Remove all LINDA-specific code from GasMixture, move it to TileAtmosphere/AtmosphereSystem instead. * Fix roundstart tiles not processing * Update Content.Server/Atmos/Commands/SetTemperatureCommand.cs Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * Update Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs Changed Files tab is so large I can't commit both suggestions at once mfw Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Co-authored-by: Moony <moonheart08@users.noreply.github.com> Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2022-07-04 16:51:34 +02:00
/// <summary>
/// Compares two gas mixtures to see if they are within acceptable ranges for group processing to be enabled.
/// </summary>
public GasCompareResult CompareExchange(GasMixture sample, GasMixture otherSample)
{
var moles = 0f;
for(var i = 0; i < Atmospherics.TotalNumberOfGases; i++)
{
var gasMoles = sample.Moles[i];
var delta = MathF.Abs(gasMoles - otherSample.Moles[i]);
if (delta > Atmospherics.MinimumMolesDeltaToMove && (delta > gasMoles * Atmospherics.MinimumAirRatioToMove))
return (GasCompareResult)i; // We can move gases!
moles += gasMoles;
}
if (moles > Atmospherics.MinimumMolesDeltaToMove)
{
var tempDelta = MathF.Abs(sample.Temperature - otherSample.Temperature);
if (tempDelta > Atmospherics.MinimumTemperatureDeltaToSuspend)
return GasCompareResult.TemperatureExchange; // There can be temperature exchange.
}
// No exchange at all!
return GasCompareResult.NoExchange;
}
2022-01-13 15:18:17 +01:00
/// <summary>
/// Performs reactions for a given gas mixture on an optional holder.
/// </summary>
public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder)
{
var reaction = ReactionResult.NoReaction;
var temperature = mixture.Temperature;
var energy = GetThermalEnergy(mixture);
foreach (var prototype in GasReactions)
{
if (energy < prototype.MinimumEnergyRequirement ||
temperature < prototype.MinimumTemperatureRequirement ||
temperature > prototype.MaximumTemperatureRequirement)
continue;
var doReaction = true;
for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++)
{
var req = prototype.MinimumRequirements[i];
2023-12-15 17:02:21 -05:00
if (!(mixture.GetMoles(i) < req))
continue;
doReaction = false;
break;
}
if (!doReaction)
continue;
2023-12-15 17:02:21 -05:00
reaction = prototype.React(mixture, holder, this, HeatScale);
if(reaction.HasFlag(ReactionResult.StopReactions))
break;
}
return reaction;
}
Refactors the AtmosphereSystem public-facing API to allow for multiple atmos backends. (#8134) * Refactors the entirety of the AtmosphereSystem public-facing API to allow for multiple atmos backends. * actually compiles * Remove commented out code * funny bracket * Move archived moles, temperature from GasMixture to TileAtmosphere. * WIP customizable map default mixture still VERY buggy * broken mess aaaaaaaaaaaaa * Fix lattice, etc not being considered space * visualization for "IsSpace" * help * Update Content.Client/Atmos/Overlays/AtmosDebugOverlay.cs Co-authored-by: Moony <moonheart08@users.noreply.github.com> * Holy SHIT it compiles AGAIN * Fix AtmosDeviceSystem crash at shutdown * Fix immutable tiles on map blueprints not being fixed by fixgridatmos/revalidate. * Use space instead of gasmixture immutable for heat capacity calculations * Remove all LINDA-specific code from GasMixture, move it to TileAtmosphere/AtmosphereSystem instead. * Fix roundstart tiles not processing * Update Content.Server/Atmos/Commands/SetTemperatureCommand.cs Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * Update Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs Changed Files tab is so large I can't commit both suggestions at once mfw Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Co-authored-by: Moony <moonheart08@users.noreply.github.com> Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2022-07-04 16:51:34 +02:00
public enum GasCompareResult
{
NoExchange = -2,
TemperatureExchange = -1,
}
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
2021-06-19 13:25:05 +02:00
}
}