ECS Atmos Part 1: Move GridAtmosphere updating and processing to AtmosphereSystem.Processing (#4206)

This commit is contained in:
Vera Aguilera Puerto
2021-06-22 10:28:15 +02:00
committed by GitHub
parent f2816e8081
commit 3f28a4d784
6 changed files with 418 additions and 489 deletions

View File

@@ -40,16 +40,10 @@ namespace Content.Server.Atmos.Components
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!;
/// <summary>
/// Check current execution time every n instances processed.
/// </summary>
private const int LagCheckIterations = 30;
public override string Name => "GridAtmosphere"; public override string Name => "GridAtmosphere";
private bool _paused; public bool ProcessingPaused { get; set; } = false;
private float _timer; public float Timer { get; set; }
private Stopwatch _stopwatch = new();
private GridId _gridId; private GridId _gridId;
[ComponentDependency] private IMapGridComponent? _mapGridComponent; [ComponentDependency] private IMapGridComponent? _mapGridComponent;
@@ -57,113 +51,74 @@ namespace Content.Server.Atmos.Components
public virtual bool Simulated => true; public virtual bool Simulated => true;
[ViewVariables] [ViewVariables]
public int UpdateCounter { get; private set; } = 0; public int UpdateCounter { get; set; } = 0;
[ViewVariables] [ViewVariables]
private double _tileEqualizeLastProcess; public readonly HashSet<ExcitedGroup> ExcitedGroups = new(1000);
[ViewVariables] [ViewVariables]
private readonly HashSet<ExcitedGroup> _excitedGroups = new(1000); public int ExcitedGroupCount => ExcitedGroups.Count;
[ViewVariables]
private int ExcitedGroupCount => _excitedGroups.Count;
[ViewVariables]
private double _excitedGroupLastProcess;
[DataField("uniqueMixes")] [DataField("uniqueMixes")]
private List<GasMixture>? _uniqueMixes; public List<GasMixture>? UniqueMixes;
[DataField("tiles")] [DataField("tiles")]
private Dictionary<Vector2i, int>? _tiles; public Dictionary<Vector2i, int>? TilesUniqueMixes;
[ViewVariables] [ViewVariables]
protected readonly Dictionary<Vector2i, TileAtmosphere> Tiles = new(1000); public readonly Dictionary<Vector2i, TileAtmosphere> Tiles = new(1000);
[ViewVariables] [ViewVariables]
private readonly HashSet<TileAtmosphere> _activeTiles = new(1000); public readonly HashSet<TileAtmosphere> ActiveTiles = new(1000);
[ViewVariables] [ViewVariables]
private int ActiveTilesCount => _activeTiles.Count; public int ActiveTilesCount => ActiveTiles.Count;
[ViewVariables] [ViewVariables]
private double _activeTilesLastProcess; public readonly HashSet<TileAtmosphere> HotspotTiles = new(1000);
[ViewVariables] [ViewVariables]
private readonly HashSet<TileAtmosphere> _hotspotTiles = new(1000); public int HotspotTilesCount => HotspotTiles.Count;
[ViewVariables] [ViewVariables]
private int HotspotTilesCount => _hotspotTiles.Count; public readonly HashSet<TileAtmosphere> SuperconductivityTiles = new(1000);
[ViewVariables] [ViewVariables]
private double _hotspotsLastProcess; public int SuperconductivityTilesCount => SuperconductivityTiles.Count;
[ViewVariables] [ViewVariables]
private readonly HashSet<TileAtmosphere> _superconductivityTiles = new(1000); public readonly HashSet<Vector2i> InvalidatedCoords = new(1000);
[ViewVariables] [ViewVariables]
private int SuperconductivityTilesCount => _superconductivityTiles.Count; public HashSet<TileAtmosphere> HighPressureDelta = new(1000);
[ViewVariables] [ViewVariables]
private double _superconductivityLastProcess; public int HighPressureDeltaCount => HighPressureDelta.Count;
[ViewVariables] [ViewVariables]
private readonly HashSet<Vector2i> _invalidatedCoords = new(1000); public readonly HashSet<IPipeNet> PipeNets = new();
[ViewVariables] [ViewVariables]
private int InvalidatedCoordsCount => _invalidatedCoords.Count; public readonly HashSet<AtmosDeviceComponent> AtmosDevices = new();
[ViewVariables] [ViewVariables]
private HashSet<TileAtmosphere> _highPressureDelta = new(1000); public Queue<TileAtmosphere> CurrentRunTiles = new();
[ViewVariables] [ViewVariables]
private int HighPressureDeltaCount => _highPressureDelta.Count; public Queue<ExcitedGroup> CurrentRunExcitedGroups = new();
[ViewVariables] [ViewVariables]
private double _highPressureDeltaLastProcess; public Queue<IPipeNet> CurrentRunPipeNet = new();
[ViewVariables] [ViewVariables]
private readonly HashSet<IPipeNet> _pipeNets = new(); public Queue<AtmosDeviceComponent> CurrentRunAtmosDevices = new();
[ViewVariables] [ViewVariables]
private double _pipeNetLastProcess; public AtmosphereProcessingState State { get; set; } = AtmosphereProcessingState.TileEqualize;
[ViewVariables]
private readonly HashSet<AtmosDeviceComponent> _atmosDevices = new();
[ViewVariables]
private double _atmosDevicesLastProcess;
[ViewVariables]
private Queue<TileAtmosphere> _currentRunTiles = new();
[ViewVariables]
private Queue<ExcitedGroup> _currentRunExcitedGroups = new();
[ViewVariables]
private Queue<IPipeNet> _currentRunPipeNet = new();
[ViewVariables]
private Queue<AtmosDeviceComponent> _currentRunAtmosDevices = new();
[ViewVariables]
private ProcessState _state = ProcessState.TileEqualize;
public GridAtmosphereComponent() public GridAtmosphereComponent()
{ {
_paused = false; ProcessingPaused = false;
}
private enum ProcessState
{
TileEqualize,
ActiveTiles,
ExcitedGroups,
HighPressureDelta,
Hotspots,
Superconductivity,
PipeNet,
AtmosDevices,
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -199,8 +154,8 @@ namespace Content.Server.Atmos.Components
if (uniqueMixes.Count == 0) uniqueMixes = null; if (uniqueMixes.Count == 0) uniqueMixes = null;
if (tiles.Count == 0) tiles = null; if (tiles.Count == 0) tiles = null;
_uniqueMixes = uniqueMixes; UniqueMixes = uniqueMixes;
_tiles = tiles; TilesUniqueMixes = tiles;
} }
protected override void Initialize() protected override void Initialize()
@@ -209,13 +164,13 @@ namespace Content.Server.Atmos.Components
Tiles.Clear(); Tiles.Clear();
if (_tiles != null && Owner.TryGetComponent(out IMapGridComponent? mapGrid)) if (TilesUniqueMixes != null && Owner.TryGetComponent(out IMapGridComponent? mapGrid))
{ {
foreach (var (indices, mix) in _tiles) foreach (var (indices, mix) in TilesUniqueMixes)
{ {
try try
{ {
Tiles.Add(indices, new TileAtmosphere(this, mapGrid.GridIndex, indices, (GasMixture) _uniqueMixes![mix].Clone())); Tiles.Add(indices, new TileAtmosphere(this, mapGrid.GridIndex, indices, (GasMixture) UniqueMixes![mix].Clone()));
} }
catch (ArgumentOutOfRangeException) catch (ArgumentOutOfRangeException)
{ {
@@ -264,12 +219,12 @@ namespace Content.Server.Atmos.Components
/// <inheritdoc /> /// <inheritdoc />
public virtual void Invalidate(Vector2i indices) public virtual void Invalidate(Vector2i indices)
{ {
_invalidatedCoords.Add(indices); InvalidatedCoords.Add(indices);
} }
protected virtual void Revalidate() public virtual void Revalidate()
{ {
foreach (var indices in _invalidatedCoords) foreach (var indices in InvalidatedCoords)
{ {
var tile = GetTile(indices); var tile = GetTile(indices);
@@ -341,7 +296,7 @@ namespace Content.Server.Atmos.Components
} }
} }
_invalidatedCoords.Clear(); InvalidatedCoords.Clear();
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -376,14 +331,14 @@ namespace Content.Server.Atmos.Components
{ {
if (tile?.GridIndex != _gridId || tile.Air == null) return; if (tile?.GridIndex != _gridId || tile.Air == null) return;
tile.Excited = true; tile.Excited = true;
_activeTiles.Add(tile); ActiveTiles.Add(tile);
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void RemoveActiveTile(TileAtmosphere tile, bool disposeGroup = true) public virtual void RemoveActiveTile(TileAtmosphere tile, bool disposeGroup = true)
{ {
_activeTiles.Remove(tile); ActiveTiles.Remove(tile);
tile.Excited = false; tile.Excited = false;
if(disposeGroup) if(disposeGroup)
tile.ExcitedGroup?.Dispose(); tile.ExcitedGroup?.Dispose();
@@ -396,25 +351,25 @@ namespace Content.Server.Atmos.Components
public virtual void AddHotspotTile(TileAtmosphere tile) public virtual void AddHotspotTile(TileAtmosphere tile)
{ {
if (tile?.GridIndex != _gridId || tile?.Air == null) return; if (tile?.GridIndex != _gridId || tile?.Air == null) return;
_hotspotTiles.Add(tile); HotspotTiles.Add(tile);
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void RemoveHotspotTile(TileAtmosphere tile) public virtual void RemoveHotspotTile(TileAtmosphere tile)
{ {
_hotspotTiles.Remove(tile); HotspotTiles.Remove(tile);
} }
public virtual void AddSuperconductivityTile(TileAtmosphere tile) public virtual void AddSuperconductivityTile(TileAtmosphere tile)
{ {
if (tile?.GridIndex != _gridId || !AtmosphereSystem.Superconduction) return; if (tile?.GridIndex != _gridId || !AtmosphereSystem.Superconduction) return;
_superconductivityTiles.Add(tile); SuperconductivityTiles.Add(tile);
} }
public virtual void RemoveSuperconductivityTile(TileAtmosphere tile) public virtual void RemoveSuperconductivityTile(TileAtmosphere tile)
{ {
_superconductivityTiles.Remove(tile); SuperconductivityTiles.Remove(tile);
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -422,48 +377,48 @@ namespace Content.Server.Atmos.Components
public virtual void AddHighPressureDelta(TileAtmosphere tile) public virtual void AddHighPressureDelta(TileAtmosphere tile)
{ {
if (tile.GridIndex != _gridId) return; if (tile.GridIndex != _gridId) return;
_highPressureDelta.Add(tile); HighPressureDelta.Add(tile);
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual bool HasHighPressureDelta(TileAtmosphere tile) public virtual bool HasHighPressureDelta(TileAtmosphere tile)
{ {
return _highPressureDelta.Contains(tile); return HighPressureDelta.Contains(tile);
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void AddExcitedGroup(ExcitedGroup excitedGroup) public virtual void AddExcitedGroup(ExcitedGroup excitedGroup)
{ {
_excitedGroups.Add(excitedGroup); ExcitedGroups.Add(excitedGroup);
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void RemoveExcitedGroup(ExcitedGroup excitedGroup) public virtual void RemoveExcitedGroup(ExcitedGroup excitedGroup)
{ {
_excitedGroups.Remove(excitedGroup); ExcitedGroups.Remove(excitedGroup);
} }
public virtual void AddPipeNet(IPipeNet pipeNet) public virtual void AddPipeNet(IPipeNet pipeNet)
{ {
_pipeNets.Add(pipeNet); PipeNets.Add(pipeNet);
} }
public virtual void RemovePipeNet(IPipeNet pipeNet) public virtual void RemovePipeNet(IPipeNet pipeNet)
{ {
_pipeNets.Remove(pipeNet); PipeNets.Remove(pipeNet);
} }
public virtual void AddAtmosDevice(AtmosDeviceComponent atmosDevice) public virtual void AddAtmosDevice(AtmosDeviceComponent atmosDevice)
{ {
_atmosDevices.Add(atmosDevice); AtmosDevices.Add(atmosDevice);
} }
public virtual void RemoveAtmosDevice(AtmosDeviceComponent atmosDevice) public virtual void RemoveAtmosDevice(AtmosDeviceComponent atmosDevice)
{ {
_atmosDevices.Remove(atmosDevice); AtmosDevices.Remove(atmosDevice);
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -545,349 +500,6 @@ namespace Content.Server.Atmos.Components
return _mapGridComponent.Grid.TileSize * cellCount * Atmospherics.CellVolume; return _mapGridComponent.Grid.TileSize * cellCount * Atmospherics.CellVolume;
} }
/// <inheritdoc />
public virtual void Update(float frameTime)
{
_timer += frameTime;
var atmosTime = 1f/AtmosphereSystem.AtmosTickRate;
if (_invalidatedCoords.Count != 0)
Revalidate();
if (_timer < atmosTime)
return;
// We subtract it so it takes lost time into account.
_timer -= atmosTime;
var maxProcessTime = AtmosphereSystem.AtmosMaxProcessTime;
switch (_state)
{
case ProcessState.TileEqualize:
if (!ProcessTileEqualize(_paused, maxProcessTime))
{
_paused = true;
return;
}
_paused = false;
_state = ProcessState.ActiveTiles;
return;
case ProcessState.ActiveTiles:
if (!ProcessActiveTiles(_paused, maxProcessTime))
{
_paused = true;
return;
}
_paused = false;
_state = ProcessState.ExcitedGroups;
return;
case ProcessState.ExcitedGroups:
if (!ProcessExcitedGroups(_paused, maxProcessTime))
{
_paused = true;
return;
}
_paused = false;
_state = ProcessState.HighPressureDelta;
return;
case ProcessState.HighPressureDelta:
if (!ProcessHighPressureDelta(_paused, maxProcessTime))
{
_paused = true;
return;
}
_paused = false;
_state = ProcessState.Hotspots;
break;
case ProcessState.Hotspots:
if (!ProcessHotspots(_paused, maxProcessTime))
{
_paused = true;
return;
}
_paused = false;
// Next state depends on whether superconduction is enabled or not.
// Note: We do this here instead of on the tile equalization step to prevent ending it early.
// Therefore, a change to this CVar might only be applied after that step is over.
_state = AtmosphereSystem.Superconduction ? ProcessState.Superconductivity : ProcessState.PipeNet;
break;
case ProcessState.Superconductivity:
if (!ProcessSuperconductivity(_paused, maxProcessTime))
{
_paused = true;
return;
}
_paused = false;
_state = ProcessState.PipeNet;
break;
case ProcessState.PipeNet:
if (!ProcessPipeNets(_paused, maxProcessTime))
{
_paused = true;
return;
}
_paused = false;
_state = ProcessState.AtmosDevices;
break;
case ProcessState.AtmosDevices:
if (!ProcessAtmosDevices(_paused, maxProcessTime))
{
_paused = true;
return;
}
_paused = false;
// Next state depends on whether monstermos equalization is enabled or not.
// Note: We do this here instead of on the tile equalization step to prevent ending it early.
// Therefore, a change to this CVar might only be applied after that step is over.
_state = AtmosphereSystem.MonstermosEqualization ? ProcessState.TileEqualize : ProcessState.ActiveTiles;
break;
}
UpdateCounter++;
}
public virtual bool ProcessTileEqualize(bool resumed = false, float lagCheck = 5f)
{
_stopwatch.Restart();
if(!resumed)
_currentRunTiles = new Queue<TileAtmosphere>(_activeTiles);
var number = 0;
while (_currentRunTiles.Count > 0)
{
var tile = _currentRunTiles.Dequeue();
tile.EqualizePressureInZone(UpdateCounter);
if (number++ < LagCheckIterations) continue;
number = 0;
// Process the rest next time.
if (_stopwatch.Elapsed.TotalMilliseconds >= lagCheck)
{
_tileEqualizeLastProcess = _stopwatch.Elapsed.TotalMilliseconds;
return false;
}
}
_tileEqualizeLastProcess = _stopwatch.Elapsed.TotalMilliseconds;
return true;
}
public virtual bool ProcessActiveTiles(bool resumed = false, float lagCheck = 5f)
{
_stopwatch.Restart();
var spaceWind = AtmosphereSystem.SpaceWind;
if(!resumed)
_currentRunTiles = new Queue<TileAtmosphere>(_activeTiles);
var number = 0;
while (_currentRunTiles.Count > 0)
{
var tile = _currentRunTiles.Dequeue();
tile.ProcessCell(UpdateCounter, spaceWind);
if (number++ < LagCheckIterations) continue;
number = 0;
// Process the rest next time.
if (_stopwatch.Elapsed.TotalMilliseconds >= lagCheck)
{
_activeTilesLastProcess = _stopwatch.Elapsed.TotalMilliseconds;
return false;
}
}
_activeTilesLastProcess = _stopwatch.Elapsed.TotalMilliseconds;
return true;
}
public virtual bool ProcessExcitedGroups(bool resumed = false, float lagCheck = 5f)
{
_stopwatch.Restart();
var spaceIsAllConsuming = AtmosphereSystem.ExcitedGroupsSpaceIsAllConsuming;
if(!resumed)
_currentRunExcitedGroups = new Queue<ExcitedGroup>(_excitedGroups);
var number = 0;
while (_currentRunExcitedGroups.Count > 0)
{
var excitedGroup = _currentRunExcitedGroups.Dequeue();
excitedGroup.BreakdownCooldown++;
excitedGroup.DismantleCooldown++;
if(excitedGroup.BreakdownCooldown > Atmospherics.ExcitedGroupBreakdownCycles)
excitedGroup.SelfBreakdown(spaceIsAllConsuming);
else if(excitedGroup.DismantleCooldown > Atmospherics.ExcitedGroupsDismantleCycles)
excitedGroup.Dismantle();
if (number++ < LagCheckIterations) continue;
number = 0;
// Process the rest next time.
if (_stopwatch.Elapsed.TotalMilliseconds >= lagCheck)
{
_excitedGroupLastProcess = _stopwatch.Elapsed.TotalMilliseconds;
return false;
}
}
_excitedGroupLastProcess = _stopwatch.Elapsed.TotalMilliseconds;
return true;
}
public virtual bool ProcessHighPressureDelta(bool resumed = false, float lagCheck = 5f)
{
_stopwatch.Restart();
if(!resumed)
_currentRunTiles = new Queue<TileAtmosphere>(_highPressureDelta);
var number = 0;
while (_currentRunTiles.Count > 0)
{
var tile = _currentRunTiles.Dequeue();
tile.HighPressureMovements();
tile.PressureDifference = 0f;
tile.PressureSpecificTarget = null;
_highPressureDelta.Remove(tile);
if (number++ < LagCheckIterations) continue;
number = 0;
// Process the rest next time.
if (_stopwatch.Elapsed.TotalMilliseconds >= lagCheck)
{
_highPressureDeltaLastProcess = _stopwatch.Elapsed.TotalMilliseconds;
return false;
}
}
_highPressureDeltaLastProcess = _stopwatch.Elapsed.TotalMilliseconds;
return true;
}
protected virtual bool ProcessHotspots(bool resumed = false, float lagCheck = 5f)
{
_stopwatch.Restart();
if(!resumed)
_currentRunTiles = new Queue<TileAtmosphere>(_hotspotTiles);
var number = 0;
while (_currentRunTiles.Count > 0)
{
var hotspot = _currentRunTiles.Dequeue();
hotspot.ProcessHotspot();
if (number++ < LagCheckIterations) continue;
number = 0;
// Process the rest next time.
if (_stopwatch.Elapsed.TotalMilliseconds >= lagCheck)
{
_hotspotsLastProcess = _stopwatch.Elapsed.TotalMilliseconds;
return false;
}
}
_hotspotsLastProcess = _stopwatch.Elapsed.TotalMilliseconds;
return true;
}
protected virtual bool ProcessSuperconductivity(bool resumed = false, float lagCheck = 5f)
{
_stopwatch.Restart();
if(!resumed)
_currentRunTiles = new Queue<TileAtmosphere>(_superconductivityTiles);
var number = 0;
while (_currentRunTiles.Count > 0)
{
var superconductivity = _currentRunTiles.Dequeue();
superconductivity.Superconduct();
if (number++ < LagCheckIterations) continue;
number = 0;
// Process the rest next time.
if (_stopwatch.Elapsed.TotalMilliseconds >= lagCheck)
{
_superconductivityLastProcess = _stopwatch.Elapsed.TotalMilliseconds;
return false;
}
}
_superconductivityLastProcess = _stopwatch.Elapsed.TotalMilliseconds;
return true;
}
protected virtual bool ProcessPipeNets(bool resumed = false, float lagCheck = 5f)
{
_stopwatch.Restart();
if(!resumed)
_currentRunPipeNet = new Queue<IPipeNet>(_pipeNets);
var number = 0;
while (_currentRunPipeNet.Count > 0)
{
var pipenet = _currentRunPipeNet.Dequeue();
pipenet.Update();
if (number++ < LagCheckIterations) continue;
number = 0;
// Process the rest next time.
if (_stopwatch.Elapsed.TotalMilliseconds >= lagCheck)
{
_pipeNetLastProcess = _stopwatch.Elapsed.TotalMilliseconds;
return false;
}
}
_pipeNetLastProcess = _stopwatch.Elapsed.TotalMilliseconds;
return true;
}
protected virtual bool ProcessAtmosDevices(bool resumed = false, float lagCheck = 5f)
{
_stopwatch.Restart();
if(!resumed)
_currentRunAtmosDevices = new Queue<AtmosDeviceComponent>(_atmosDevices);
var time = _gameTiming.CurTime;
var updateEvent = new AtmosDeviceUpdateEvent(this);
var number = 0;
while (_currentRunAtmosDevices.Count > 0)
{
var device = _currentRunAtmosDevices.Dequeue();
Owner.EntityManager.EventBus.RaiseLocalEvent(device.Owner.Uid, updateEvent, false);
device.LastProcess = time;
if (number++ < LagCheckIterations) continue;
number = 0;
// Process the rest next time.
if (_stopwatch.Elapsed.TotalMilliseconds >= lagCheck)
{
_atmosDevicesLastProcess = _stopwatch.Elapsed.TotalMilliseconds;
return false;
}
}
_atmosDevicesLastProcess = _stopwatch.Elapsed.TotalMilliseconds;
return true;
}
protected virtual IEnumerable<AirtightComponent> GetObstructingComponents(Vector2i indices) protected virtual IEnumerable<AirtightComponent> GetObstructingComponents(Vector2i indices)
{ {
var gridLookup = EntitySystem.Get<GridTileLookupSystem>(); var gridLookup = EntitySystem.Get<GridTileLookupSystem>();

View File

@@ -171,8 +171,6 @@ namespace Content.Server.Atmos.Components
/// </summary> /// </summary>
Dictionary<AtmosDirection, TileAtmosphere> GetAdjacentTiles(Vector2i indices, bool includeAirBlocked = false); Dictionary<AtmosDirection, TileAtmosphere> GetAdjacentTiles(Vector2i indices, bool includeAirBlocked = false);
void Update(float frameTime);
void AddPipeNet(IPipeNet pipeNet); void AddPipeNet(IPipeNet pipeNet);
void RemovePipeNet(IPipeNet pipeNet); void RemovePipeNet(IPipeNet pipeNet);

View File

@@ -33,7 +33,7 @@ namespace Content.Server.Atmos.Components
public override void Invalidate(Vector2i indices) { } public override void Invalidate(Vector2i indices) { }
protected override void Revalidate() { } public override void Revalidate() { }
public override void FixVacuum(Vector2i indices) { } public override void FixVacuum(Vector2i indices) { }
@@ -67,47 +67,5 @@ namespace Content.Server.Atmos.Components
public override void AddAtmosDevice(AtmosDeviceComponent atmosDevice) { } public override void AddAtmosDevice(AtmosDeviceComponent atmosDevice) { }
public override void RemoveAtmosDevice(AtmosDeviceComponent atmosDevice) { } public override void RemoveAtmosDevice(AtmosDeviceComponent atmosDevice) { }
public override void Update(float frameTime) { }
public override bool ProcessTileEqualize(bool resumed = false, float lagCheck = 5f)
{
return false;
}
public override bool ProcessActiveTiles(bool resumed = false, float lagCheck = 5f)
{
return false;
}
public override bool ProcessExcitedGroups(bool resumed = false, float lagCheck = 5f)
{
return false;
}
public override bool ProcessHighPressureDelta(bool resumed = false, float lagCheck = 5f)
{
return false;
}
protected override bool ProcessHotspots(bool resumed = false, float lagCheck = 5f)
{
return false;
}
protected override bool ProcessSuperconductivity(bool resumed = false, float lagCheck = 5f)
{
return false;
}
protected override bool ProcessPipeNets(bool resumed = false, float lagCheck = 5f)
{
return false;
}
protected override bool ProcessAtmosDevices(bool resumed = false, float lagCheck = 5f)
{
return false;
}
} }
} }

View File

@@ -10,6 +10,7 @@ namespace Content.Server.Atmos.EntitySystems
public bool ExcitedGroupsSpaceIsAllConsuming { get; private set; } public bool ExcitedGroupsSpaceIsAllConsuming { get; private set; }
public float AtmosMaxProcessTime { get; private set; } public float AtmosMaxProcessTime { get; private set; }
public float AtmosTickRate { get; private set; } public float AtmosTickRate { get; private set; }
public float AtmosTime => 1f / AtmosTickRate;
private void InitializeCVars() private void InitializeCVars()
{ {

View File

@@ -0,0 +1,365 @@
using System.Collections.Generic;
using Content.Server.Atmos.Components;
using Content.Server.Atmos.Piping.Components;
using Content.Server.NodeContainer.NodeGroups;
using Content.Shared.Atmos;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Timing;
namespace Content.Server.Atmos.EntitySystems
{
public partial class AtmosphereSystem
{
[Dependency] private readonly IGameTiming _gameTiming = default!;
private readonly Stopwatch _simulationStopwatch = new();
/// <summary>
/// Check current execution time every n instances processed.
/// </summary>
private const int LagCheckIterations = 30;
private int _currentRunAtmosphereIndex = 0;
private bool _simulationPaused = false;
private readonly List<GridAtmosphereComponent> _currentRunAtmosphere = new();
private bool ProcessTileEqualize(GridAtmosphereComponent atmosphere)
{
if(!atmosphere.ProcessingPaused)
atmosphere.CurrentRunTiles = new Queue<TileAtmosphere>(atmosphere.ActiveTiles);
var number = 0;
while (atmosphere.CurrentRunTiles.TryDequeue(out var tile))
{
tile.EqualizePressureInZone(atmosphere.UpdateCounter);
if (number++ < LagCheckIterations) continue;
number = 0;
// Process the rest next time.
if (_simulationStopwatch.Elapsed.TotalMilliseconds >= AtmosMaxProcessTime)
{
return false;
}
}
return true;
}
private bool ProcessActiveTiles(GridAtmosphereComponent atmosphere)
{
if(!atmosphere.ProcessingPaused)
atmosphere.CurrentRunTiles = new Queue<TileAtmosphere>(atmosphere.ActiveTiles);
var number = 0;
while (atmosphere.CurrentRunTiles.TryDequeue(out var tile))
{
tile.ProcessCell(atmosphere.UpdateCounter, SpaceWind);
if (number++ < LagCheckIterations) continue;
number = 0;
// Process the rest next time.
if (_simulationStopwatch.Elapsed.TotalMilliseconds >= AtmosMaxProcessTime)
{
return false;
}
}
return true;
}
private bool ProcessExcitedGroups(GridAtmosphereComponent atmosphere)
{
if(!atmosphere.ProcessingPaused)
atmosphere.CurrentRunExcitedGroups = new Queue<ExcitedGroup>(atmosphere.ExcitedGroups);
var number = 0;
while (atmosphere.CurrentRunExcitedGroups.TryDequeue(out var excitedGroup))
{
excitedGroup.BreakdownCooldown++;
excitedGroup.DismantleCooldown++;
if(excitedGroup.BreakdownCooldown > Atmospherics.ExcitedGroupBreakdownCycles)
excitedGroup.SelfBreakdown(ExcitedGroupsSpaceIsAllConsuming);
else if(excitedGroup.DismantleCooldown > Atmospherics.ExcitedGroupsDismantleCycles)
excitedGroup.Dismantle();
if (number++ < LagCheckIterations) continue;
number = 0;
// Process the rest next time.
if (_simulationStopwatch.Elapsed.TotalMilliseconds >= AtmosMaxProcessTime)
{
return false;
}
}
return true;
}
private bool ProcessHighPressureDelta(GridAtmosphereComponent atmosphere)
{
if(!atmosphere.ProcessingPaused)
atmosphere.CurrentRunTiles = new Queue<TileAtmosphere>(atmosphere.HighPressureDelta);
var number = 0;
while (atmosphere.CurrentRunTiles.TryDequeue(out var tile))
{
tile.HighPressureMovements();
tile.PressureDifference = 0f;
tile.PressureSpecificTarget = null;
atmosphere.HighPressureDelta.Remove(tile);
if (number++ < LagCheckIterations) continue;
number = 0;
// Process the rest next time.
if (_simulationStopwatch.Elapsed.TotalMilliseconds >= AtmosMaxProcessTime)
{
return false;
}
}
return true;
}
private bool ProcessHotspots(GridAtmosphereComponent atmosphere)
{
if(!atmosphere.ProcessingPaused)
atmosphere.CurrentRunTiles = new Queue<TileAtmosphere>(atmosphere.HotspotTiles);
var number = 0;
while (atmosphere.CurrentRunTiles.TryDequeue(out var hotspot))
{
hotspot.ProcessHotspot();
if (number++ < LagCheckIterations) continue;
number = 0;
// Process the rest next time.
if (_simulationStopwatch.Elapsed.TotalMilliseconds >= AtmosMaxProcessTime)
{
return false;
}
}
return true;
}
private bool ProcessSuperconductivity(GridAtmosphereComponent atmosphere)
{
if(!atmosphere.ProcessingPaused)
atmosphere.CurrentRunTiles = new Queue<TileAtmosphere>(atmosphere.SuperconductivityTiles);
var number = 0;
while (atmosphere.CurrentRunTiles.TryDequeue(out var superconductivity))
{
superconductivity.Superconduct();
if (number++ < LagCheckIterations) continue;
number = 0;
// Process the rest next time.
if (_simulationStopwatch.Elapsed.TotalMilliseconds >= AtmosMaxProcessTime)
{
return false;
}
}
return true;
}
private bool ProcessPipeNets(GridAtmosphereComponent atmosphere)
{
if(!atmosphere.ProcessingPaused)
atmosphere.CurrentRunPipeNet = new Queue<IPipeNet>(atmosphere.PipeNets);
var number = 0;
while (atmosphere.CurrentRunPipeNet.TryDequeue(out var pipenet))
{
pipenet.Update();
if (number++ < LagCheckIterations) continue;
number = 0;
// Process the rest next time.
if (_simulationStopwatch.Elapsed.TotalMilliseconds >= AtmosMaxProcessTime)
{
return false;
}
}
return true;
}
private bool ProcessAtmosDevices(GridAtmosphereComponent atmosphere)
{
if(!atmosphere.ProcessingPaused)
atmosphere.CurrentRunAtmosDevices = new Queue<AtmosDeviceComponent>(atmosphere.AtmosDevices);
var time = _gameTiming.CurTime;
var updateEvent = new AtmosDeviceUpdateEvent(atmosphere);
var number = 0;
while (atmosphere.CurrentRunAtmosDevices.TryDequeue(out var device))
{
EntityManager.EventBus.RaiseLocalEvent(device.Owner.Uid, updateEvent, false);
device.LastProcess = time;
if (number++ < LagCheckIterations) continue;
number = 0;
// Process the rest next time.
if (_simulationStopwatch.Elapsed.TotalMilliseconds >= AtmosMaxProcessTime)
{
return false;
}
}
return true;
}
private void UpdateProcessing(float frameTime)
{
_simulationStopwatch.Restart();
if (!_simulationPaused)
{
_currentRunAtmosphereIndex = 0;
_currentRunAtmosphere.Clear();
_currentRunAtmosphere.AddRange(ComponentManager.EntityQuery<GridAtmosphereComponent>());
}
// We set this to true just in case we have to stop processing due to time constraints.
_simulationPaused = true;
for (; _currentRunAtmosphereIndex < _currentRunAtmosphere.Count; _currentRunAtmosphereIndex++)
{
var atmosphere = _currentRunAtmosphere[_currentRunAtmosphereIndex];
if (atmosphere.Paused || atmosphere.LifeStage >= ComponentLifeStage.Stopping)
continue;
atmosphere.Timer += frameTime;
if (atmosphere.InvalidatedCoords.Count != 0)
atmosphere.Revalidate();
if (atmosphere.Timer < AtmosTime)
continue;
// We subtract it so it takes lost time into account.
atmosphere.Timer -= AtmosTime;
switch (atmosphere.State)
{
case AtmosphereProcessingState.TileEqualize:
if (!ProcessTileEqualize(atmosphere))
{
atmosphere.ProcessingPaused = true;
return;
}
atmosphere.ProcessingPaused = false;
atmosphere.State = AtmosphereProcessingState.ActiveTiles;
continue;
case AtmosphereProcessingState.ActiveTiles:
if (!ProcessActiveTiles(atmosphere))
{
atmosphere.ProcessingPaused = true;
return;
}
atmosphere.ProcessingPaused = false;
atmosphere.State = AtmosphereProcessingState.ExcitedGroups;
continue;
case AtmosphereProcessingState.ExcitedGroups:
if (!ProcessExcitedGroups(atmosphere))
{
atmosphere.ProcessingPaused = true;
return;
}
atmosphere.ProcessingPaused = false;
atmosphere.State = AtmosphereProcessingState.HighPressureDelta;
continue;
case AtmosphereProcessingState.HighPressureDelta:
if (!ProcessHighPressureDelta(atmosphere))
{
atmosphere.ProcessingPaused = true;
return;
}
atmosphere.ProcessingPaused = false;
atmosphere.State = AtmosphereProcessingState.Hotspots;
continue;
case AtmosphereProcessingState.Hotspots:
if (!ProcessHotspots(atmosphere))
{
atmosphere.ProcessingPaused = true;
return;
}
atmosphere.ProcessingPaused = false;
// Next state depends on whether superconduction is enabled or not.
// Note: We do this here instead of on the tile equalization step to prevent ending it early.
// Therefore, a change to this CVar might only be applied after that step is over.
atmosphere.State = Superconduction
? AtmosphereProcessingState.Superconductivity
: AtmosphereProcessingState.PipeNet;
continue;
case AtmosphereProcessingState.Superconductivity:
if (!ProcessSuperconductivity(atmosphere))
{
atmosphere.ProcessingPaused = true;
return;
}
atmosphere.ProcessingPaused = false;
atmosphere.State = AtmosphereProcessingState.PipeNet;
continue;
case AtmosphereProcessingState.PipeNet:
if (!ProcessPipeNets(atmosphere))
{
atmosphere.ProcessingPaused = true;
return;
}
atmosphere.ProcessingPaused = false;
atmosphere.State = AtmosphereProcessingState.AtmosDevices;
continue;
case AtmosphereProcessingState.AtmosDevices:
if (!ProcessAtmosDevices(atmosphere))
{
atmosphere.ProcessingPaused = true;
return;
}
atmosphere.ProcessingPaused = false;
// Next state depends on whether monstermos equalization is enabled or not.
// Note: We do this here instead of on the tile equalization step to prevent ending it early.
// Therefore, a change to this CVar might only be applied after that step is over.
atmosphere.State = MonstermosEqualization
? AtmosphereProcessingState.TileEqualize
: AtmosphereProcessingState.ActiveTiles;
// We reached the end of this atmosphere's update tick. Break out of the switch.
break;
}
// And increase the update counter.
atmosphere.UpdateCounter++;
}
// We finished processing all atmospheres successfully, therefore we won't be paused next tick.
_simulationPaused = false;
}
}
public enum AtmosphereProcessingState : byte
{
TileEqualize,
ActiveTiles,
ExcitedGroups,
HighPressureDelta,
Hotspots,
Superconductivity,
PipeNet,
AtmosDevices,
}
}

View File

@@ -149,15 +149,10 @@ namespace Content.Server.Atmos.EntitySystems
{ {
base.Update(frameTime); base.Update(frameTime);
UpdateProcessing(frameTime);
_exposedTimer += frameTime; _exposedTimer += frameTime;
foreach (var (mapGridComponent, gridAtmosphereComponent) in EntityManager.ComponentManager.EntityQuery<IMapGridComponent, IGridAtmosphereComponent>(true))
{
if (_pauseManager.IsGridPaused(mapGridComponent.GridIndex)) continue;
gridAtmosphereComponent.Update(frameTime);
}
if (_exposedTimer >= ExposedUpdateDelay) if (_exposedTimer >= ExposedUpdateDelay)
{ {
foreach (var exposed in EntityManager.ComponentManager.EntityQuery<AtmosExposedComponent>(true)) foreach (var exposed in EntityManager.ComponentManager.EntityQuery<AtmosExposedComponent>(true))
@@ -167,7 +162,7 @@ namespace Content.Server.Atmos.EntitySystems
exposed.Update(tile, _exposedTimer); exposed.Update(tile, _exposedTimer);
} }
_exposedTimer = 0; _exposedTimer -= ExposedUpdateDelay;
} }
} }
} }