Partial atmos refactor (#22521)
* Reduce atmos component queries * Remove method events * Cache airtight data * Make MolesArchived nullable * Fix airtight cache * only get tile def once * Immutable mixtures * firelock queries * misc * misc cleanup * Trim disconnected tiles * Fix merge issues and bugs * Why does the PR keep increasing in scope * debug overlay * Fix bugs * Fix test, remove unused events * Add setmapatmos command * Fix overlays * Add map check * A * Resolve conflicts with #26102 * Remove some obsolete methods
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.NodeContainer.NodeGroups;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.Components;
|
||||
using Content.Shared.Maps;
|
||||
@@ -8,6 +7,7 @@ using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Atmos.EntitySystems
|
||||
{
|
||||
@@ -30,118 +30,63 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
private int _currentRunAtmosphereIndex;
|
||||
private bool _simulationPaused;
|
||||
|
||||
private readonly List<Entity<GridAtmosphereComponent>> _currentRunAtmosphere = new();
|
||||
private TileAtmosphere GetOrNewTile(EntityUid owner, GridAtmosphereComponent atmosphere, Vector2i index)
|
||||
{
|
||||
var tile = atmosphere.Tiles.GetOrNew(index, out var existing);
|
||||
if (existing)
|
||||
return tile;
|
||||
|
||||
atmosphere.InvalidatedCoords.Add(index);
|
||||
tile.GridIndex = owner;
|
||||
tile.GridIndices = index;
|
||||
return tile;
|
||||
}
|
||||
|
||||
private readonly List<Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent>> _currentRunAtmosphere = new();
|
||||
|
||||
/// <summary>
|
||||
/// Revalidates all invalid coordinates in a grid atmosphere.
|
||||
/// I.e., process any tiles that have had their airtight blockers modified.
|
||||
/// </summary>
|
||||
/// <param name="ent">The grid atmosphere in question.</param>
|
||||
/// <returns>Whether the process succeeded or got paused due to time constrains.</returns>
|
||||
private bool ProcessRevalidate(Entity<GridAtmosphereComponent> ent, GasTileOverlayComponent? visuals)
|
||||
private bool ProcessRevalidate(Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent> ent)
|
||||
{
|
||||
var (owner, atmosphere) = ent;
|
||||
if (!atmosphere.ProcessingPaused)
|
||||
if (ent.Comp4.MapUid == null)
|
||||
{
|
||||
atmosphere.CurrentRunInvalidatedCoordinates.Clear();
|
||||
atmosphere.CurrentRunInvalidatedCoordinates.EnsureCapacity(atmosphere.InvalidatedCoords.Count);
|
||||
foreach (var tile in atmosphere.InvalidatedCoords)
|
||||
{
|
||||
atmosphere.CurrentRunInvalidatedCoordinates.Enqueue(tile);
|
||||
}
|
||||
atmosphere.InvalidatedCoords.Clear();
|
||||
Log.Error($"Attempted to process atmosphere on a map-less grid? Grid: {ToPrettyString(ent)}");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!TryComp(owner, out MapGridComponent? mapGridComp))
|
||||
return true;
|
||||
var (uid, atmosphere, visuals, grid, xform) = ent;
|
||||
var volume = GetVolumeForTiles(grid);
|
||||
TryComp(xform.MapUid, out MapAtmosphereComponent? mapAtmos);
|
||||
|
||||
var mapUid = _mapManager.GetMapEntityIdOrThrow(Transform(owner).MapID);
|
||||
if (!atmosphere.ProcessingPaused)
|
||||
{
|
||||
atmosphere.CurrentRunInvalidatedTiles.Clear();
|
||||
atmosphere.CurrentRunInvalidatedTiles.EnsureCapacity(atmosphere.InvalidatedCoords.Count);
|
||||
foreach (var indices in atmosphere.InvalidatedCoords)
|
||||
{
|
||||
var tile = GetOrNewTile(uid, atmosphere, indices);
|
||||
atmosphere.CurrentRunInvalidatedTiles.Enqueue(tile);
|
||||
|
||||
var volume = GetVolumeForTiles(mapGridComp);
|
||||
// Update tile.IsSpace and tile.MapAtmosphere, and tile.AirtightData.
|
||||
UpdateTileData(ent, mapAtmos, tile);
|
||||
}
|
||||
atmosphere.InvalidatedCoords.Clear();
|
||||
|
||||
if (_simulationStopwatch.Elapsed.TotalMilliseconds >= AtmosMaxProcessTime)
|
||||
return false;
|
||||
}
|
||||
|
||||
var number = 0;
|
||||
while (atmosphere.CurrentRunInvalidatedCoordinates.TryDequeue(out var indices))
|
||||
while (atmosphere.CurrentRunInvalidatedTiles.TryDequeue(out var tile))
|
||||
{
|
||||
if (!atmosphere.Tiles.TryGetValue(indices, out var tile))
|
||||
{
|
||||
tile = new TileAtmosphere(owner, indices,
|
||||
new GasMixture(volume) { Temperature = Atmospherics.T20C });
|
||||
atmosphere.Tiles[indices] = tile;
|
||||
}
|
||||
|
||||
var airBlockedEv = new IsTileAirBlockedMethodEvent(owner, indices, MapGridComponent:mapGridComp);
|
||||
GridIsTileAirBlocked(owner, atmosphere, ref airBlockedEv);
|
||||
var isAirBlocked = airBlockedEv.Result;
|
||||
|
||||
var oldBlocked = tile.BlockedAirflow;
|
||||
var updateAdjacentEv = new UpdateAdjacentMethodEvent(owner, indices, mapGridComp);
|
||||
GridUpdateAdjacent(owner, atmosphere, ref updateAdjacentEv);
|
||||
|
||||
// Blocked airflow changed, rebuild excited groups!
|
||||
if (tile.Excited && tile.BlockedAirflow != oldBlocked)
|
||||
{
|
||||
RemoveActiveTile(atmosphere, tile);
|
||||
}
|
||||
|
||||
// Call this instead of the grid method as the map has a say on whether the tile is space or not.
|
||||
if ((!mapGridComp.TryGetTileRef(indices, out var t) || t.IsSpace(_tileDefinitionManager)) && !isAirBlocked)
|
||||
{
|
||||
tile.Air = GetTileMixture(null, mapUid, indices);
|
||||
tile.MolesArchived = tile.Air != null ? new float[Atmospherics.AdjustedNumberOfGases] : null;
|
||||
tile.Space = IsTileSpace(null, mapUid, indices, mapGridComp);
|
||||
}
|
||||
else if (isAirBlocked)
|
||||
{
|
||||
if (airBlockedEv.NoAir)
|
||||
{
|
||||
tile.Air = null;
|
||||
tile.MolesArchived = null;
|
||||
tile.ArchivedCycle = 0;
|
||||
tile.LastShare = 0f;
|
||||
tile.Hotspot = new Hotspot();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tile.Air == null && NeedsVacuumFixing(mapGridComp, indices))
|
||||
{
|
||||
var vacuumEv = new FixTileVacuumMethodEvent(owner, indices);
|
||||
GridFixTileVacuum(owner, atmosphere, ref vacuumEv);
|
||||
}
|
||||
|
||||
// Tile used to be space, but isn't anymore.
|
||||
if (tile.Space || (tile.Air?.Immutable ?? false))
|
||||
{
|
||||
tile.Air = null;
|
||||
tile.MolesArchived = null;
|
||||
tile.ArchivedCycle = 0;
|
||||
tile.LastShare = 0f;
|
||||
tile.Space = false;
|
||||
}
|
||||
|
||||
tile.Air ??= new GasMixture(volume){Temperature = Atmospherics.T20C};
|
||||
tile.MolesArchived ??= new float[Atmospherics.AdjustedNumberOfGases];
|
||||
}
|
||||
|
||||
// We activate the tile.
|
||||
AddActiveTile(atmosphere, tile);
|
||||
|
||||
// TODO ATMOS: Query all the contents of this tile (like walls) and calculate the correct thermal conductivity and heat capacity
|
||||
var tileDef = mapGridComp.TryGetTileRef(indices, out var tileRef)
|
||||
? tileRef.GetContentTileDefinition(_tileDefinitionManager)
|
||||
: null;
|
||||
|
||||
tile.ThermalConductivity = tileDef?.ThermalConductivity ?? 0.5f;
|
||||
tile.HeatCapacity = tileDef?.HeatCapacity ?? float.PositiveInfinity;
|
||||
InvalidateVisuals(owner, indices, visuals);
|
||||
|
||||
for (var i = 0; i < Atmospherics.Directions; i++)
|
||||
{
|
||||
var direction = (AtmosDirection) (1 << i);
|
||||
var otherIndices = indices.Offset(direction);
|
||||
|
||||
if (atmosphere.Tiles.TryGetValue(otherIndices, out var otherTile))
|
||||
AddActiveTile(atmosphere, otherTile);
|
||||
}
|
||||
DebugTools.Assert(atmosphere.Tiles.GetValueOrDefault(tile.GridIndices) == tile);
|
||||
UpdateAdjacentTiles(ent, tile, activate: true);
|
||||
UpdateTileAir(ent, tile, volume);
|
||||
InvalidateVisuals(uid, tile.GridIndices, visuals);
|
||||
|
||||
if (number++ < InvalidCoordinatesLagCheckIterations)
|
||||
continue;
|
||||
@@ -149,12 +94,185 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
number = 0;
|
||||
// Process the rest next time.
|
||||
if (_simulationStopwatch.Elapsed.TotalMilliseconds >= AtmosMaxProcessTime)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TrimDisconnectedMapTiles(ent);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method queued a tile and all of its neighbours up for processing by <see cref="TrimDisconnectedMapTiles"/>.
|
||||
/// </summary>
|
||||
public void QueueTileTrim(GridAtmosphereComponent atmos, TileAtmosphere tile)
|
||||
{
|
||||
if (!tile.TrimQueued)
|
||||
{
|
||||
tile.TrimQueued = true;
|
||||
atmos.PossiblyDisconnectedTiles.Add(tile);
|
||||
}
|
||||
|
||||
for (var i = 0; i < Atmospherics.Directions; i++)
|
||||
{
|
||||
var direction = (AtmosDirection) (1 << i);
|
||||
var indices = tile.GridIndices.Offset(direction);
|
||||
if (atmos.Tiles.TryGetValue(indices, out var adj)
|
||||
&& adj.NoGridTile
|
||||
&& !adj.TrimQueued)
|
||||
{
|
||||
adj.TrimQueued = true;
|
||||
atmos.PossiblyDisconnectedTiles.Add(adj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tiles in a <see cref="GridAtmosphereComponent"/> are either grid-tiles, or they they should be are tiles
|
||||
/// adjacent to grid-tiles that represent the map's atmosphere. This method trims any map-tiles that are no longer
|
||||
/// adjacent to any grid-tiles.
|
||||
/// </summary>
|
||||
private void TrimDisconnectedMapTiles(
|
||||
Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent> ent)
|
||||
{
|
||||
var atmos = ent.Comp1;
|
||||
|
||||
foreach (var tile in atmos.PossiblyDisconnectedTiles)
|
||||
{
|
||||
tile.TrimQueued = false;
|
||||
if (!tile.NoGridTile)
|
||||
continue;
|
||||
|
||||
var connected = false;
|
||||
for (var i = 0; i < Atmospherics.Directions; i++)
|
||||
{
|
||||
var indices = tile.GridIndices.Offset((AtmosDirection) (1 << i));
|
||||
if (_map.TryGetTile(ent.Comp3, indices, out var gridTile) && !gridTile.IsEmpty)
|
||||
{
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!connected)
|
||||
{
|
||||
RemoveActiveTile(atmos, tile);
|
||||
atmos.Tiles.Remove(tile.GridIndices);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
atmos.PossiblyDisconnectedTiles.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a tile has a corresponding grid-tile, or whether it is a "map" tile. Also checks whether the
|
||||
/// tile should be considered "space"
|
||||
/// </summary>
|
||||
private void UpdateTileData(
|
||||
Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent> ent,
|
||||
MapAtmosphereComponent? mapAtmos,
|
||||
TileAtmosphere tile)
|
||||
{
|
||||
var idx = tile.GridIndices;
|
||||
bool mapAtmosphere;
|
||||
if (_map.TryGetTile(ent.Comp3, idx, out var gTile) && !gTile.IsEmpty)
|
||||
{
|
||||
var contentDef = (ContentTileDefinition) _tileDefinitionManager[gTile.TypeId];
|
||||
mapAtmosphere = contentDef.MapAtmosphere;
|
||||
tile.ThermalConductivity = contentDef.ThermalConductivity;
|
||||
tile.HeatCapacity = contentDef.HeatCapacity;
|
||||
tile.NoGridTile = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
mapAtmosphere = true;
|
||||
tile.ThermalConductivity = 0.5f;
|
||||
tile.HeatCapacity = float.PositiveInfinity;
|
||||
|
||||
if (!tile.NoGridTile)
|
||||
{
|
||||
tile.NoGridTile = true;
|
||||
|
||||
// This tile just became a non-grid atmos tile.
|
||||
// It, or one of its neighbours, might now be completely disconnected from the grid.
|
||||
QueueTileTrim(ent.Comp1, tile);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateAirtightData(ent.Owner, ent.Comp1, ent.Comp3, tile);
|
||||
|
||||
if (mapAtmosphere)
|
||||
{
|
||||
if (!tile.MapAtmosphere)
|
||||
{
|
||||
(tile.Air, tile.Space) = GetDefaultMapAtmosphere(mapAtmos);
|
||||
tile.MapAtmosphere = true;
|
||||
ent.Comp1.MapTiles.Add(tile);
|
||||
}
|
||||
|
||||
DebugTools.AssertNotNull(tile.Air);
|
||||
DebugTools.Assert(tile.Air?.Immutable ?? false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tile.MapAtmosphere)
|
||||
return;
|
||||
|
||||
// Tile used to be exposed to the map's atmosphere, but isn't anymore.
|
||||
RemoveMapAtmos(ent.Comp1, tile);
|
||||
}
|
||||
|
||||
private void RemoveMapAtmos(GridAtmosphereComponent atmos, TileAtmosphere tile)
|
||||
{
|
||||
DebugTools.Assert(tile.MapAtmosphere);
|
||||
DebugTools.AssertNotNull(tile.Air);
|
||||
DebugTools.Assert(tile.Air?.Immutable ?? false);
|
||||
tile.MapAtmosphere = false;
|
||||
atmos.MapTiles.Remove(tile);
|
||||
tile.Air = null;
|
||||
Array.Clear(tile.MolesArchived);
|
||||
tile.ArchivedCycle = 0;
|
||||
tile.LastShare = 0f;
|
||||
tile.Space = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check whether a grid-tile should have an air mixture, and give it one if it doesn't already have one.
|
||||
/// </summary>
|
||||
private void UpdateTileAir(
|
||||
Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent> ent,
|
||||
TileAtmosphere tile,
|
||||
float volume)
|
||||
{
|
||||
if (tile.MapAtmosphere)
|
||||
{
|
||||
DebugTools.AssertNotNull(tile.Air);
|
||||
DebugTools.Assert(tile.Air?.Immutable ?? false);
|
||||
return;
|
||||
}
|
||||
|
||||
var data = tile.AirtightData;
|
||||
var fullyBlocked = data.BlockedDirections == AtmosDirection.All;
|
||||
|
||||
if (fullyBlocked && data.NoAirWhenBlocked)
|
||||
{
|
||||
if (tile.Air == null)
|
||||
return;
|
||||
|
||||
tile.Air = null;
|
||||
Array.Clear(tile.MolesArchived);
|
||||
tile.ArchivedCycle = 0;
|
||||
tile.LastShare = 0f;
|
||||
tile.Hotspot = new Hotspot();
|
||||
return;
|
||||
}
|
||||
|
||||
if (tile.Air != null)
|
||||
return;
|
||||
|
||||
tile.Air = new GasMixture(volume){Temperature = Atmospherics.T20C};
|
||||
|
||||
if (data.FixVacuum)
|
||||
GridFixTileVacuum(ent, tile, volume);
|
||||
}
|
||||
|
||||
private void QueueRunTiles(
|
||||
@@ -170,19 +288,16 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
}
|
||||
}
|
||||
|
||||
private bool ProcessTileEqualize(Entity<GridAtmosphereComponent> ent, GasTileOverlayComponent? visuals)
|
||||
private bool ProcessTileEqualize(Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent> ent)
|
||||
{
|
||||
var (uid, atmosphere) = ent;
|
||||
var atmosphere = ent.Comp1;
|
||||
if (!atmosphere.ProcessingPaused)
|
||||
QueueRunTiles(atmosphere.CurrentRunTiles, atmosphere.ActiveTiles);
|
||||
|
||||
if (!TryComp(uid, out MapGridComponent? mapGridComp))
|
||||
throw new Exception("Tried to process a grid atmosphere on an entity that isn't a grid!");
|
||||
|
||||
var number = 0;
|
||||
while (atmosphere.CurrentRunTiles.TryDequeue(out var tile))
|
||||
{
|
||||
EqualizePressureInZone((uid, mapGridComp, atmosphere), tile, atmosphere.UpdateCounter, visuals);
|
||||
EqualizePressureInZone(ent, tile, atmosphere.UpdateCounter);
|
||||
|
||||
if (number++ < LagCheckIterations)
|
||||
continue;
|
||||
@@ -198,7 +313,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ProcessActiveTiles(GridAtmosphereComponent atmosphere, GasTileOverlayComponent? visuals)
|
||||
private bool ProcessActiveTiles(GridAtmosphereComponent atmosphere, GasTileOverlayComponent visuals)
|
||||
{
|
||||
if(!atmosphere.ProcessingPaused)
|
||||
QueueRunTiles(atmosphere.CurrentRunTiles, atmosphere.ActiveTiles);
|
||||
@@ -240,11 +355,11 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
excitedGroup.BreakdownCooldown++;
|
||||
excitedGroup.DismantleCooldown++;
|
||||
|
||||
if(excitedGroup.BreakdownCooldown > Atmospherics.ExcitedGroupBreakdownCycles)
|
||||
if (excitedGroup.BreakdownCooldown > Atmospherics.ExcitedGroupBreakdownCycles)
|
||||
ExcitedGroupSelfBreakdown(gridAtmosphere, excitedGroup);
|
||||
|
||||
else if(excitedGroup.DismantleCooldown > Atmospherics.ExcitedGroupsDismantleCycles)
|
||||
ExcitedGroupDismantle(gridAtmosphere, excitedGroup);
|
||||
else if (excitedGroup.DismantleCooldown > Atmospherics.ExcitedGroupsDismantleCycles)
|
||||
DeactivateGroupTiles(gridAtmosphere, excitedGroup);
|
||||
// TODO ATMOS. What is the point of this? why is this only de-exciting the group? Shouldn't it also dismantle it?
|
||||
|
||||
if (number++ < LagCheckIterations)
|
||||
continue;
|
||||
@@ -435,10 +550,10 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
_currentRunAtmosphereIndex = 0;
|
||||
_currentRunAtmosphere.Clear();
|
||||
|
||||
var query = EntityQueryEnumerator<GridAtmosphereComponent>();
|
||||
while (query.MoveNext(out var uid, out var grid))
|
||||
var query = EntityQueryEnumerator<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent>();
|
||||
while (query.MoveNext(out var uid, out var atmos, out var overlay, out var grid, out var xform ))
|
||||
{
|
||||
_currentRunAtmosphere.Add((uid, grid));
|
||||
_currentRunAtmosphere.Add((uid, atmos, overlay, grid, xform));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -448,8 +563,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
for (; _currentRunAtmosphereIndex < _currentRunAtmosphere.Count; _currentRunAtmosphereIndex++)
|
||||
{
|
||||
var ent = _currentRunAtmosphere[_currentRunAtmosphereIndex];
|
||||
var (owner, atmosphere) = ent;
|
||||
TryComp(owner, out GasTileOverlayComponent? visuals);
|
||||
var (owner, atmosphere, visuals, grid, xform) = ent;
|
||||
|
||||
if (!TryComp(owner, out TransformComponent? x)
|
||||
|| x.MapUid == null
|
||||
@@ -474,13 +588,14 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
switch (atmosphere.State)
|
||||
{
|
||||
case AtmosphereProcessingState.Revalidate:
|
||||
if (!ProcessRevalidate(ent, visuals))
|
||||
if (!ProcessRevalidate(ent))
|
||||
{
|
||||
atmosphere.ProcessingPaused = true;
|
||||
return;
|
||||
}
|
||||
|
||||
atmosphere.ProcessingPaused = false;
|
||||
|
||||
// Next state depends on whether monstermos equalization is enabled or not.
|
||||
// Note: We do this here instead of on the tile equalization step to prevent ending it early.
|
||||
// Therefore, a change to this CVar might only be applied after that step is over.
|
||||
@@ -489,7 +604,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
: AtmosphereProcessingState.ActiveTiles;
|
||||
continue;
|
||||
case AtmosphereProcessingState.TileEqualize:
|
||||
if (!ProcessTileEqualize(ent, visuals))
|
||||
if (!ProcessTileEqualize(ent))
|
||||
{
|
||||
atmosphere.ProcessingPaused = true;
|
||||
return;
|
||||
@@ -499,7 +614,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
atmosphere.State = AtmosphereProcessingState.ActiveTiles;
|
||||
continue;
|
||||
case AtmosphereProcessingState.ActiveTiles:
|
||||
if (!ProcessActiveTiles(atmosphere, visuals))
|
||||
if (!ProcessActiveTiles(ent, ent))
|
||||
{
|
||||
atmosphere.ProcessingPaused = true;
|
||||
return;
|
||||
@@ -520,7 +635,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
atmosphere.State = AtmosphereProcessingState.HighPressureDelta;
|
||||
continue;
|
||||
case AtmosphereProcessingState.HighPressureDelta:
|
||||
if (!ProcessHighPressureDelta(ent))
|
||||
if (!ProcessHighPressureDelta((ent, ent)))
|
||||
{
|
||||
atmosphere.ProcessingPaused = true;
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user