ECS Atmos Part 2: Moves a lot of Gas Mixture methods to AtmosphereSystem. (#4218)
This commit is contained in:
committed by
GitHub
parent
e16c23a747
commit
263c9ef974
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.Atmos.Reactions;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Shared.Atmos;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
@@ -30,5 +31,273 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
_gasSpecificHeats[i] = GasPrototypes[i].SpecificHeat;
|
||||
}
|
||||
}
|
||||
|
||||
public float GetHeatCapacity(GasMixture mixture)
|
||||
{
|
||||
Span<float> tmp = stackalloc float[mixture.Moles.Length];
|
||||
NumericsHelpers.Multiply(mixture.Moles, GasSpecificHeats, tmp);
|
||||
return MathF.Max(NumericsHelpers.HorizontalAdd(tmp), Atmospherics.MinimumHeatCapacity);
|
||||
}
|
||||
|
||||
public float GetHeatCapacityArchived(GasMixture mixture)
|
||||
{
|
||||
Span<float> tmp = stackalloc float[mixture.Moles.Length];
|
||||
NumericsHelpers.Multiply(mixture.MolesArchived, GasSpecificHeats, tmp);
|
||||
return MathF.Max(NumericsHelpers.HorizontalAdd(tmp), Atmospherics.MinimumHeatCapacity);
|
||||
}
|
||||
|
||||
public float GetThermalEnergy(GasMixture mixture)
|
||||
{
|
||||
return mixture.Temperature * GetHeatCapacity(mixture);
|
||||
}
|
||||
|
||||
public void Merge(GasMixture receiver, GasMixture giver)
|
||||
{
|
||||
if (receiver.Immutable) return;
|
||||
|
||||
if (MathF.Abs(receiver.Temperature - giver.Temperature) > Atmospherics.MinimumTemperatureDeltaToConsider)
|
||||
{
|
||||
var combinedHeatCapacity = GetHeatCapacity(receiver) + GetHeatCapacity(giver);
|
||||
if (combinedHeatCapacity > 0f)
|
||||
{
|
||||
receiver.Temperature = (GetThermalEnergy(giver) + GetThermalEnergy(receiver)) / combinedHeatCapacity;
|
||||
}
|
||||
}
|
||||
|
||||
NumericsHelpers.Add(receiver.Moles, giver.Moles);
|
||||
}
|
||||
|
||||
public float Share(GasMixture receiver, GasMixture sharer, int atmosAdjacentTurfs)
|
||||
{
|
||||
var temperatureDelta = receiver.TemperatureArchived - sharer.TemperatureArchived;
|
||||
var absTemperatureDelta = Math.Abs(temperatureDelta);
|
||||
var oldHeatCapacity = 0f;
|
||||
var oldSharerHeatCapacity = 0f;
|
||||
|
||||
if (absTemperatureDelta > Atmospherics.MinimumTemperatureDeltaToConsider)
|
||||
{
|
||||
oldHeatCapacity = GetHeatCapacity(receiver);
|
||||
oldSharerHeatCapacity = GetHeatCapacity(sharer);
|
||||
}
|
||||
|
||||
var heatCapacityToSharer = 0f;
|
||||
var heatCapacitySharerToThis = 0f;
|
||||
var movedMoles = 0f;
|
||||
var absMovedMoles = 0f;
|
||||
|
||||
for(var i = 0; i < Atmospherics.TotalNumberOfGases; i++)
|
||||
{
|
||||
var thisValue = receiver.Moles[i];
|
||||
var sharerValue = sharer.Moles[i];
|
||||
var delta = (thisValue - sharerValue) / (atmosAdjacentTurfs + 1);
|
||||
if (!(MathF.Abs(delta) >= Atmospherics.GasMinMoles)) continue;
|
||||
if (absTemperatureDelta > Atmospherics.MinimumTemperatureDeltaToConsider)
|
||||
{
|
||||
var gasHeatCapacity = delta * GasSpecificHeats[i];
|
||||
if (delta > 0)
|
||||
{
|
||||
heatCapacityToSharer += gasHeatCapacity;
|
||||
}
|
||||
else
|
||||
{
|
||||
heatCapacitySharerToThis -= gasHeatCapacity;
|
||||
}
|
||||
}
|
||||
|
||||
if (!receiver.Immutable) receiver.Moles[i] -= delta;
|
||||
if (!sharer.Immutable) sharer.Moles[i] += delta;
|
||||
movedMoles += delta;
|
||||
absMovedMoles += MathF.Abs(delta);
|
||||
}
|
||||
|
||||
receiver.LastShare = absMovedMoles;
|
||||
|
||||
if (absTemperatureDelta > Atmospherics.MinimumTemperatureDeltaToConsider)
|
||||
{
|
||||
var newHeatCapacity = oldHeatCapacity + heatCapacitySharerToThis - heatCapacityToSharer;
|
||||
var newSharerHeatCapacity = oldSharerHeatCapacity + heatCapacityToSharer - heatCapacitySharerToThis;
|
||||
|
||||
// Transfer of thermal energy (via changed heat capacity) between self and sharer.
|
||||
if (!receiver.Immutable && newHeatCapacity > Atmospherics.MinimumHeatCapacity)
|
||||
{
|
||||
receiver.Temperature = ((oldHeatCapacity * receiver.Temperature) - (heatCapacityToSharer * receiver.TemperatureArchived) + (heatCapacitySharerToThis * sharer.TemperatureArchived)) / newHeatCapacity;
|
||||
}
|
||||
|
||||
if (!sharer.Immutable && newSharerHeatCapacity > Atmospherics.MinimumHeatCapacity)
|
||||
{
|
||||
sharer.Temperature = ((oldSharerHeatCapacity * sharer.Temperature) - (heatCapacitySharerToThis * sharer.TemperatureArchived) + (heatCapacityToSharer*receiver.TemperatureArchived)) / newSharerHeatCapacity;
|
||||
}
|
||||
|
||||
// Thermal energy of the system (self and sharer) is unchanged.
|
||||
|
||||
if (MathF.Abs(oldSharerHeatCapacity) > Atmospherics.MinimumHeatCapacity)
|
||||
{
|
||||
if (MathF.Abs(newSharerHeatCapacity / oldSharerHeatCapacity - 1) < 0.1)
|
||||
{
|
||||
TemperatureShare(receiver, sharer, Atmospherics.OpenHeatTransferCoefficient);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(temperatureDelta > Atmospherics.MinimumTemperatureToMove) &&
|
||||
!(MathF.Abs(movedMoles) > Atmospherics.MinimumMolesDeltaToMove)) return 0f;
|
||||
var moles = receiver.TotalMoles;
|
||||
var theirMoles = sharer.TotalMoles;
|
||||
|
||||
return (receiver.TemperatureArchived * (moles + movedMoles)) - (sharer.TemperatureArchived * (theirMoles - movedMoles)) * Atmospherics.R / receiver.Volume;
|
||||
|
||||
}
|
||||
|
||||
public float TemperatureShare(GasMixture receiver, GasMixture sharer, float conductionCoefficient)
|
||||
{
|
||||
var temperatureDelta = receiver.TemperatureArchived - sharer.TemperatureArchived;
|
||||
if (MathF.Abs(temperatureDelta) > Atmospherics.MinimumTemperatureDeltaToConsider)
|
||||
{
|
||||
var heatCapacity = GetHeatCapacityArchived(receiver);
|
||||
var sharerHeatCapacity = GetHeatCapacityArchived(sharer);
|
||||
|
||||
if (sharerHeatCapacity > Atmospherics.MinimumHeatCapacity && heatCapacity > Atmospherics.MinimumHeatCapacity)
|
||||
{
|
||||
var heat = conductionCoefficient * temperatureDelta * (heatCapacity * sharerHeatCapacity / (heatCapacity + sharerHeatCapacity));
|
||||
|
||||
if (!receiver.Immutable)
|
||||
receiver.Temperature = MathF.Abs(MathF.Max(receiver.Temperature - heat / heatCapacity, Atmospherics.TCMB));
|
||||
|
||||
if (!sharer.Immutable)
|
||||
sharer.Temperature = MathF.Abs(MathF.Max(sharer.Temperature + heat / sharerHeatCapacity, Atmospherics.TCMB));
|
||||
}
|
||||
}
|
||||
|
||||
return sharer.Temperature;
|
||||
}
|
||||
|
||||
public float TemperatureShare(GasMixture receiver, float conductionCoefficient, float sharerTemperature, float sharerHeatCapacity)
|
||||
{
|
||||
var temperatureDelta = receiver.TemperatureArchived - sharerTemperature;
|
||||
if (MathF.Abs(temperatureDelta) > Atmospherics.MinimumTemperatureDeltaToConsider)
|
||||
{
|
||||
var heatCapacity = GetHeatCapacityArchived(receiver);
|
||||
|
||||
if (sharerHeatCapacity > Atmospherics.MinimumHeatCapacity && heatCapacity > Atmospherics.MinimumHeatCapacity)
|
||||
{
|
||||
var heat = conductionCoefficient * temperatureDelta * (heatCapacity * sharerHeatCapacity / (heatCapacity + sharerHeatCapacity));
|
||||
|
||||
if (!receiver.Immutable)
|
||||
receiver.Temperature = MathF.Abs(MathF.Max(receiver.Temperature - heat / heatCapacity, Atmospherics.TCMB));
|
||||
|
||||
sharerTemperature = MathF.Abs(MathF.Max(sharerTemperature + heat / sharerHeatCapacity, Atmospherics.TCMB));
|
||||
}
|
||||
}
|
||||
|
||||
return sharerTemperature;
|
||||
}
|
||||
|
||||
/// <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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 < prototype.MinimumRequirements.Length; i++)
|
||||
{
|
||||
if(i > Atmospherics.TotalNumberOfGases)
|
||||
throw new IndexOutOfRangeException("Reaction Gas Minimum Requirements Array Prototype exceeds total number of gases!");
|
||||
|
||||
var req = prototype.MinimumRequirements[i];
|
||||
|
||||
if (!(mixture.GetMoles(i) < req)) continue;
|
||||
doReaction = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!doReaction)
|
||||
continue;
|
||||
|
||||
reaction = prototype.React(mixture, holder, this);
|
||||
if(reaction.HasFlag(ReactionResult.StopReactions))
|
||||
break;
|
||||
}
|
||||
|
||||
return reaction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
var number = 0;
|
||||
while (atmosphere.CurrentRunTiles.TryDequeue(out var tile))
|
||||
{
|
||||
tile.EqualizePressureInZone(atmosphere.UpdateCounter);
|
||||
tile.EqualizePressureInZone(this, atmosphere.UpdateCounter);
|
||||
|
||||
if (number++ < LagCheckIterations) continue;
|
||||
number = 0;
|
||||
@@ -55,7 +55,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
var number = 0;
|
||||
while (atmosphere.CurrentRunTiles.TryDequeue(out var tile))
|
||||
{
|
||||
tile.ProcessCell(atmosphere.UpdateCounter, SpaceWind);
|
||||
tile.ProcessCell(this, atmosphere.UpdateCounter, SpaceWind);
|
||||
|
||||
if (number++ < LagCheckIterations) continue;
|
||||
number = 0;
|
||||
@@ -81,7 +81,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
excitedGroup.DismantleCooldown++;
|
||||
|
||||
if(excitedGroup.BreakdownCooldown > Atmospherics.ExcitedGroupBreakdownCycles)
|
||||
excitedGroup.SelfBreakdown(ExcitedGroupsSpaceIsAllConsuming);
|
||||
excitedGroup.SelfBreakdown(this, ExcitedGroupsSpaceIsAllConsuming);
|
||||
|
||||
else if(excitedGroup.DismantleCooldown > Atmospherics.ExcitedGroupsDismantleCycles)
|
||||
excitedGroup.Dismantle();
|
||||
@@ -153,7 +153,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
var number = 0;
|
||||
while (atmosphere.CurrentRunTiles.TryDequeue(out var superconductivity))
|
||||
{
|
||||
superconductivity.Superconduct();
|
||||
superconductivity.Superconduct(this);
|
||||
|
||||
if (number++ < LagCheckIterations) continue;
|
||||
number = 0;
|
||||
|
||||
@@ -159,7 +159,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
{
|
||||
var tile = exposed.Owner.Transform.Coordinates.GetTileAtmosphere();
|
||||
if (tile == null) continue;
|
||||
exposed.Update(tile, _exposedTimer);
|
||||
exposed.Update(tile, _exposedTimer, this);
|
||||
}
|
||||
|
||||
_exposedTimer -= ExposedUpdateDelay;
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
using Content.Server.Atmos.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.Atmos.EntitySystems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class GasTankSystem : EntitySystem
|
||||
{
|
||||
private float _timer = 0f;
|
||||
private const float Interval = 0.5f;
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
_timer += frameTime;
|
||||
|
||||
if (_timer < Interval) return;
|
||||
_timer = 0f;
|
||||
|
||||
foreach (var gasTank in EntityManager.ComponentManager.EntityQuery<GasTankComponent>(true))
|
||||
{
|
||||
gasTank.Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,7 +167,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
var overlay = _atmosphereSystem.GetOverlay(i);
|
||||
if (overlay == null) continue;
|
||||
|
||||
var moles = tile.Air.Gases[i];
|
||||
var moles = tile.Air.Moles[i];
|
||||
|
||||
if (moles < gas.GasMolesVisible) continue;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user