ECS Atmos Part 4: Moves all atmos logic from TileAtmosphere to AtmosphereSystem. (#4295)

* Moves all atmos logic from TileAtmosphere to AtmosphereSystem.

* Atmos uses grid anchoring to check for firelocks instead of grid tile lookups.

* CVar for space wind sound

* CVar for explosive depressurization
This commit is contained in:
Vera Aguilera Puerto
2021-07-20 18:03:49 +02:00
committed by GitHub
parent e1fdd902bb
commit fcafa8f439
17 changed files with 1165 additions and 1121 deletions

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Content.Server.Alert;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Stunnable.Components;
using Content.Server.Temperature.Components;
using Content.Shared.ActionBlocker;
@@ -122,7 +123,7 @@ namespace Content.Server.Atmos.Components
return;
}
tile.HotspotExpose(700, 50, true);
EntitySystem.Get<AtmosphereSystem>().HotspotExpose(tile.GridIndex, tile.GridIndices, 700f, 50f, true);
var physics = Owner.GetComponent<IPhysBody>();

View File

@@ -36,7 +36,6 @@ namespace Content.Server.Atmos.Components
[Dependency] private IServerEntityManager _serverEntityManager = default!;
[Dependency] private IGameTiming _gameTiming = default!;
public GridTileLookupSystem GridTileLookupSystem { get; private set; } = default!;
internal GasTileOverlaySystem GasTileOverlaySystem { get; private set; } = default!;
public AtmosphereSystem AtmosphereSystem { get; private set; } = default!;
@@ -182,7 +181,6 @@ namespace Content.Server.Atmos.Components
}
}
GridTileLookupSystem = EntitySystem.Get<GridTileLookupSystem>();
GasTileOverlaySystem = EntitySystem.Get<GasTileOverlaySystem>();
AtmosphereSystem = EntitySystem.Get<AtmosphereSystem>();

View File

@@ -109,7 +109,7 @@ namespace Content.Server.Atmos.EntitySystems
{
gases[i] = tile.Air.GetMoles(i);
}
return new AtmosDebugOverlayData(tile.Air.Temperature, gases, tile.PressureDirectionForDebugOverlay, tile.ExcitedGroup != null, tile.BlockedAirflow);
return new AtmosDebugOverlayData(tile.Air.Temperature, gases, tile.PressureDirection, tile.ExcitedGroup != null, tile.BlockedAirflow);
}
}

View File

@@ -5,7 +5,9 @@ namespace Content.Server.Atmos.EntitySystems
public partial class AtmosphereSystem
{
public bool SpaceWind { get; private set; }
public string? SpaceWindSound { get; private set; }
public bool MonstermosEqualization { get; private set; }
public bool MonstermosDepressurization { get; private set; }
public bool Superconduction { get; private set; }
public bool ExcitedGroupsSpaceIsAllConsuming { get; private set; }
public float AtmosMaxProcessTime { get; private set; }
@@ -15,7 +17,9 @@ namespace Content.Server.Atmos.EntitySystems
private void InitializeCVars()
{
_cfg.OnValueChanged(CCVars.SpaceWind, value => SpaceWind = value, true);
_cfg.OnValueChanged(CCVars.SpaceWindSound, value => SpaceWindSound = value, true);
_cfg.OnValueChanged(CCVars.MonstermosEqualization, value => MonstermosEqualization = value, true);
_cfg.OnValueChanged(CCVars.MonstermosDepressurization, value => MonstermosDepressurization = value, true);
_cfg.OnValueChanged(CCVars.Superconduction, value => Superconduction = value, true);
_cfg.OnValueChanged(CCVars.AtmosMaxProcessTime, value => AtmosMaxProcessTime = value, true);
_cfg.OnValueChanged(CCVars.AtmosTickRate, value => AtmosTickRate = value, true);

View File

@@ -163,15 +163,15 @@ namespace Content.Server.Atmos.EntitySystems
if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere))
{
foreach (var tileAtmos in gridAtmosphere)
foreach (var tile in gridAtmosphere)
{
if (tileAtmos?.Air == null)
if (tile?.Air == null)
continue;
if(invalidate)
tileAtmos.Invalidate();
gridAtmosphere.Invalidate(tile.GridIndices);
yield return tileAtmos.Air;
yield return tile.Air;
}
}
}
@@ -560,7 +560,7 @@ namespace Content.Server.Atmos.EntitySystems
{
var tileAtmos = gridAtmosphere.GetTile(tile)!;
for (var i = 0; i < tileAtmos.AdjacentTiles.Count; i++)
for (var i = 0; i < tileAtmos.AdjacentTiles.Length; i++)
{
var adjacentTile = tileAtmos.AdjacentTiles[i];
// TileAtmosphere has nullable disabled, so just in case...
@@ -634,7 +634,7 @@ namespace Content.Server.Atmos.EntitySystems
{
var tileAtmos = gridAtmosphere.GetTile(tile)!;
for (var i = 0; i < tileAtmos.AdjacentTiles.Count; i++)
for (var i = 0; i < tileAtmos.AdjacentTiles.Length; i++)
{
var adjacentTile = tileAtmos.AdjacentTiles[i];
@@ -651,7 +651,7 @@ namespace Content.Server.Atmos.EntitySystems
}
if (invalidate)
adjacentTile.Invalidate();
gridAtmosphere.Invalidate(adjacentTile.GridIndices);
yield return adjacentTile.Air;
}
@@ -747,7 +747,12 @@ namespace Content.Server.Atmos.EntitySystems
if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere))
{
gridAtmosphere.GetTile(tile, false)?.HotspotExpose(exposedTemperature, exposedVolume, soh);
var tileAtmosphere = gridAtmosphere.GetTile(tile, false);
if (tileAtmosphere == null)
return;
HotspotExpose(gridAtmosphere, tileAtmosphere, exposedTemperature, exposedVolume, soh);
gridAtmosphere.Invalidate(tile);
return;
}

View File

@@ -0,0 +1,69 @@
using Content.Server.Atmos.Components;
using Content.Shared.Atmos;
using Content.Shared.Audio;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Player;
namespace Content.Server.Atmos.EntitySystems
{
public partial class AtmosphereSystem
{
private int _spaceWindSoundCooldown = 0;
private void HighPressureMovements(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile)
{
// TODO ATMOS finish this
if(tile.PressureDifference > 15)
{
if(_spaceWindSoundCooldown == 0)
{
var coordinates = tile.GridIndices.ToEntityCoordinates(tile.GridIndex, _mapManager);
if(!string.IsNullOrEmpty(SpaceWindSound))
SoundSystem.Play(Filter.Pvs(coordinates), SpaceWindSound, coordinates,
AudioHelpers.WithVariation(0.125f).WithVolume(MathHelper.Clamp(tile.PressureDifference / 10, 10, 100)));
}
}
foreach (var entity in Get<GridTileLookupSystem>().GetEntitiesIntersecting(tile.GridIndex, tile.GridIndices))
{
if (!entity.TryGetComponent(out IPhysBody? physics)
|| !entity.IsMovedByPressure(out var pressure)
|| entity.IsInContainer())
continue;
var pressureMovements = physics.Owner.EnsureComponent<MovedByPressureComponent>();
if (pressure.LastHighPressureMovementAirCycle < gridAtmosphere.UpdateCounter)
{
pressureMovements.ExperiencePressureDifference(gridAtmosphere.UpdateCounter, tile.PressureDifference, tile.PressureDirection, 0, tile.PressureSpecificTarget?.GridIndices.ToEntityCoordinates(tile.GridIndex, _mapManager) ?? EntityCoordinates.Invalid);
}
}
if (tile.PressureDifference > 100)
{
// TODO ATMOS Do space wind graphics here!
}
_spaceWindSoundCooldown++;
if (_spaceWindSoundCooldown > 75)
_spaceWindSoundCooldown = 0;
}
private void ConsiderPressureDifference(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, TileAtmosphere other, float difference)
{
gridAtmosphere.AddHighPressureDelta(tile);
if (difference > tile.PressureDifference)
{
tile.PressureDifference = difference;
tile.PressureDirection = ((Vector2i)(tile.GridIndices - other.GridIndices)).GetDir().ToAtmosDirection();
}
}
}
}

View File

@@ -0,0 +1,150 @@
#nullable disable warnings
#nullable enable annotations
using Content.Server.Atmos.Components;
using Content.Server.Atmos.Reactions;
using Content.Server.Coordinates.Helpers;
using Content.Shared.Atmos;
using Content.Shared.GameTicking;
using Content.Shared.Maps;
namespace Content.Server.Atmos.EntitySystems
{
public partial class AtmosphereSystem
{
private void ProcessHotspot(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile)
{
if (!tile.Hotspot.Valid)
{
gridAtmosphere.RemoveHotspotTile(tile);
return;
}
if (!tile.Excited)
{
gridAtmosphere.AddActiveTile(tile);
}
if (!tile.Hotspot.SkippedFirstProcess)
{
tile.Hotspot.SkippedFirstProcess = true;
return;
}
tile.ExcitedGroup?.ResetCooldowns();
if ((tile.Hotspot.Temperature < Atmospherics.FireMinimumTemperatureToExist) || (tile.Hotspot.Volume <= 1f)
|| tile.Air == null || tile.Air.GetMoles(Gas.Oxygen) < 0.5f || (tile.Air.GetMoles(Gas.Plasma) < 0.5f && tile.Air.GetMoles(Gas.Tritium) < 0.5f))
{
tile.Hotspot = new Hotspot();
tile.UpdateVisuals();
return;
}
PerformHotspotExposure(gridAtmosphere, tile);
if (tile.Hotspot.Bypassing)
{
tile.Hotspot.State = 3;
gridAtmosphere.BurnTile(tile.GridIndices);
if (tile.Air.Temperature > Atmospherics.FireMinimumTemperatureToSpread)
{
var radiatedTemperature = tile.Air.Temperature * Atmospherics.FireSpreadRadiosityScale;
foreach (var otherTile in tile.AdjacentTiles)
{
if(!otherTile.Hotspot.Valid)
HotspotExpose(gridAtmosphere, otherTile, radiatedTemperature, Atmospherics.CellVolume/4);
}
}
}
else
{
tile.Hotspot.State = (byte) (tile.Hotspot.Volume > Atmospherics.CellVolume * 0.4f ? 2 : 1);
}
if (tile.Hotspot.Temperature > tile.MaxFireTemperatureSustained)
tile.MaxFireTemperatureSustained = tile.Hotspot.Temperature;
// TODO ATMOS Maybe destroy location here?
}
private void HotspotExpose(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, float exposedTemperature, float exposedVolume, bool soh = false)
{
if (tile.Air == null)
return;
var oxygen = tile.Air.GetMoles(Gas.Oxygen);
if (oxygen < 0.5f)
return;
var plasma = tile.Air.GetMoles(Gas.Plasma);
var tritium = tile.Air.GetMoles(Gas.Tritium);
if (tile.Hotspot.Valid)
{
if (soh)
{
if (plasma > 0.5f || tritium > 0.5f)
{
if (tile.Hotspot.Temperature < exposedTemperature)
tile.Hotspot.Temperature = exposedTemperature;
if (tile.Hotspot.Volume < exposedVolume)
tile.Hotspot.Volume = exposedVolume;
}
}
return;
}
if ((exposedTemperature > Atmospherics.PlasmaMinimumBurnTemperature) && (plasma > 0.5f || tritium > 0.5f))
{
tile.Hotspot = new Hotspot
{
Volume = exposedVolume * 25f,
Temperature = exposedTemperature,
SkippedFirstProcess = tile.CurrentCycle > gridAtmosphere.UpdateCounter
};
tile.Hotspot.Start();
gridAtmosphere.AddActiveTile(tile);
gridAtmosphere.AddHotspotTile(tile);
}
}
private void PerformHotspotExposure(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile)
{
if (tile.Air == null || !tile.Hotspot.Valid) return;
tile.Hotspot.Bypassing = tile.Hotspot.SkippedFirstProcess && tile.Hotspot.Volume > tile.Air.Volume*0.95f;
if (tile.Hotspot.Bypassing)
{
tile.Hotspot.Volume = tile.Air.ReactionResults[GasReaction.Fire] * Atmospherics.FireGrowthRate;
tile.Hotspot.Temperature = tile.Air.Temperature;
}
else
{
var affected = tile.Air.RemoveRatio(tile.Hotspot.Volume / tile.Air.Volume);
affected.Temperature = tile.Hotspot.Temperature;
gridAtmosphere.AtmosphereSystem.React(affected, tile);
tile.Hotspot.Temperature = affected.Temperature;
tile.Hotspot.Volume = affected.ReactionResults[GasReaction.Fire] * Atmospherics.FireGrowthRate;
Merge(tile.Air, affected);
gridAtmosphere.Invalidate(tile.GridIndices);
}
var tileRef = tile.GridIndices.GetTileRef(tile.GridIndex);
foreach (var entity in tileRef.GetEntitiesInTileFast())
{
foreach (var fireAct in entity.GetAllComponents<IFireAct>())
{
fireAct.FireAct(tile.Hotspot.Temperature, tile.Hotspot.Volume);
}
}
}
}
}

View File

@@ -0,0 +1,135 @@
#nullable disable warnings
#nullable enable annotations
using Content.Server.Atmos.Components;
using Content.Shared.Atmos;
namespace Content.Server.Atmos.EntitySystems
{
public partial class AtmosphereSystem
{
private void ProcessCell(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, int fireCount, bool spaceWind = true)
{
// Can't process a tile without air
if (tile.Air == null)
{
gridAtmosphere.RemoveActiveTile(tile);
return;
}
if (tile.ArchivedCycle < fireCount)
Archive(tile, fireCount);
tile.CurrentCycle = fireCount;
var adjacentTileLength = 0;
for (var i = 0; i < Atmospherics.Directions; i++)
{
var direction = (AtmosDirection) (1 << i);
if(tile.AdjacentBits.IsFlagSet(direction))
adjacentTileLength++;
}
for(var i = 0; i < Atmospherics.Directions; i++)
{
var direction = (AtmosDirection) (1 << i);
if (!tile.AdjacentBits.IsFlagSet(direction)) continue;
var enemyTile = tile.AdjacentTiles[i];
// If the tile is null or has no air, we don't do anything for it.
if(enemyTile?.Air == null) continue;
if (fireCount <= enemyTile.CurrentCycle) continue;
Archive(enemyTile, fireCount);
var shouldShareAir = false;
if (tile.ExcitedGroup != null && enemyTile.ExcitedGroup != null)
{
if (tile.ExcitedGroup != enemyTile.ExcitedGroup)
{
tile.ExcitedGroup.MergeGroups(enemyTile.ExcitedGroup);
}
shouldShareAir = true;
} else if (tile.Air!.Compare(enemyTile.Air!) != GasMixture.GasCompareResult.NoExchange)
{
if (!enemyTile.Excited)
{
gridAtmosphere.AddActiveTile(enemyTile);
}
var excitedGroup = tile.ExcitedGroup;
excitedGroup ??= enemyTile.ExcitedGroup;
if (excitedGroup == null)
{
excitedGroup = new ExcitedGroup();
excitedGroup.Initialize(gridAtmosphere);
}
if (tile.ExcitedGroup == null)
excitedGroup.AddTile(tile);
if(enemyTile.ExcitedGroup == null)
excitedGroup.AddTile(enemyTile);
shouldShareAir = true;
}
if (shouldShareAir)
{
var difference = Share(tile.Air!, enemyTile.Air!, adjacentTileLength);
if (spaceWind)
{
if (difference > 0)
{
ConsiderPressureDifference(gridAtmosphere, tile, enemyTile, difference);
}
else
{
ConsiderPressureDifference(gridAtmosphere, enemyTile, tile, -difference);
}
}
LastShareCheck(tile);
}
}
if(tile.Air != null)
React(tile.Air, tile);
tile.UpdateVisuals();
var remove = true;
if(tile.Air!.Temperature > Atmospherics.MinimumTemperatureStartSuperConduction)
if (ConsiderSuperconductivity(gridAtmosphere, tile, true))
remove = false;
if(tile.ExcitedGroup == null && remove)
gridAtmosphere.RemoveActiveTile(tile);
}
private void Archive(TileAtmosphere tile, int fireCount)
{
tile.Air?.Archive();
tile.ArchivedCycle = fireCount;
tile.TemperatureArchived = tile.Temperature;
}
private void LastShareCheck(TileAtmosphere tile)
{
if (tile.Air == null || tile.ExcitedGroup == null)
return;
switch (tile.Air.LastShare)
{
case > Atmospherics.MinimumAirToSuspend:
tile.ExcitedGroup.ResetCooldowns();
break;
case > Atmospherics.MinimumMolesDeltaToMove:
tile.ExcitedGroup.DismantleCooldown = 0;
break;
}
}
}
}

View File

@@ -0,0 +1,576 @@
#nullable disable warnings
#nullable enable annotations
using System;
using System.Buffers;
using System.Collections.Generic;
using Content.Server.Atmos.Components;
using Content.Server.Coordinates.Helpers;
using Content.Shared.Atmos;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Random;
namespace Content.Server.Atmos.EntitySystems
{
public partial class AtmosphereSystem
{
[Dependency] private readonly IRobustRandom _robustRandom = default!;
private readonly TileAtmosphereComparer _monstermosComparer = new();
public void EqualizePressureInZone(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, int cycleNum)
{
if (tile.Air == null || (tile.MonstermosInfo.LastCycle >= cycleNum))
return; // Already done.
tile.MonstermosInfo = new MonstermosInfo();
var startingMoles = tile.Air.TotalMoles;
var runAtmos = false;
// We need to figure if this is necessary
for (var i = 0; i < Atmospherics.Directions; i++)
{
var direction = (AtmosDirection) (1 << i);
if (!tile.AdjacentBits.IsFlagSet(direction)) continue;
var other = tile.AdjacentTiles[i];
if (other?.Air == null) continue;
var comparisonMoles = other.Air.TotalMoles;
if (!(MathF.Abs(comparisonMoles - startingMoles) > Atmospherics.MinimumMolesDeltaToMove)) continue;
runAtmos = true;
break;
}
if (!runAtmos) // There's no need so we don't bother.
{
tile.MonstermosInfo.LastCycle = cycleNum;
return;
}
var queueCycle = ++gridAtmosphere.EqualizationQueueCycleControl;
var totalMoles = 0f;
var tiles = ArrayPool<TileAtmosphere>.Shared.Rent(Atmospherics.MonstermosHardTileLimit);
tiles[0] = tile;
tile.MonstermosInfo.LastQueueCycle = queueCycle;
var tileCount = 1;
for (var i = 0; i < tileCount; i++)
{
if (i > Atmospherics.MonstermosHardTileLimit) break;
var exploring = tiles[i];
if (i < Atmospherics.MonstermosTileLimit)
{
var tileMoles = exploring.Air.TotalMoles;
exploring.MonstermosInfo.MoleDelta = tileMoles;
totalMoles += tileMoles;
}
for (var j = 0; j < Atmospherics.Directions; j++)
{
var direction = (AtmosDirection) (1 << j);
if (!exploring.AdjacentBits.IsFlagSet(direction)) continue;
var adj = exploring.AdjacentTiles[j];
if (adj?.Air == null) continue;
if(adj.MonstermosInfo.LastQueueCycle == queueCycle) continue;
adj.MonstermosInfo = new MonstermosInfo {LastQueueCycle = queueCycle};
if(tileCount < Atmospherics.MonstermosHardTileLimit)
tiles[tileCount++] = adj;
if (adj.Air.Immutable)
{
// Looks like someone opened an airlock to space!
ExplosivelyDepressurize(gridAtmosphere, tile, cycleNum);
return;
}
}
}
if (tileCount > Atmospherics.MonstermosTileLimit)
{
for (var i = Atmospherics.MonstermosTileLimit; i < tileCount; i++)
{
//We unmark them. We shouldn't be pushing/pulling gases to/from them.
var otherTile = tiles[i];
if (otherTile == null)
continue;
tiles[i].MonstermosInfo.LastQueueCycle = 0;
}
tileCount = Atmospherics.MonstermosTileLimit;
}
var averageMoles = totalMoles / (tileCount);
var giverTiles = ArrayPool<TileAtmosphere>.Shared.Rent(tileCount);
var takerTiles = ArrayPool<TileAtmosphere>.Shared.Rent(tileCount);
var giverTilesLength = 0;
var takerTilesLength = 0;
for (var i = 0; i < tileCount; i++)
{
var otherTile = tiles[i];
otherTile.MonstermosInfo.LastCycle = cycleNum;
otherTile.MonstermosInfo.MoleDelta -= averageMoles;
if (otherTile.MonstermosInfo.MoleDelta > 0)
{
giverTiles[giverTilesLength++] = otherTile;
}
else
{
takerTiles[takerTilesLength++] = otherTile;
}
}
var logN = MathF.Log2(tileCount);
// Optimization - try to spread gases using an O(nlogn) algorithm that has a chance of not working first to avoid O(n^2)
if (giverTilesLength > logN && takerTilesLength > logN)
{
// Even if it fails, it will speed up the next part.
Array.Sort(tiles, 0, tileCount, _monstermosComparer);
for (var i = 0; i < tileCount; i++)
{
var otherTile = tiles[i];
otherTile.MonstermosInfo.FastDone = true;
if (!(otherTile.MonstermosInfo.MoleDelta > 0)) continue;
var eligibleDirections = AtmosDirection.Invalid;
var eligibleDirectionCount = 0;
for (var j = 0; j < Atmospherics.Directions; j++)
{
var direction = (AtmosDirection) (1 << j);
if (!otherTile.AdjacentBits.IsFlagSet(direction)) continue;
var tile2 = otherTile.AdjacentTiles[j];
// skip anything that isn't part of our current processing block.
if (tile2.MonstermosInfo.FastDone || tile2.MonstermosInfo.LastQueueCycle != queueCycle)
continue;
eligibleDirections |= direction;
eligibleDirectionCount++;
}
if (eligibleDirectionCount <= 0)
continue; // Oof we've painted ourselves into a corner. Bad luck. Next part will handle this.
var molesToMove = otherTile.MonstermosInfo.MoleDelta / eligibleDirectionCount;
for (var j = 0; j < Atmospherics.Directions; j++)
{
var direction = (AtmosDirection) (1 << j);
if (!eligibleDirections.IsFlagSet(direction)) continue;
AdjustEqMovement(otherTile, direction, molesToMove);
otherTile.MonstermosInfo.MoleDelta -= molesToMove;
otherTile.AdjacentTiles[j].MonstermosInfo.MoleDelta += molesToMove;
}
}
giverTilesLength = 0;
takerTilesLength = 0;
for (var i = 0; i < tileCount; i++)
{
var otherTile = tiles[i];
if (otherTile.MonstermosInfo.MoleDelta > 0)
{
giverTiles[giverTilesLength++] = otherTile;
}
else
{
takerTiles[takerTilesLength++] = otherTile;
}
}
}
// This is the part that can become O(n^2).
if (giverTilesLength < takerTilesLength)
{
// as an optimization, we choose one of two methods based on which list is smaller. We really want to avoid O(n^2) if we can.
var queue = ArrayPool<TileAtmosphere>.Shared.Rent(tileCount);
for (var j = 0; j < giverTilesLength; j++)
{
var giver = giverTiles[j];
giver.MonstermosInfo.CurrentTransferDirection = AtmosDirection.Invalid;
giver.MonstermosInfo.CurrentTransferAmount = 0;
var queueCycleSlow = ++gridAtmosphere.EqualizationQueueCycleControl;
var queueLength = 0;
queue[queueLength++] = giver;
giver.MonstermosInfo.LastSlowQueueCycle = queueCycleSlow;
for (var i = 0; i < queueLength; i++)
{
if (giver.MonstermosInfo.MoleDelta <= 0)
break; // We're done here now. Let's not do more work than needed.
var otherTile = queue[i];
for (var k = 0; k < Atmospherics.Directions; k++)
{
var direction = (AtmosDirection) (1 << k);
if (!otherTile.AdjacentBits.IsFlagSet(direction)) continue;
var otherTile2 = otherTile.AdjacentTiles[k];
if (giver.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.MonstermosInfo.LastSlowQueueCycle == queueCycleSlow) continue;
queue[queueLength++] = otherTile2;
otherTile2.MonstermosInfo.LastSlowQueueCycle = queueCycleSlow;
otherTile2.MonstermosInfo.CurrentTransferDirection = direction.GetOpposite();
otherTile2.MonstermosInfo.CurrentTransferAmount = 0;
if (otherTile2.MonstermosInfo.MoleDelta < 0)
{
// This tile needs gas. Let's give it to 'em.
if (-otherTile2.MonstermosInfo.MoleDelta > giver.MonstermosInfo.MoleDelta)
{
// We don't have enough gas!
otherTile2.MonstermosInfo.CurrentTransferAmount -= giver.MonstermosInfo.MoleDelta;
otherTile2.MonstermosInfo.MoleDelta += giver.MonstermosInfo.MoleDelta;
giver.MonstermosInfo.MoleDelta = 0;
}
else
{
// We have enough gas.
otherTile2.MonstermosInfo.CurrentTransferAmount += otherTile2.MonstermosInfo.MoleDelta;
giver.MonstermosInfo.MoleDelta += otherTile2.MonstermosInfo.MoleDelta;
otherTile2.MonstermosInfo.MoleDelta = 0;
}
}
}
}
// Putting this loop here helps make it O(n^2) over O(n^3)
for (var i = queueLength - 1; i >= 0; i--)
{
var otherTile = queue[i];
if (otherTile.MonstermosInfo.CurrentTransferAmount != 0 && otherTile.MonstermosInfo.CurrentTransferDirection != AtmosDirection.Invalid)
{
AdjustEqMovement(otherTile, otherTile.MonstermosInfo.CurrentTransferDirection, otherTile.MonstermosInfo.CurrentTransferAmount);
otherTile.AdjacentTiles[otherTile.MonstermosInfo.CurrentTransferDirection.ToIndex()]
.MonstermosInfo.CurrentTransferAmount += otherTile.MonstermosInfo.CurrentTransferAmount;
otherTile.MonstermosInfo.CurrentTransferAmount = 0;
}
}
}
ArrayPool<TileAtmosphere>.Shared.Return(queue);
}
else
{
var queue = ArrayPool<TileAtmosphere>.Shared.Rent(tileCount);
for (var j = 0; j < takerTilesLength; j++)
{
var taker = takerTiles[j];
taker.MonstermosInfo.CurrentTransferDirection = AtmosDirection.Invalid;
taker.MonstermosInfo.CurrentTransferAmount = 0;
var queueCycleSlow = ++gridAtmosphere.EqualizationQueueCycleControl;
var queueLength = 0;
queue[queueLength++] = taker;
taker.MonstermosInfo.LastSlowQueueCycle = queueCycleSlow;
for (var i = 0; i < queueLength; i++)
{
if (taker.MonstermosInfo.MoleDelta >= 0)
break; // We're done here now. Let's not do more work than needed.
var otherTile = queue[i];
for (var k = 0; k < Atmospherics.Directions; k++)
{
var direction = (AtmosDirection) (1 << k);
if (!otherTile.AdjacentBits.IsFlagSet(direction)) continue;
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 (otherTile2 == null || otherTile2.MonstermosInfo.LastQueueCycle != queueCycle) continue;
if (otherTile2.MonstermosInfo.LastSlowQueueCycle == queueCycleSlow) continue;
queue[queueLength++] = otherTile2;
otherTile2.MonstermosInfo.LastSlowQueueCycle = queueCycleSlow;
otherTile2.MonstermosInfo.CurrentTransferDirection = direction.GetOpposite();
otherTile2.MonstermosInfo.CurrentTransferAmount = 0;
if (otherTile2.MonstermosInfo.MoleDelta > 0)
{
// This tile has gas we can suck, so let's
if (otherTile2.MonstermosInfo.MoleDelta > -taker.MonstermosInfo.MoleDelta)
{
// They have enough gas
otherTile2.MonstermosInfo.CurrentTransferAmount -= taker.MonstermosInfo.MoleDelta;
otherTile2.MonstermosInfo.MoleDelta += taker.MonstermosInfo.MoleDelta;
taker.MonstermosInfo.MoleDelta = 0;
}
else
{
// They don't have enough gas!
otherTile2.MonstermosInfo.CurrentTransferAmount += otherTile2.MonstermosInfo.MoleDelta;
taker.MonstermosInfo.MoleDelta += otherTile2.MonstermosInfo.MoleDelta;
otherTile2.MonstermosInfo.MoleDelta = 0;
}
}
}
}
for (var i = queueLength - 1; i >= 0; i--)
{
var otherTile = queue[i];
if (otherTile.MonstermosInfo.CurrentTransferAmount == 0 || otherTile.MonstermosInfo.CurrentTransferDirection == AtmosDirection.Invalid)
continue;
AdjustEqMovement(otherTile, otherTile.MonstermosInfo.CurrentTransferDirection, otherTile.MonstermosInfo.CurrentTransferAmount);
otherTile.AdjacentTiles[otherTile.MonstermosInfo.CurrentTransferDirection.ToIndex()]
.MonstermosInfo.CurrentTransferAmount += otherTile.MonstermosInfo.CurrentTransferAmount;
otherTile.MonstermosInfo.CurrentTransferAmount = 0;
}
}
ArrayPool<TileAtmosphere>.Shared.Return(queue);
}
for (var i = 0; i < tileCount; i++)
{
var otherTile = tiles[i];
FinalizeEq(gridAtmosphere, otherTile);
}
for (var i = 0; i < tileCount; i++)
{
var otherTile = tiles[i];
for (var j = 0; j < Atmospherics.Directions; j++)
{
var direction = (AtmosDirection) (1 << j);
if (!otherTile.AdjacentBits.IsFlagSet(direction)) continue;
var otherTile2 = otherTile.AdjacentTiles[j];
if (otherTile2?.Air?.Compare(tile.Air) == GasMixture.GasCompareResult.NoExchange) continue;
gridAtmosphere.AddActiveTile(otherTile2);
break;
}
}
ArrayPool<TileAtmosphere>.Shared.Return(tiles);
ArrayPool<TileAtmosphere>.Shared.Return(giverTiles);
ArrayPool<TileAtmosphere>.Shared.Return(takerTiles);
}
public void ExplosivelyDepressurize(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, int cycleNum)
{
// Check if explosive depressurization is enabled and if the tile is valid.
if (!MonstermosDepressurization || tile.Air == null)
return;
const int limit = Atmospherics.MonstermosHardTileLimit;
var totalGasesRemoved = 0f;
var queueCycle = ++gridAtmosphere.EqualizationQueueCycleControl;
var tiles = ArrayPool<TileAtmosphere>.Shared.Rent(limit);
var spaceTiles = ArrayPool<TileAtmosphere>.Shared.Rent(limit);
var tileCount = 0;
var spaceTileCount = 0;
tiles[tileCount++] = tile;
tile.MonstermosInfo = new MonstermosInfo {LastQueueCycle = queueCycle};
for (var i = 0; i < tileCount; i++)
{
var otherTile = tiles[i];
otherTile.MonstermosInfo.LastCycle = cycleNum;
otherTile.MonstermosInfo.CurrentTransferDirection = AtmosDirection.Invalid;
if (otherTile.Air.Immutable)
{
spaceTiles[spaceTileCount++] = otherTile;
otherTile.PressureSpecificTarget = otherTile;
}
else
{
for (var j = 0; j < Atmospherics.Directions; j++)
{
var direction = (AtmosDirection) (1 << j);
if (!otherTile.AdjacentBits.IsFlagSet(direction)) continue;
var otherTile2 = otherTile.AdjacentTiles[j];
if (otherTile2.Air == null) continue;
if (otherTile2.MonstermosInfo.LastQueueCycle == queueCycle) continue;
ConsiderFirelocks(otherTile, otherTile2);
// The firelocks might have closed on us.
if (!otherTile.AdjacentBits.IsFlagSet(direction)) continue;
otherTile2.MonstermosInfo = new MonstermosInfo {LastQueueCycle = queueCycle};
tiles[tileCount++] = otherTile2;
}
}
if (tileCount >= limit || spaceTileCount >= limit)
break;
}
var queueCycleSlow = ++gridAtmosphere.EqualizationQueueCycleControl;
var progressionOrder = ArrayPool<TileAtmosphere>.Shared.Rent(limit * 2);
var progressionCount = 0;
for (var i = 0; i < spaceTileCount; i++)
{
var otherTile = spaceTiles[i];
progressionOrder[progressionCount++] = otherTile;
otherTile.MonstermosInfo.LastSlowQueueCycle = queueCycleSlow;
otherTile.MonstermosInfo.CurrentTransferDirection = AtmosDirection.Invalid;
}
for (var i = 0; i < progressionCount; i++)
{
var otherTile = progressionOrder[i];
for (var j = 0; j < Atmospherics.Directions; j++)
{
var direction = (AtmosDirection) (1 << j);
// TODO ATMOS This is a terrible hack that accounts for the mess that are space TileAtmospheres.
if (!otherTile.AdjacentBits.IsFlagSet(direction) && !otherTile.Air.Immutable) continue;
var tile2 = otherTile.AdjacentTiles[j];
if (tile2?.MonstermosInfo.LastQueueCycle != queueCycle) continue;
if (tile2.MonstermosInfo.LastSlowQueueCycle == queueCycleSlow) continue;
if(tile2.Air?.Immutable ?? false) continue;
tile2.MonstermosInfo.CurrentTransferDirection = direction.GetOpposite();
tile2.MonstermosInfo.CurrentTransferAmount = 0;
tile2.PressureSpecificTarget = otherTile.PressureSpecificTarget;
tile2.MonstermosInfo.LastSlowQueueCycle = queueCycleSlow;
progressionOrder[progressionCount++] = tile2;
}
}
for (var i = progressionCount - 1; i >= 0; i--)
{
var otherTile = progressionOrder[i];
if (otherTile.MonstermosInfo.CurrentTransferDirection == AtmosDirection.Invalid) continue;
gridAtmosphere.AddHighPressureDelta(otherTile);
gridAtmosphere.AddActiveTile(otherTile);
var otherTile2 = otherTile.AdjacentTiles[otherTile.MonstermosInfo.CurrentTransferDirection.ToIndex()];
if (otherTile2?.Air == null) continue;
var sum = otherTile2.Air.TotalMoles;
totalGasesRemoved += sum;
otherTile.MonstermosInfo.CurrentTransferAmount += sum;
otherTile2.MonstermosInfo.CurrentTransferAmount += otherTile.MonstermosInfo.CurrentTransferAmount;
otherTile.PressureDifference = otherTile.MonstermosInfo.CurrentTransferAmount;
otherTile.PressureDirection = otherTile.MonstermosInfo.CurrentTransferDirection;
if (otherTile2.MonstermosInfo.CurrentTransferDirection == AtmosDirection.Invalid)
{
otherTile2.PressureDifference = otherTile2.MonstermosInfo.CurrentTransferAmount;
otherTile2.PressureDirection = otherTile.MonstermosInfo.CurrentTransferDirection;
}
otherTile.Air.Clear();
otherTile.UpdateVisuals();
HandleDecompressionFloorRip(gridAtmosphere, otherTile, sum);
}
ArrayPool<TileAtmosphere>.Shared.Return(tiles);
ArrayPool<TileAtmosphere>.Shared.Return(spaceTiles);
ArrayPool<TileAtmosphere>.Shared.Return(progressionOrder);
}
private void ConsiderFirelocks(TileAtmosphere tile, TileAtmosphere other)
{
if (!_mapManager.TryGetGrid(tile.GridIndex, out var mapGrid))
return;
var reconsiderAdjacent = false;
foreach (var entity in mapGrid.GetAnchoredEntities(tile.GridIndices))
{
if (!ComponentManager.TryGetComponent(entity, out FirelockComponent firelock))
continue;
reconsiderAdjacent |= firelock.EmergencyPressureStop();
}
foreach (var entity in mapGrid.GetAnchoredEntities(other.GridIndices))
{
if (!ComponentManager.TryGetComponent(entity, out FirelockComponent firelock))
continue;
reconsiderAdjacent |= firelock.EmergencyPressureStop();
}
if (!reconsiderAdjacent)
return;
tile.UpdateAdjacent();
other.UpdateAdjacent();
}
public void FinalizeEq(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile)
{
Span<float> transferDirections = stackalloc float[Atmospherics.Directions];
var hasTransferDirs = false;
for (var i = 0; i < Atmospherics.Directions; i++)
{
var amount = tile.MonstermosInfo[i];
if (amount == 0) continue;
transferDirections[i] = amount;
tile.MonstermosInfo[i] = 0; // Set them to 0 to prevent infinite recursion.
hasTransferDirs = true;
}
if (!hasTransferDirs) return;
for(var i = 0; i < Atmospherics.Directions; i++)
{
var direction = (AtmosDirection) (1 << i);
if (!tile.AdjacentBits.IsFlagSet(direction)) continue;
var amount = transferDirections[i];
var otherTile = tile.AdjacentTiles[i];
if (otherTile?.Air == null) continue;
if (amount > 0)
{
if (tile.Air.TotalMoles < amount)
FinalizeEqNeighbors(gridAtmosphere, tile, transferDirections);
otherTile.MonstermosInfo[direction.GetOpposite()] = 0;
Merge(otherTile.Air, tile.Air.Remove(amount));
tile.UpdateVisuals();
otherTile.UpdateVisuals();
ConsiderPressureDifference(gridAtmosphere, tile, otherTile, amount);
}
}
}
private void FinalizeEqNeighbors(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, ReadOnlySpan<float> transferDirs)
{
for (var i = 0; i < Atmospherics.Directions; i++)
{
var direction = (AtmosDirection) (1 << i);
var amount = transferDirs[i];
if(amount < 0 && tile.AdjacentBits.IsFlagSet(direction))
FinalizeEq(gridAtmosphere, tile.AdjacentTiles[i]); // A bit of recursion if needed.
}
}
private void AdjustEqMovement(TileAtmosphere tile, AtmosDirection direction, float amount)
{
tile.MonstermosInfo[direction] += amount;
tile.AdjacentTiles[direction.ToIndex()].MonstermosInfo[direction.GetOpposite()] -= amount;
}
private void HandleDecompressionFloorRip(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, float sum)
{
var chance = MathHelper.Clamp(sum / 500, 0.005f, 0.5f);
if (sum > 20 && _robustRandom.Prob(chance))
gridAtmosphere.PryTile(tile.GridIndices);
}
private class TileAtmosphereComparer : IComparer<TileAtmosphere>
{
public int Compare(TileAtmosphere a, TileAtmosphere b)
{
if (a == null && b == null)
return 0;
if (a == null)
return -1;
if (b == null)
return 1;
return a.MonstermosInfo.MoleDelta.CompareTo(b.MonstermosInfo.MoleDelta);
}
}
}
}

View File

@@ -33,7 +33,7 @@ namespace Content.Server.Atmos.EntitySystems
var number = 0;
while (atmosphere.CurrentRunTiles.TryDequeue(out var tile))
{
tile.EqualizePressureInZone(this, atmosphere.UpdateCounter);
EqualizePressureInZone(atmosphere, tile, 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(this, atmosphere.UpdateCounter, SpaceWind);
ProcessCell(atmosphere, tile, atmosphere.UpdateCounter, SpaceWind);
if (number++ < LagCheckIterations) continue;
number = 0;
@@ -106,7 +106,7 @@ namespace Content.Server.Atmos.EntitySystems
var number = 0;
while (atmosphere.CurrentRunTiles.TryDequeue(out var tile))
{
tile.HighPressureMovements();
HighPressureMovements(atmosphere, tile);
tile.PressureDifference = 0f;
tile.PressureSpecificTarget = null;
atmosphere.HighPressureDelta.Remove(tile);
@@ -131,7 +131,7 @@ namespace Content.Server.Atmos.EntitySystems
var number = 0;
while (atmosphere.CurrentRunTiles.TryDequeue(out var hotspot))
{
hotspot.ProcessHotspot();
ProcessHotspot(atmosphere, hotspot);
if (number++ < LagCheckIterations) continue;
number = 0;
@@ -153,7 +153,7 @@ namespace Content.Server.Atmos.EntitySystems
var number = 0;
while (atmosphere.CurrentRunTiles.TryDequeue(out var superconductivity))
{
superconductivity.Superconduct(this);
Superconduct(atmosphere, superconductivity);
if (number++ < LagCheckIterations) continue;
number = 0;

View File

@@ -0,0 +1,157 @@
using System;
using Content.Server.Atmos.Components;
using Content.Shared.Atmos;
namespace Content.Server.Atmos.EntitySystems
{
public partial class AtmosphereSystem
{
private void Superconduct(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile)
{
var directions = ConductivityDirections(gridAtmosphere, tile);
for(var i = 0; i < Atmospherics.Directions; i++)
{
var direction = (AtmosDirection) (1 << i);
if (!directions.IsFlagSet(direction)) continue;
var adjacent = tile.AdjacentTiles[direction.ToIndex()];
// TODO ATMOS handle adjacent being null.
if (adjacent == null || adjacent.ThermalConductivity == 0f)
continue;
if(adjacent.ArchivedCycle < gridAtmosphere.UpdateCounter)
Archive(adjacent, gridAtmosphere.UpdateCounter);
NeighborConductWithSource(gridAtmosphere, adjacent, tile);
ConsiderSuperconductivity(gridAtmosphere, adjacent);
}
RadiateToSpace(tile);
FinishSuperconduction(gridAtmosphere, tile);
}
private AtmosDirection ConductivityDirections(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile)
{
if(tile.Air == null)
{
if(tile.ArchivedCycle < gridAtmosphere.UpdateCounter)
Archive(tile, gridAtmosphere.UpdateCounter);
return AtmosDirection.All;
}
// TODO ATMOS check if this is correct
return AtmosDirection.All;
}
public bool ConsiderSuperconductivity(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile)
{
if (tile.ThermalConductivity == 0f)
return false;
gridAtmosphere.AddSuperconductivityTile(tile);
return true;
}
public bool ConsiderSuperconductivity(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, bool starting)
{
if (tile.Air == null || tile.Air.Temperature < (starting
? Atmospherics.MinimumTemperatureStartSuperConduction
: Atmospherics.MinimumTemperatureForSuperconduction))
return false;
return !(gridAtmosphere.AtmosphereSystem.GetHeatCapacity(tile.Air) < Atmospherics.MCellWithRatio)
&& ConsiderSuperconductivity(gridAtmosphere, tile);
}
public void FinishSuperconduction(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile)
{
// Conduct with air on my tile if I have it
if (tile.Air != null)
{
tile.Temperature = TemperatureShare(tile.Air, tile.ThermalConductivity, tile.Temperature, tile.HeatCapacity);
}
FinishSuperconduction(gridAtmosphere, tile, tile.Air?.Temperature ?? tile.Temperature);
}
public void FinishSuperconduction(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, float temperature)
{
// Make sure it's still hot enough to continue conducting.
if (temperature < Atmospherics.MinimumTemperatureForSuperconduction)
{
gridAtmosphere.RemoveSuperconductivityTile(tile);
}
}
public void NeighborConductWithSource(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, TileAtmosphere other)
{
if (tile.Air == null)
{
if (other.Tile != null)
{
TemperatureShareOpenToSolid(other, tile);
}
else
{
TemperatureShareMutualSolid(other, tile, tile.ThermalConductivity);
}
// TODO ATMOS: tile.TemperatureExpose(null, tile.Temperature, gridAtmosphere.GetVolumeForCells(1));
return;
}
if (other.Air != null)
{
TemperatureShare(other.Air, tile.Air, Atmospherics.WindowHeatTransferCoefficient);
}
else
{
TemperatureShareOpenToSolid(tile, other);
}
gridAtmosphere.AddActiveTile(tile);
}
private void TemperatureShareOpenToSolid(TileAtmosphere tile, TileAtmosphere other)
{
if (tile.Air == null)
return;
other.Temperature = TemperatureShare(tile.Air, other.ThermalConductivity, other.Temperature, other.HeatCapacity);
}
private void TemperatureShareMutualSolid(TileAtmosphere tile, TileAtmosphere other, float conductionCoefficient)
{
var deltaTemperature = (tile.TemperatureArchived - other.TemperatureArchived);
if (MathF.Abs(deltaTemperature) > Atmospherics.MinimumTemperatureDeltaToConsider
&& tile.HeatCapacity != 0f && other.HeatCapacity != 0f)
{
var heat = conductionCoefficient * deltaTemperature *
(tile.HeatCapacity * other.HeatCapacity / (tile.HeatCapacity + other.HeatCapacity));
tile.Temperature -= heat / tile.HeatCapacity;
other.Temperature += heat / other.HeatCapacity;
}
}
public void RadiateToSpace(TileAtmosphere tile)
{
// 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);
if ((tile.HeatCapacity > 0) && (MathF.Abs(deltaTemperature) > Atmospherics.MinimumTemperatureDeltaToConsider))
{
var heat = tile.ThermalConductivity * deltaTemperature * (tile.HeatCapacity *
Atmospherics.HeatCapacityVacuum / (tile.HeatCapacity + Atmospherics.HeatCapacityVacuum));
tile.Temperature -= heat;
}
}
}
}
}

View File

@@ -4,7 +4,7 @@ using Robust.Shared.ViewVariables;
namespace Content.Server.Atmos
{
public struct TileAtmosInfo
public struct MonstermosInfo
{
[ViewVariables]
public int LastCycle;
@@ -30,6 +30,15 @@ namespace Content.Server.Atmos
[ViewVariables]
public float TransferDirectionSouth;
[ViewVariables]
public float CurrentTransferAmount;
[ViewVariables]
public AtmosDirection CurrentTransferDirection;
[ViewVariables]
public bool FastDone;
public float this[AtmosDirection direction]
{
get =>
@@ -69,13 +78,5 @@ namespace Content.Server.Atmos
get => this[(AtmosDirection) (1 << index)];
set => this[(AtmosDirection) (1 << index)] = value;
}
[ViewVariables]
public float CurrentTransferAmount;
public AtmosDirection CurrentTransferDirection;
[ViewVariables]
public bool FastDone;
}
}

View File

@@ -73,7 +73,7 @@ namespace Content.Server.Atmos.Reactions
temperature = mixture.Temperature;
if (temperature > Atmospherics.FireMinimumTemperatureToExist)
{
location.HotspotExpose(temperature, mixture.Volume);
atmosphereSystem.HotspotExpose(location.GridIndex, location.GridIndices, temperature, mixture.Volume);
foreach (var entity in location.GridIndices.GetEntitiesInTileFast(location.GridIndex))
{
@@ -83,7 +83,7 @@ namespace Content.Server.Atmos.Reactions
}
}
location.TemperatureExpose(mixture, temperature, mixture.Volume);
// TODO ATMOS: location.TemperatureExpose(mixture, temperature, mixture.Volume);
}
}

View File

@@ -63,7 +63,7 @@ namespace Content.Server.Atmos.Reactions
temperature = mixture.Temperature;
if (temperature > Atmospherics.FireMinimumTemperatureToExist)
{
location.HotspotExpose(temperature, mixture.Volume);
atmosphereSystem.HotspotExpose(location.GridIndex, location.GridIndices, temperature, mixture.Volume);
foreach (var entity in location.GridIndices.GetEntitiesInTileFast(location.GridIndex))
{
@@ -73,7 +73,7 @@ namespace Content.Server.Atmos.Reactions
}
}
location.TemperatureExpose(mixture, temperature, mixture.Volume);
// TODO ATMOS: location.TemperatureExpose(mixture, temperature, mixture.Volume);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -141,14 +141,14 @@ namespace Content.Shared.Atmos
#endregion
/// <summary>
/// Hard limit for tile equalization.
/// Hard limit for zone-based tile equalization.
/// </summary>
public const int ZumosHardTileLimit = 2000;
public const int MonstermosHardTileLimit = 2000;
/// <summary>
/// Limit for zone-based tile equalization.
/// </summary>
public const int ZumosTileLimit = 200;
public const int MonstermosTileLimit = 200;
/// <summary>
/// Total number of gases. Increase this if you want to add more!

View File

@@ -243,12 +243,25 @@ namespace Content.Shared.CCVar
public static readonly CVarDef<bool> SpaceWind =
CVarDef.Create("atmos.space_wind", true, CVar.SERVERONLY);
/// <summary>
/// The sound that plays when space wind occurs.
/// </summary>
public static readonly CVarDef<string> SpaceWindSound =
CVarDef.Create("atmos.space_wind_sound", "/Audio/Effects/space_wind.ogg", CVar.SERVERONLY);
/// <summary>
/// Whether monstermos tile equalization is enabled.
/// </summary>
public static readonly CVarDef<bool> MonstermosEqualization =
CVarDef.Create("atmos.monstermos_equalization", true, CVar.SERVERONLY);
/// <summary>
/// Whether monstermos explosive depressurization is enabled.
/// Needs <see cref="MonstermosEqualization"/> to be enabled to work.
/// </summary>
public static readonly CVarDef<bool> MonstermosDepressurization =
CVarDef.Create<bool>("atmos.monstermos_depressurization", true, CVar.SERVERONLY);
/// <summary>
/// Whether atmos superconduction is enabled.
/// </summary>