]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Use archived gas mixture in gas exchange comparison (#32088)
authordrakewill-CRL <46307022+drakewill-CRL@users.noreply.github.com>
Mon, 30 Sep 2024 05:14:07 +0000 (01:14 -0400)
committerGitHub <noreply@github.com>
Mon, 30 Sep 2024 05:14:07 +0000 (22:14 -0700)
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>
Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs
Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs
Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs
Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs
Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs
Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs
Content.Server/Atmos/TileAtmosphere.cs

index 70c4639e481e75064bbd0fb013ab83b004b0b0bc..f38ec3fef60b2b6247837955459d0b38ed4a79d3 100644 (file)
@@ -281,6 +281,17 @@ namespace Content.Server.Atmos.EntitySystems
             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>
         ///     Compares two gas mixtures to see if they are within acceptable ranges for group processing to be enabled.
         /// </summary>
index 3983234dea6e99fb20a6bbeb113d820cf8f3fb82..b11eb5dc3e670ae4adbdb8d471275b1ff3f32d0b 100644 (file)
@@ -270,7 +270,7 @@ public sealed partial class AtmosphereSystem
     {
         DebugTools.AssertNotNull(tile.Air);
         DebugTools.Assert(tile.Air?.Immutable == false);
-        Array.Clear(tile.MolesArchived);
+        tile.AirArchived = null;
         tile.ArchivedCycle = 0;
 
         var count = 0;
index fb2375899d9dbb0dda25b03b4c1cf7ad154f4dd5..55b38924c0ee57e33603ed2a04dd2fc0408e350f 100644 (file)
@@ -54,7 +54,7 @@ namespace Content.Server.Atmos.EntitySystems
                     }
 
                     shouldShareAir = true;
-                } else if (CompareExchange(tile.Air, enemyTile.Air) != GasCompareResult.NoExchange)
+                } else if (CompareExchange(tile, enemyTile) != GasCompareResult.NoExchange)
                 {
                     AddActiveTile(gridAtmosphere, enemyTile);
                     if (ExcitedGroups)
@@ -117,9 +117,8 @@ namespace Content.Server.Atmos.EntitySystems
         private void Archive(TileAtmosphere tile, int fireCount)
         {
             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;
         }
 
@@ -184,10 +183,10 @@ namespace Content.Server.Atmos.EntitySystems
         /// </summary>
         public float GetHeatCapacityArchived(TileAtmosphere tile)
         {
-            if (tile.Air == null)
+            if (tile.AirArchived == null)
                 return tile.HeatCapacity;
 
-            return GetHeatCapacityCalculation(tile.MolesArchived!, tile.Space);
+            return GetHeatCapacity(tile.AirArchived);
         }
 
         /// <summary>
@@ -195,10 +194,11 @@ namespace Content.Server.Atmos.EntitySystems
         /// </summary>
         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;
 
-            var temperatureDelta = tileReceiver.TemperatureArchived - tileSharer.TemperatureArchived;
+            var temperatureDelta = tileReceiver.AirArchived.Temperature - tileSharer.AirArchived.Temperature;
             var absTemperatureDelta = Math.Abs(temperatureDelta);
             var oldHeatCapacity = 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.
                 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)
                 {
-                    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.
@@ -273,7 +273,7 @@ namespace Content.Server.Atmos.EntitySystems
             var moles = receiver.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>
@@ -281,10 +281,11 @@ namespace Content.Server.Atmos.EntitySystems
         /// </summary>
         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;
 
-            var temperatureDelta = tileReceiver.TemperatureArchived - tileSharer.TemperatureArchived;
+            var temperatureDelta = tileReceiver.AirArchived.Temperature - tileSharer.AirArchived.Temperature;
             if (MathF.Abs(temperatureDelta) > Atmospherics.MinimumTemperatureDeltaToConsider)
             {
                 var heatCapacity = GetHeatCapacityArchived(tileReceiver);
@@ -310,10 +311,10 @@ namespace Content.Server.Atmos.EntitySystems
         /// </summary>
         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;
 
-            var temperatureDelta = tileReceiver.TemperatureArchived - sharerTemperature;
+            var temperatureDelta = tileReceiver.AirArchived.Temperature - sharerTemperature;
             if (MathF.Abs(temperatureDelta) > Atmospherics.MinimumTemperatureDeltaToConsider)
             {
                 var heatCapacity = GetHeatCapacityArchived(tileReceiver);
index d703a9815425b7d1bbce8a39cadebe828fe3563d..e6466c8157f8cae48b93813c6b13e96132e2028b 100644 (file)
@@ -355,7 +355,7 @@ namespace Content.Server.Atmos.EntitySystems
                         continue;
 
                     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;
 
                     AddActiveTile(gridAtmosphere, otherTile2);
index 85b1a93e20f7e9874befe2e4eb38ebdaa13d50ec..59320ba67bae1d9b4f1a2ad317b82be5e6719091 100644 (file)
@@ -231,7 +231,7 @@ namespace Content.Server.Atmos.EntitySystems
             tile.MapAtmosphere = false;
             atmos.MapTiles.Remove(tile);
             tile.Air = null;
-            Array.Clear(tile.MolesArchived);
+            tile.AirArchived = null;
             tile.ArchivedCycle = 0;
             tile.LastShare = 0f;
             tile.Space = false;
@@ -261,7 +261,7 @@ namespace Content.Server.Atmos.EntitySystems
                     return;
 
                 tile.Air = null;
-                Array.Clear(tile.MolesArchived);
+                tile.AirArchived = null;
                 tile.ArchivedCycle = 0;
                 tile.LastShare = 0f;
                 tile.Hotspot = new Hotspot();
index 8ed92a9d0eb26b19b721371e98a4db07bad790ec..46a554054b495f1e13b0131315cccacd2553d417 100644 (file)
@@ -131,7 +131,10 @@ namespace Content.Server.Atmos.EntitySystems
 
         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
                 && tile.HeatCapacity != 0f && other.HeatCapacity != 0f)
             {
@@ -145,11 +148,14 @@ namespace Content.Server.Atmos.EntitySystems
 
         public void RadiateToSpace(TileAtmosphere tile)
         {
+            if (tile.AirArchived == null)
+                return;
+
             // Considering 0ºC as the break even point for radiation in and out.
             if (tile.Temperature > Atmospherics.T0C)
             {
                 // 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))
                 {
                     var heat = tile.ThermalConductivity * deltaTemperature * (tile.HeatCapacity *
index 0026dbbf4f043ee4796ed6ec3fadc2be87db5a94..46a85990fa99d4d7a5386600d2c813a102ba22c0 100644 (file)
@@ -22,9 +22,6 @@ namespace Content.Server.Atmos
         [ViewVariables]
         public float Temperature { get; set; } = Atmospherics.T20C;
 
-        [ViewVariables]
-        public float TemperatureArchived { get; set; } = Atmospherics.T20C;
-
         [ViewVariables]
         public TileAtmosphere? PressureSpecificTarget { get; set; }
 
@@ -93,12 +90,16 @@ namespace Content.Server.Atmos
         [Access(typeof(AtmosphereSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends
         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")]
         public float LastShare;
 
-        [ViewVariables]
-        public readonly float[] MolesArchived = new float[Atmospherics.AdjustedNumberOfGases];
-
         GasMixture IGasMixtureHolder.Air
         {
             get => Air ?? new GasMixture(Atmospherics.CellVolume){ Temperature = Temperature };
@@ -139,6 +140,7 @@ namespace Content.Server.Atmos
             GridIndex = gridIndex;
             GridIndices = gridIndices;
             Air = mixture;
+            AirArchived = Air != null ? Air.Clone() : null;
             Space = space;
 
             if(immutable)
@@ -153,7 +155,7 @@ namespace Content.Server.Atmos
             NoGridTile = other.NoGridTile;
             MapAtmosphere = other.MapAtmosphere;
             Air = other.Air?.Clone();
-            Array.Copy(other.MolesArchived, MolesArchived, MolesArchived.Length);
+            AirArchived = Air != null ? Air.Clone() : null;
         }
 
         public TileAtmosphere()