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:
committed by
GitHub
parent
e1fdd902bb
commit
fcafa8f439
@@ -2,6 +2,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Server.Alert;
|
using Content.Server.Alert;
|
||||||
|
using Content.Server.Atmos.EntitySystems;
|
||||||
using Content.Server.Stunnable.Components;
|
using Content.Server.Stunnable.Components;
|
||||||
using Content.Server.Temperature.Components;
|
using Content.Server.Temperature.Components;
|
||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
@@ -122,7 +123,7 @@ namespace Content.Server.Atmos.Components
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tile.HotspotExpose(700, 50, true);
|
EntitySystem.Get<AtmosphereSystem>().HotspotExpose(tile.GridIndex, tile.GridIndices, 700f, 50f, true);
|
||||||
|
|
||||||
var physics = Owner.GetComponent<IPhysBody>();
|
var physics = Owner.GetComponent<IPhysBody>();
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ namespace Content.Server.Atmos.Components
|
|||||||
[Dependency] private IServerEntityManager _serverEntityManager = default!;
|
[Dependency] private IServerEntityManager _serverEntityManager = default!;
|
||||||
[Dependency] private IGameTiming _gameTiming = default!;
|
[Dependency] private IGameTiming _gameTiming = default!;
|
||||||
|
|
||||||
public GridTileLookupSystem GridTileLookupSystem { get; private set; } = default!;
|
|
||||||
internal GasTileOverlaySystem GasTileOverlaySystem { get; private set; } = default!;
|
internal GasTileOverlaySystem GasTileOverlaySystem { get; private set; } = default!;
|
||||||
public AtmosphereSystem AtmosphereSystem { 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>();
|
GasTileOverlaySystem = EntitySystem.Get<GasTileOverlaySystem>();
|
||||||
AtmosphereSystem = EntitySystem.Get<AtmosphereSystem>();
|
AtmosphereSystem = EntitySystem.Get<AtmosphereSystem>();
|
||||||
|
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
{
|
{
|
||||||
gases[i] = tile.Air.GetMoles(i);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
public partial class AtmosphereSystem
|
public partial class AtmosphereSystem
|
||||||
{
|
{
|
||||||
public bool SpaceWind { get; private set; }
|
public bool SpaceWind { get; private set; }
|
||||||
|
public string? SpaceWindSound { get; private set; }
|
||||||
public bool MonstermosEqualization { get; private set; }
|
public bool MonstermosEqualization { get; private set; }
|
||||||
|
public bool MonstermosDepressurization { get; private set; }
|
||||||
public bool Superconduction { get; private set; }
|
public bool Superconduction { get; private set; }
|
||||||
public bool ExcitedGroupsSpaceIsAllConsuming { get; private set; }
|
public bool ExcitedGroupsSpaceIsAllConsuming { get; private set; }
|
||||||
public float AtmosMaxProcessTime { get; private set; }
|
public float AtmosMaxProcessTime { get; private set; }
|
||||||
@@ -15,7 +17,9 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
private void InitializeCVars()
|
private void InitializeCVars()
|
||||||
{
|
{
|
||||||
_cfg.OnValueChanged(CCVars.SpaceWind, value => SpaceWind = value, true);
|
_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.MonstermosEqualization, value => MonstermosEqualization = value, true);
|
||||||
|
_cfg.OnValueChanged(CCVars.MonstermosDepressurization, value => MonstermosDepressurization = value, true);
|
||||||
_cfg.OnValueChanged(CCVars.Superconduction, value => Superconduction = value, true);
|
_cfg.OnValueChanged(CCVars.Superconduction, value => Superconduction = value, true);
|
||||||
_cfg.OnValueChanged(CCVars.AtmosMaxProcessTime, value => AtmosMaxProcessTime = value, true);
|
_cfg.OnValueChanged(CCVars.AtmosMaxProcessTime, value => AtmosMaxProcessTime = value, true);
|
||||||
_cfg.OnValueChanged(CCVars.AtmosTickRate, value => AtmosTickRate = value, true);
|
_cfg.OnValueChanged(CCVars.AtmosTickRate, value => AtmosTickRate = value, true);
|
||||||
|
|||||||
@@ -163,15 +163,15 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
|
|
||||||
if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere))
|
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;
|
continue;
|
||||||
|
|
||||||
if(invalidate)
|
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)!;
|
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];
|
var adjacentTile = tileAtmos.AdjacentTiles[i];
|
||||||
// TileAtmosphere has nullable disabled, so just in case...
|
// TileAtmosphere has nullable disabled, so just in case...
|
||||||
@@ -634,7 +634,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
{
|
{
|
||||||
var tileAtmos = gridAtmosphere.GetTile(tile)!;
|
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];
|
var adjacentTile = tileAtmos.AdjacentTiles[i];
|
||||||
|
|
||||||
@@ -651,7 +651,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (invalidate)
|
if (invalidate)
|
||||||
adjacentTile.Invalidate();
|
gridAtmosphere.Invalidate(adjacentTile.GridIndices);
|
||||||
|
|
||||||
yield return adjacentTile.Air;
|
yield return adjacentTile.Air;
|
||||||
}
|
}
|
||||||
@@ -747,7 +747,12 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
|
|
||||||
if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere))
|
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);
|
gridAtmosphere.Invalidate(tile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
150
Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs
Normal file
150
Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
135
Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs
Normal file
135
Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,7 +33,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
var number = 0;
|
var number = 0;
|
||||||
while (atmosphere.CurrentRunTiles.TryDequeue(out var tile))
|
while (atmosphere.CurrentRunTiles.TryDequeue(out var tile))
|
||||||
{
|
{
|
||||||
tile.EqualizePressureInZone(this, atmosphere.UpdateCounter);
|
EqualizePressureInZone(atmosphere, tile, atmosphere.UpdateCounter);
|
||||||
|
|
||||||
if (number++ < LagCheckIterations) continue;
|
if (number++ < LagCheckIterations) continue;
|
||||||
number = 0;
|
number = 0;
|
||||||
@@ -55,7 +55,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
var number = 0;
|
var number = 0;
|
||||||
while (atmosphere.CurrentRunTiles.TryDequeue(out var tile))
|
while (atmosphere.CurrentRunTiles.TryDequeue(out var tile))
|
||||||
{
|
{
|
||||||
tile.ProcessCell(this, atmosphere.UpdateCounter, SpaceWind);
|
ProcessCell(atmosphere, tile, atmosphere.UpdateCounter, SpaceWind);
|
||||||
|
|
||||||
if (number++ < LagCheckIterations) continue;
|
if (number++ < LagCheckIterations) continue;
|
||||||
number = 0;
|
number = 0;
|
||||||
@@ -106,7 +106,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
var number = 0;
|
var number = 0;
|
||||||
while (atmosphere.CurrentRunTiles.TryDequeue(out var tile))
|
while (atmosphere.CurrentRunTiles.TryDequeue(out var tile))
|
||||||
{
|
{
|
||||||
tile.HighPressureMovements();
|
HighPressureMovements(atmosphere, tile);
|
||||||
tile.PressureDifference = 0f;
|
tile.PressureDifference = 0f;
|
||||||
tile.PressureSpecificTarget = null;
|
tile.PressureSpecificTarget = null;
|
||||||
atmosphere.HighPressureDelta.Remove(tile);
|
atmosphere.HighPressureDelta.Remove(tile);
|
||||||
@@ -131,7 +131,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
var number = 0;
|
var number = 0;
|
||||||
while (atmosphere.CurrentRunTiles.TryDequeue(out var hotspot))
|
while (atmosphere.CurrentRunTiles.TryDequeue(out var hotspot))
|
||||||
{
|
{
|
||||||
hotspot.ProcessHotspot();
|
ProcessHotspot(atmosphere, hotspot);
|
||||||
|
|
||||||
if (number++ < LagCheckIterations) continue;
|
if (number++ < LagCheckIterations) continue;
|
||||||
number = 0;
|
number = 0;
|
||||||
@@ -153,7 +153,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
var number = 0;
|
var number = 0;
|
||||||
while (atmosphere.CurrentRunTiles.TryDequeue(out var superconductivity))
|
while (atmosphere.CurrentRunTiles.TryDequeue(out var superconductivity))
|
||||||
{
|
{
|
||||||
superconductivity.Superconduct(this);
|
Superconduct(atmosphere, superconductivity);
|
||||||
|
|
||||||
if (number++ < LagCheckIterations) continue;
|
if (number++ < LagCheckIterations) continue;
|
||||||
number = 0;
|
number = 0;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@ using Robust.Shared.ViewVariables;
|
|||||||
|
|
||||||
namespace Content.Server.Atmos
|
namespace Content.Server.Atmos
|
||||||
{
|
{
|
||||||
public struct TileAtmosInfo
|
public struct MonstermosInfo
|
||||||
{
|
{
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public int LastCycle;
|
public int LastCycle;
|
||||||
@@ -30,6 +30,15 @@ namespace Content.Server.Atmos
|
|||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public float TransferDirectionSouth;
|
public float TransferDirectionSouth;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public float CurrentTransferAmount;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public AtmosDirection CurrentTransferDirection;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public bool FastDone;
|
||||||
|
|
||||||
public float this[AtmosDirection direction]
|
public float this[AtmosDirection direction]
|
||||||
{
|
{
|
||||||
get =>
|
get =>
|
||||||
@@ -69,13 +78,5 @@ namespace Content.Server.Atmos
|
|||||||
get => this[(AtmosDirection) (1 << index)];
|
get => this[(AtmosDirection) (1 << index)];
|
||||||
set => this[(AtmosDirection) (1 << index)] = value;
|
set => this[(AtmosDirection) (1 << index)] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
public float CurrentTransferAmount;
|
|
||||||
|
|
||||||
public AtmosDirection CurrentTransferDirection;
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
public bool FastDone;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,7 +73,7 @@ namespace Content.Server.Atmos.Reactions
|
|||||||
temperature = mixture.Temperature;
|
temperature = mixture.Temperature;
|
||||||
if (temperature > Atmospherics.FireMinimumTemperatureToExist)
|
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))
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ namespace Content.Server.Atmos.Reactions
|
|||||||
temperature = mixture.Temperature;
|
temperature = mixture.Temperature;
|
||||||
if (temperature > Atmospherics.FireMinimumTemperatureToExist)
|
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))
|
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
@@ -141,14 +141,14 @@ namespace Content.Shared.Atmos
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Hard limit for tile equalization.
|
/// Hard limit for zone-based tile equalization.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int ZumosHardTileLimit = 2000;
|
public const int MonstermosHardTileLimit = 2000;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Limit for zone-based tile equalization.
|
/// Limit for zone-based tile equalization.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int ZumosTileLimit = 200;
|
public const int MonstermosTileLimit = 200;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Total number of gases. Increase this if you want to add more!
|
/// Total number of gases. Increase this if you want to add more!
|
||||||
|
|||||||
@@ -243,12 +243,25 @@ namespace Content.Shared.CCVar
|
|||||||
public static readonly CVarDef<bool> SpaceWind =
|
public static readonly CVarDef<bool> SpaceWind =
|
||||||
CVarDef.Create("atmos.space_wind", true, CVar.SERVERONLY);
|
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>
|
/// <summary>
|
||||||
/// Whether monstermos tile equalization is enabled.
|
/// Whether monstermos tile equalization is enabled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly CVarDef<bool> MonstermosEqualization =
|
public static readonly CVarDef<bool> MonstermosEqualization =
|
||||||
CVarDef.Create("atmos.monstermos_equalization", true, CVar.SERVERONLY);
|
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>
|
/// <summary>
|
||||||
/// Whether atmos superconduction is enabled.
|
/// Whether atmos superconduction is enabled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user