Use archived gas mixture in gas exchange comparison (#32088)
The comparison for doing gas exchange used current and not archived moles. This could lead to update order-dependent gas spreading effects. To fix this, convert TileAtmosphere's MolesArchived and TemperatureArchived to a AirArchived, and use that in the comparison method. --------- Co-authored-by: PraxisMapper <praxismapper@gmail.com> Co-authored-by: Kevin Zheng <kevinz5000@gmail.com>
This commit is contained in:
@@ -281,6 +281,17 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
return true;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Compares two gas mixtures to see if they are within acceptable ranges for group processing to be enabled.
|
/// Compares two gas mixtures to see if they are within acceptable ranges for group processing to be enabled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -270,7 +270,7 @@ public sealed partial class AtmosphereSystem
|
|||||||
{
|
{
|
||||||
DebugTools.AssertNotNull(tile.Air);
|
DebugTools.AssertNotNull(tile.Air);
|
||||||
DebugTools.Assert(tile.Air?.Immutable == false);
|
DebugTools.Assert(tile.Air?.Immutable == false);
|
||||||
Array.Clear(tile.MolesArchived);
|
tile.AirArchived = null;
|
||||||
tile.ArchivedCycle = 0;
|
tile.ArchivedCycle = 0;
|
||||||
|
|
||||||
var count = 0;
|
var count = 0;
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
}
|
}
|
||||||
|
|
||||||
shouldShareAir = true;
|
shouldShareAir = true;
|
||||||
} else if (CompareExchange(tile.Air, enemyTile.Air) != GasCompareResult.NoExchange)
|
} else if (CompareExchange(tile, enemyTile) != GasCompareResult.NoExchange)
|
||||||
{
|
{
|
||||||
AddActiveTile(gridAtmosphere, enemyTile);
|
AddActiveTile(gridAtmosphere, enemyTile);
|
||||||
if (ExcitedGroups)
|
if (ExcitedGroups)
|
||||||
@@ -117,9 +117,8 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
private void Archive(TileAtmosphere tile, int fireCount)
|
private void Archive(TileAtmosphere tile, int fireCount)
|
||||||
{
|
{
|
||||||
if (tile.Air != null)
|
if (tile.Air != null)
|
||||||
tile.Air.Moles.AsSpan().CopyTo(tile.MolesArchived.AsSpan());
|
tile.AirArchived = new GasMixture(tile.Air);
|
||||||
|
|
||||||
tile.TemperatureArchived = tile.Temperature;
|
|
||||||
tile.ArchivedCycle = fireCount;
|
tile.ArchivedCycle = fireCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,10 +183,10 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public float GetHeatCapacityArchived(TileAtmosphere tile)
|
public float GetHeatCapacityArchived(TileAtmosphere tile)
|
||||||
{
|
{
|
||||||
if (tile.Air == null)
|
if (tile.AirArchived == null)
|
||||||
return tile.HeatCapacity;
|
return tile.HeatCapacity;
|
||||||
|
|
||||||
return GetHeatCapacityCalculation(tile.MolesArchived!, tile.Space);
|
return GetHeatCapacity(tile.AirArchived);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -195,10 +194,11 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public float Share(TileAtmosphere tileReceiver, TileAtmosphere tileSharer, int atmosAdjacentTurfs)
|
public float Share(TileAtmosphere tileReceiver, TileAtmosphere tileSharer, int atmosAdjacentTurfs)
|
||||||
{
|
{
|
||||||
if (tileReceiver.Air is not {} receiver || tileSharer.Air is not {} sharer)
|
if (tileReceiver.Air is not {} receiver || tileSharer.Air is not {} sharer ||
|
||||||
|
tileReceiver.AirArchived == null || tileSharer.AirArchived == null)
|
||||||
return 0f;
|
return 0f;
|
||||||
|
|
||||||
var temperatureDelta = tileReceiver.TemperatureArchived - tileSharer.TemperatureArchived;
|
var temperatureDelta = tileReceiver.AirArchived.Temperature - tileSharer.AirArchived.Temperature;
|
||||||
var absTemperatureDelta = Math.Abs(temperatureDelta);
|
var absTemperatureDelta = Math.Abs(temperatureDelta);
|
||||||
var oldHeatCapacity = 0f;
|
var oldHeatCapacity = 0f;
|
||||||
var oldSharerHeatCapacity = 0f;
|
var oldSharerHeatCapacity = 0f;
|
||||||
@@ -249,12 +249,12 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
// Transfer of thermal energy (via changed heat capacity) between self and sharer.
|
// Transfer of thermal energy (via changed heat capacity) between self and sharer.
|
||||||
if (!receiver.Immutable && newHeatCapacity > Atmospherics.MinimumHeatCapacity)
|
if (!receiver.Immutable && newHeatCapacity > Atmospherics.MinimumHeatCapacity)
|
||||||
{
|
{
|
||||||
receiver.Temperature = ((oldHeatCapacity * receiver.Temperature) - (heatCapacityToSharer * tileReceiver.TemperatureArchived) + (heatCapacitySharerToThis * tileSharer.TemperatureArchived)) / newHeatCapacity;
|
receiver.Temperature = ((oldHeatCapacity * receiver.Temperature) - (heatCapacityToSharer * tileReceiver.AirArchived.Temperature) + (heatCapacitySharerToThis * tileSharer.AirArchived.Temperature)) / newHeatCapacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sharer.Immutable && newSharerHeatCapacity > Atmospherics.MinimumHeatCapacity)
|
if (!sharer.Immutable && newSharerHeatCapacity > Atmospherics.MinimumHeatCapacity)
|
||||||
{
|
{
|
||||||
sharer.Temperature = ((oldSharerHeatCapacity * sharer.Temperature) - (heatCapacitySharerToThis * tileSharer.TemperatureArchived) + (heatCapacityToSharer * tileReceiver.TemperatureArchived)) / newSharerHeatCapacity;
|
sharer.Temperature = ((oldSharerHeatCapacity * sharer.Temperature) - (heatCapacitySharerToThis * tileSharer.AirArchived.Temperature) + (heatCapacityToSharer * tileReceiver.AirArchived.Temperature)) / newSharerHeatCapacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Thermal energy of the system (self and sharer) is unchanged.
|
// Thermal energy of the system (self and sharer) is unchanged.
|
||||||
@@ -273,7 +273,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
var moles = receiver.TotalMoles;
|
var moles = receiver.TotalMoles;
|
||||||
var theirMoles = sharer.TotalMoles;
|
var theirMoles = sharer.TotalMoles;
|
||||||
|
|
||||||
return (tileReceiver.TemperatureArchived * (moles + movedMoles)) - (tileSharer.TemperatureArchived * (theirMoles - movedMoles)) * Atmospherics.R / receiver.Volume;
|
return (tileReceiver.AirArchived.Temperature * (moles + movedMoles)) - (tileSharer.AirArchived.Temperature * (theirMoles - movedMoles)) * Atmospherics.R / receiver.Volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -281,10 +281,11 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public float TemperatureShare(TileAtmosphere tileReceiver, TileAtmosphere tileSharer, float conductionCoefficient)
|
public float TemperatureShare(TileAtmosphere tileReceiver, TileAtmosphere tileSharer, float conductionCoefficient)
|
||||||
{
|
{
|
||||||
if (tileReceiver.Air is not { } receiver || tileSharer.Air is not { } sharer)
|
if (tileReceiver.Air is not { } receiver || tileSharer.Air is not { } sharer ||
|
||||||
|
tileReceiver.AirArchived == null || tileSharer.AirArchived == null)
|
||||||
return 0f;
|
return 0f;
|
||||||
|
|
||||||
var temperatureDelta = tileReceiver.TemperatureArchived - tileSharer.TemperatureArchived;
|
var temperatureDelta = tileReceiver.AirArchived.Temperature - tileSharer.AirArchived.Temperature;
|
||||||
if (MathF.Abs(temperatureDelta) > Atmospherics.MinimumTemperatureDeltaToConsider)
|
if (MathF.Abs(temperatureDelta) > Atmospherics.MinimumTemperatureDeltaToConsider)
|
||||||
{
|
{
|
||||||
var heatCapacity = GetHeatCapacityArchived(tileReceiver);
|
var heatCapacity = GetHeatCapacityArchived(tileReceiver);
|
||||||
@@ -310,10 +311,10 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public float TemperatureShare(TileAtmosphere tileReceiver, float conductionCoefficient, float sharerTemperature, float sharerHeatCapacity)
|
public float TemperatureShare(TileAtmosphere tileReceiver, float conductionCoefficient, float sharerTemperature, float sharerHeatCapacity)
|
||||||
{
|
{
|
||||||
if (tileReceiver.Air is not {} receiver)
|
if (tileReceiver.Air is not {} receiver || tileReceiver.AirArchived == null)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
var temperatureDelta = tileReceiver.TemperatureArchived - sharerTemperature;
|
var temperatureDelta = tileReceiver.AirArchived.Temperature - sharerTemperature;
|
||||||
if (MathF.Abs(temperatureDelta) > Atmospherics.MinimumTemperatureDeltaToConsider)
|
if (MathF.Abs(temperatureDelta) > Atmospherics.MinimumTemperatureDeltaToConsider)
|
||||||
{
|
{
|
||||||
var heatCapacity = GetHeatCapacityArchived(tileReceiver);
|
var heatCapacity = GetHeatCapacityArchived(tileReceiver);
|
||||||
|
|||||||
@@ -355,7 +355,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
DebugTools.Assert(otherTile2.AdjacentBits.IsFlagSet(direction.GetOpposite()));
|
DebugTools.Assert(otherTile2.AdjacentBits.IsFlagSet(direction.GetOpposite()));
|
||||||
if (otherTile2.Air != null && CompareExchange(otherTile2.Air, tile.Air) == GasCompareResult.NoExchange)
|
if (otherTile2.Air != null && CompareExchange(otherTile2, tile) == GasCompareResult.NoExchange)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
AddActiveTile(gridAtmosphere, otherTile2);
|
AddActiveTile(gridAtmosphere, otherTile2);
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
tile.MapAtmosphere = false;
|
tile.MapAtmosphere = false;
|
||||||
atmos.MapTiles.Remove(tile);
|
atmos.MapTiles.Remove(tile);
|
||||||
tile.Air = null;
|
tile.Air = null;
|
||||||
Array.Clear(tile.MolesArchived);
|
tile.AirArchived = null;
|
||||||
tile.ArchivedCycle = 0;
|
tile.ArchivedCycle = 0;
|
||||||
tile.LastShare = 0f;
|
tile.LastShare = 0f;
|
||||||
tile.Space = false;
|
tile.Space = false;
|
||||||
@@ -261,7 +261,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
tile.Air = null;
|
tile.Air = null;
|
||||||
Array.Clear(tile.MolesArchived);
|
tile.AirArchived = null;
|
||||||
tile.ArchivedCycle = 0;
|
tile.ArchivedCycle = 0;
|
||||||
tile.LastShare = 0f;
|
tile.LastShare = 0f;
|
||||||
tile.Hotspot = new Hotspot();
|
tile.Hotspot = new Hotspot();
|
||||||
|
|||||||
@@ -131,7 +131,10 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
|
|
||||||
private void TemperatureShareMutualSolid(TileAtmosphere tile, TileAtmosphere other, float conductionCoefficient)
|
private void TemperatureShareMutualSolid(TileAtmosphere tile, TileAtmosphere other, float conductionCoefficient)
|
||||||
{
|
{
|
||||||
var deltaTemperature = (tile.TemperatureArchived - other.TemperatureArchived);
|
if (tile.AirArchived == null || other.AirArchived == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var deltaTemperature = (tile.AirArchived.Temperature - other.AirArchived.Temperature);
|
||||||
if (MathF.Abs(deltaTemperature) > Atmospherics.MinimumTemperatureDeltaToConsider
|
if (MathF.Abs(deltaTemperature) > Atmospherics.MinimumTemperatureDeltaToConsider
|
||||||
&& tile.HeatCapacity != 0f && other.HeatCapacity != 0f)
|
&& tile.HeatCapacity != 0f && other.HeatCapacity != 0f)
|
||||||
{
|
{
|
||||||
@@ -145,11 +148,14 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
|
|
||||||
public void RadiateToSpace(TileAtmosphere tile)
|
public void RadiateToSpace(TileAtmosphere tile)
|
||||||
{
|
{
|
||||||
|
if (tile.AirArchived == null)
|
||||||
|
return;
|
||||||
|
|
||||||
// Considering 0ºC as the break even point for radiation in and out.
|
// Considering 0ºC as the break even point for radiation in and out.
|
||||||
if (tile.Temperature > Atmospherics.T0C)
|
if (tile.Temperature > Atmospherics.T0C)
|
||||||
{
|
{
|
||||||
// Hardcoded space temperature.
|
// Hardcoded space temperature.
|
||||||
var deltaTemperature = (tile.TemperatureArchived - Atmospherics.TCMB);
|
var deltaTemperature = (tile.AirArchived.Temperature - Atmospherics.TCMB);
|
||||||
if ((tile.HeatCapacity > 0) && (MathF.Abs(deltaTemperature) > Atmospherics.MinimumTemperatureDeltaToConsider))
|
if ((tile.HeatCapacity > 0) && (MathF.Abs(deltaTemperature) > Atmospherics.MinimumTemperatureDeltaToConsider))
|
||||||
{
|
{
|
||||||
var heat = tile.ThermalConductivity * deltaTemperature * (tile.HeatCapacity *
|
var heat = tile.ThermalConductivity * deltaTemperature * (tile.HeatCapacity *
|
||||||
|
|||||||
@@ -22,9 +22,6 @@ namespace Content.Server.Atmos
|
|||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public float Temperature { get; set; } = Atmospherics.T20C;
|
public float Temperature { get; set; } = Atmospherics.T20C;
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
public float TemperatureArchived { get; set; } = Atmospherics.T20C;
|
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public TileAtmosphere? PressureSpecificTarget { get; set; }
|
public TileAtmosphere? PressureSpecificTarget { get; set; }
|
||||||
|
|
||||||
@@ -93,12 +90,16 @@ namespace Content.Server.Atmos
|
|||||||
[Access(typeof(AtmosphereSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends
|
[Access(typeof(AtmosphereSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends
|
||||||
public GasMixture? Air { get; set; }
|
public GasMixture? Air { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Like Air, but a copy stored each atmos tick before tile processing takes place. This lets us update Air
|
||||||
|
/// in-place without affecting the results based on update order.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
public GasMixture? AirArchived;
|
||||||
|
|
||||||
[DataField("lastShare")]
|
[DataField("lastShare")]
|
||||||
public float LastShare;
|
public float LastShare;
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
public readonly float[] MolesArchived = new float[Atmospherics.AdjustedNumberOfGases];
|
|
||||||
|
|
||||||
GasMixture IGasMixtureHolder.Air
|
GasMixture IGasMixtureHolder.Air
|
||||||
{
|
{
|
||||||
get => Air ?? new GasMixture(Atmospherics.CellVolume){ Temperature = Temperature };
|
get => Air ?? new GasMixture(Atmospherics.CellVolume){ Temperature = Temperature };
|
||||||
@@ -139,6 +140,7 @@ namespace Content.Server.Atmos
|
|||||||
GridIndex = gridIndex;
|
GridIndex = gridIndex;
|
||||||
GridIndices = gridIndices;
|
GridIndices = gridIndices;
|
||||||
Air = mixture;
|
Air = mixture;
|
||||||
|
AirArchived = Air != null ? Air.Clone() : null;
|
||||||
Space = space;
|
Space = space;
|
||||||
|
|
||||||
if(immutable)
|
if(immutable)
|
||||||
@@ -153,7 +155,7 @@ namespace Content.Server.Atmos
|
|||||||
NoGridTile = other.NoGridTile;
|
NoGridTile = other.NoGridTile;
|
||||||
MapAtmosphere = other.MapAtmosphere;
|
MapAtmosphere = other.MapAtmosphere;
|
||||||
Air = other.Air?.Clone();
|
Air = other.Air?.Clone();
|
||||||
Array.Copy(other.MolesArchived, MolesArchived, MolesArchived.Length);
|
AirArchived = Air != null ? Air.Clone() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TileAtmosphere()
|
public TileAtmosphere()
|
||||||
|
|||||||
Reference in New Issue
Block a user