Space sections substantially slower (5-15 sec, exponential) with cooling (#16115)
* Space sections fractionally slower (1 sec, exponential) - ExplosivelyDepressurize reduces air pressure by about 20% each pass, sets to vacuum below 20 kPa - Causes some issues with AdjacentBits on airlock close * Introduced constants for Spacing in atmospherics * Limit space wind allowed during spacing to 1000 kPa per tile/sec - Less tile ripping per tick - Tiles rip based on wind - Robustness checks * Slowed down the spacing a bit * Slowed down the spacing a bit more * Better dynamics about high pressure air escaping, - Reduce air temperature (due to decompression) during spacing - Make some water vapor for flavor * Limit temperature loss to >8 Deg.C. No Water vapor
This commit is contained in:
@@ -284,7 +284,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
var otherTile2 = otherTile.AdjacentTiles[k];
|
var otherTile2 = otherTile.AdjacentTiles[k];
|
||||||
|
|
||||||
if (taker.MonstermosInfo.MoleDelta >= 0) break; // We're done here now. Let's not do more work than needed.
|
if (taker.MonstermosInfo.MoleDelta >= 0) break; // We're done here now. Let's not do more work than needed.
|
||||||
if (otherTile2 == null || otherTile2.MonstermosInfo.LastQueueCycle != queueCycle) continue;
|
if (otherTile2 == null || otherTile2.AdjacentBits == 0 || otherTile2.MonstermosInfo.LastQueueCycle != queueCycle) continue;
|
||||||
DebugTools.Assert(otherTile2.AdjacentBits.IsFlagSet(direction.GetOpposite()));
|
DebugTools.Assert(otherTile2.AdjacentBits.IsFlagSet(direction.GetOpposite()));
|
||||||
if (otherTile2.MonstermosInfo.LastSlowQueueCycle == queueCycleSlow) continue;
|
if (otherTile2.MonstermosInfo.LastSlowQueueCycle == queueCycleSlow) continue;
|
||||||
_equalizeQueue[queueLength++] = otherTile2;
|
_equalizeQueue[queueLength++] = otherTile2;
|
||||||
@@ -342,6 +342,8 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
var direction = (AtmosDirection) (1 << j);
|
var direction = (AtmosDirection) (1 << j);
|
||||||
if (!otherTile.AdjacentBits.IsFlagSet(direction)) continue;
|
if (!otherTile.AdjacentBits.IsFlagSet(direction)) continue;
|
||||||
var otherTile2 = otherTile.AdjacentTiles[j]!;
|
var otherTile2 = otherTile.AdjacentTiles[j]!;
|
||||||
|
if (otherTile2.AdjacentBits == 0)
|
||||||
|
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) continue;
|
if (otherTile2.Air != null && CompareExchange(otherTile2.Air, tile.Air) == GasCompareResult.NoExchange) continue;
|
||||||
AddActiveTile(gridAtmosphere, otherTile2);
|
AddActiveTile(gridAtmosphere, otherTile2);
|
||||||
@@ -423,36 +425,61 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
otherTile.MonstermosInfo.CurrentTransferDirection = AtmosDirection.Invalid;
|
otherTile.MonstermosInfo.CurrentTransferDirection = AtmosDirection.Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Moving into the room from the breach or airlock
|
||||||
for (var i = 0; i < progressionCount; i++)
|
for (var i = 0; i < progressionCount; i++)
|
||||||
{
|
{
|
||||||
|
// From a tile exposed to space
|
||||||
var otherTile = _depressurizeProgressionOrder[i];
|
var otherTile = _depressurizeProgressionOrder[i];
|
||||||
for (var j = 0; j < Atmospherics.Directions; j++)
|
for (var j = 0; j < Atmospherics.Directions; j++)
|
||||||
{
|
{
|
||||||
|
// Flood fill into this new direction
|
||||||
var direction = (AtmosDirection) (1 << j);
|
var direction = (AtmosDirection) (1 << j);
|
||||||
// Tiles in _depressurizeProgressionOrder cannot have null air.
|
// Tiles in _depressurizeProgressionOrder cannot have null air.
|
||||||
if (!otherTile.AdjacentBits.IsFlagSet(direction) && !otherTile.Space) continue;
|
if (!otherTile.AdjacentBits.IsFlagSet(direction) && !otherTile.Space) continue;
|
||||||
var tile2 = otherTile.AdjacentTiles[j];
|
var tile2 = otherTile.AdjacentTiles[j];
|
||||||
if (tile2?.MonstermosInfo.LastQueueCycle != queueCycle) continue;
|
if (tile2?.MonstermosInfo.LastQueueCycle != queueCycle) continue;
|
||||||
DebugTools.Assert(tile2.AdjacentBits.IsFlagSet(direction.GetOpposite()));
|
DebugTools.Assert(tile2.AdjacentBits.IsFlagSet(direction.GetOpposite()));
|
||||||
|
// If flood fill has already reached this tile, continue.
|
||||||
if (tile2.MonstermosInfo.LastSlowQueueCycle == queueCycleSlow) continue;
|
if (tile2.MonstermosInfo.LastSlowQueueCycle == queueCycleSlow) continue;
|
||||||
if(tile2.Space) continue;
|
if(tile2.Space) continue;
|
||||||
tile2.MonstermosInfo.CurrentTransferDirection = direction.GetOpposite();
|
tile2.MonstermosInfo.CurrentTransferDirection = direction.GetOpposite();
|
||||||
tile2.MonstermosInfo.CurrentTransferAmount = 0;
|
tile2.MonstermosInfo.CurrentTransferAmount = 0.0f;
|
||||||
tile2.PressureSpecificTarget = otherTile.PressureSpecificTarget;
|
tile2.PressureSpecificTarget = otherTile.PressureSpecificTarget;
|
||||||
tile2.MonstermosInfo.LastSlowQueueCycle = queueCycleSlow;
|
tile2.MonstermosInfo.LastSlowQueueCycle = queueCycleSlow;
|
||||||
_depressurizeProgressionOrder[progressionCount++] = tile2;
|
_depressurizeProgressionOrder[progressionCount++] = tile2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Moving towards the breach from the edges of the flood filled region
|
||||||
for (var i = progressionCount - 1; i >= 0; i--)
|
for (var i = progressionCount - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
var otherTile = _depressurizeProgressionOrder[i];
|
var otherTile = _depressurizeProgressionOrder[i];
|
||||||
|
if (otherTile?.Air == null) { continue;}
|
||||||
if (otherTile.MonstermosInfo.CurrentTransferDirection == AtmosDirection.Invalid) continue;
|
if (otherTile.MonstermosInfo.CurrentTransferDirection == AtmosDirection.Invalid) continue;
|
||||||
gridAtmosphere.HighPressureDelta.Add(otherTile);
|
gridAtmosphere.HighPressureDelta.Add(otherTile);
|
||||||
AddActiveTile(gridAtmosphere, otherTile);
|
AddActiveTile(gridAtmosphere, otherTile);
|
||||||
var otherTile2 = otherTile.AdjacentTiles[otherTile.MonstermosInfo.CurrentTransferDirection.ToIndex()];
|
var otherTile2 = otherTile.AdjacentTiles[otherTile.MonstermosInfo.CurrentTransferDirection.ToIndex()];
|
||||||
if (otherTile2?.Air == null) continue;
|
if (otherTile2?.Air == null)
|
||||||
var sum = otherTile2.Air.TotalMoles;
|
{
|
||||||
|
// The tile connecting us to space is spaced already. So just space this tile now.
|
||||||
|
otherTile.Air!.Clear();
|
||||||
|
otherTile.Air.Temperature = Atmospherics.TCMB;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pressure as a multiple of normal air pressure (takes temperature into account)
|
||||||
|
float pressureMultiple = (otherTile.Air.Pressure / 110.0f);
|
||||||
|
var sum = otherTile.Air.TotalMoles * Atmospherics.SpacingEscapeRatio * pressureMultiple;
|
||||||
|
if (sum < Atmospherics.SpacingMinGas)
|
||||||
|
{
|
||||||
|
// Boost the last bit of air draining from the tile.
|
||||||
|
sum = Math.Min(Atmospherics.SpacingMinGas, otherTile.Air.TotalMoles);
|
||||||
|
}
|
||||||
|
if (sum + otherTile.MonstermosInfo.CurrentTransferAmount > Atmospherics.SpacingMaxWind * pressureMultiple)
|
||||||
|
{
|
||||||
|
// Limit the flow of air out of tiles which have air flowing into them from elsewhere.
|
||||||
|
sum = Math.Max(Atmospherics.SpacingMinGas, Atmospherics.SpacingMaxWind * pressureMultiple - otherTile.MonstermosInfo.CurrentTransferAmount);
|
||||||
|
}
|
||||||
totalMolesRemoved += sum;
|
totalMolesRemoved += sum;
|
||||||
otherTile.MonstermosInfo.CurrentTransferAmount += sum;
|
otherTile.MonstermosInfo.CurrentTransferAmount += sum;
|
||||||
otherTile2.MonstermosInfo.CurrentTransferAmount += otherTile.MonstermosInfo.CurrentTransferAmount;
|
otherTile2.MonstermosInfo.CurrentTransferAmount += otherTile.MonstermosInfo.CurrentTransferAmount;
|
||||||
@@ -465,16 +492,33 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
otherTile2.PressureDirection = otherTile.MonstermosInfo.CurrentTransferDirection;
|
otherTile2.PressureDirection = otherTile.MonstermosInfo.CurrentTransferDirection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (otherTile.Air != null && otherTile.Air.Pressure - sum > Atmospherics.SpacingMinGas * 0.1f)
|
||||||
|
{
|
||||||
|
// Transfer the air into the other tile (space wind :)
|
||||||
|
ReleaseGasTo(otherTile.Air!, otherTile2.Air!, sum);
|
||||||
|
// And then some magically into space
|
||||||
|
ReleaseGasTo(otherTile2.Air!, null, sum * 0.3f);
|
||||||
|
|
||||||
// This gas mixture cannot be null, no tile in _depressurizeProgressionOrder can have a null gas mixture
|
if (otherTile.Air.Temperature > 280.0f)
|
||||||
otherTile.Air!.Clear();
|
{
|
||||||
|
// Temperature reduces as air drains. But nerf the real temperature reduction a bit
|
||||||
|
// Also, limit the temperature loss to remain > 10 Deg.C for convenience
|
||||||
|
float realtemploss = (otherTile.Air.TotalMoles - sum) / otherTile.Air.TotalMoles;
|
||||||
|
otherTile.Air.Temperature *= 0.9f + 0.1f * realtemploss;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This gas mixture cannot be null, no tile in _depressurizeProgressionOrder can have a null gas mixture
|
||||||
|
otherTile.Air!.Clear();
|
||||||
|
|
||||||
// This is a little hacky, but hear me out. It makes sense. We have just vacuumed all of the tile's air
|
// This is a little hacky, but hear me out. It makes sense. We have just vacuumed all of the tile's air
|
||||||
// therefore there is no more gas in the tile, therefore the tile should be as cold as space!
|
// therefore there is no more gas in the tile, therefore the tile should be as cold as space!
|
||||||
otherTile.Air.Temperature = Atmospherics.TCMB;
|
otherTile.Air.Temperature = Atmospherics.TCMB;
|
||||||
|
}
|
||||||
|
|
||||||
InvalidateVisuals(otherTile.GridIndex, otherTile.GridIndices, visuals);
|
InvalidateVisuals(otherTile.GridIndex, otherTile.GridIndices, visuals);
|
||||||
HandleDecompressionFloorRip(mapGrid, otherTile, sum);
|
HandleDecompressionFloorRip(mapGrid, otherTile, otherTile.MonstermosInfo.CurrentTransferAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GridImpulse && tileCount > 0)
|
if (GridImpulse && tileCount > 0)
|
||||||
@@ -488,7 +532,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
_physics.ApplyAngularImpulse(mapGrid.Owner, Vector2.Cross(tile.GridIndices - gridPhysics.LocalCenter, direction) * totalMolesRemoved, body: gridPhysics);
|
_physics.ApplyAngularImpulse(mapGrid.Owner, Vector2.Cross(tile.GridIndices - gridPhysics.LocalCenter, direction) * totalMolesRemoved, body: gridPhysics);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tileCount > 10 && (totalMolesRemoved / tileCount) > 20)
|
if(tileCount > 10 && (totalMolesRemoved / tileCount) > 10)
|
||||||
_adminLog.Add(LogType.ExplosiveDepressurization, LogImpact.High,
|
_adminLog.Add(LogType.ExplosiveDepressurization, LogImpact.High,
|
||||||
$"Explosive depressurization removed {totalMolesRemoved} moles from {tileCount} tiles starting from position {tile.GridIndices:position} on grid ID {tile.GridIndex:grid}");
|
$"Explosive depressurization removed {totalMolesRemoved} moles from {tileCount} tiles starting from position {tile.GridIndices:position} on grid ID {tile.GridIndex:grid}");
|
||||||
|
|
||||||
@@ -607,7 +651,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
if (!MonstermosRipTiles)
|
if (!MonstermosRipTiles)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var chance = MathHelper.Clamp(sum / 500, 0.005f, 0.5f);
|
var chance = MathHelper.Clamp(0.01f + (sum / Atmospherics.SpacingMaxWind) * 0.3f, 0.003f, 0.3f);
|
||||||
|
|
||||||
if (sum > 20 && _robustRandom.Prob(chance))
|
if (sum > 20 && _robustRandom.Prob(chance))
|
||||||
PryTile(mapGrid, tile.GridIndices);
|
PryTile(mapGrid, tile.GridIndices);
|
||||||
|
|||||||
@@ -309,6 +309,25 @@ namespace Content.Shared.Atmos
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public const float MaxTransferRate = 200;
|
public const float MaxTransferRate = 200;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// What fraction of air from a spaced tile escapes every tick.
|
||||||
|
/// 1.0 for instant spacing, 0.2 means 20% of remaining air lost each time
|
||||||
|
/// </summary>
|
||||||
|
public const float SpacingEscapeRatio = 0.05f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Minimum amount of air allowed on a spaced tile before it is reset to 0 immediately in kPa
|
||||||
|
/// Since the decay due to SpacingEscapeRatio follows a curve, it would never reach 0.0 exactly
|
||||||
|
/// unless we truncate it somewhere.
|
||||||
|
/// </summary>
|
||||||
|
public const float SpacingMinGas = 2.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How much wind can go through a single tile before that tile doesn't depressurize itself
|
||||||
|
/// (I.e spacing is limited in large rooms heading into smaller spaces)
|
||||||
|
/// </summary>
|
||||||
|
public const float SpacingMaxWind = 500.0f;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user