diff --git a/Content.Server/Atmos/Components/GridAtmosphereComponent.cs b/Content.Server/Atmos/Components/GridAtmosphereComponent.cs index c03c52f252..9d606fe731 100644 --- a/Content.Server/Atmos/Components/GridAtmosphereComponent.cs +++ b/Content.Server/Atmos/Components/GridAtmosphereComponent.cs @@ -40,16 +40,10 @@ namespace Content.Server.Atmos.Components internal GasTileOverlaySystem GasTileOverlaySystem { get; private set; } = default!; public AtmosphereSystem AtmosphereSystem { get; private set; } = default!; - /// - /// Check current execution time every n instances processed. - /// - private const int LagCheckIterations = 30; - public override string Name => "GridAtmosphere"; - private bool _paused; - private float _timer; - private Stopwatch _stopwatch = new(); + public bool ProcessingPaused { get; set; } = false; + public float Timer { get; set; } private GridId _gridId; [ComponentDependency] private IMapGridComponent? _mapGridComponent; @@ -57,113 +51,74 @@ namespace Content.Server.Atmos.Components public virtual bool Simulated => true; [ViewVariables] - public int UpdateCounter { get; private set; } = 0; + public int UpdateCounter { get; set; } = 0; [ViewVariables] - private double _tileEqualizeLastProcess; + public readonly HashSet ExcitedGroups = new(1000); [ViewVariables] - private readonly HashSet _excitedGroups = new(1000); - - [ViewVariables] - private int ExcitedGroupCount => _excitedGroups.Count; - - [ViewVariables] - private double _excitedGroupLastProcess; + public int ExcitedGroupCount => ExcitedGroups.Count; [DataField("uniqueMixes")] - private List? _uniqueMixes; + public List? UniqueMixes; [DataField("tiles")] - private Dictionary? _tiles; + public Dictionary? TilesUniqueMixes; [ViewVariables] - protected readonly Dictionary Tiles = new(1000); + public readonly Dictionary Tiles = new(1000); [ViewVariables] - private readonly HashSet _activeTiles = new(1000); + public readonly HashSet ActiveTiles = new(1000); [ViewVariables] - private int ActiveTilesCount => _activeTiles.Count; + public int ActiveTilesCount => ActiveTiles.Count; [ViewVariables] - private double _activeTilesLastProcess; + public readonly HashSet HotspotTiles = new(1000); [ViewVariables] - private readonly HashSet _hotspotTiles = new(1000); + public int HotspotTilesCount => HotspotTiles.Count; [ViewVariables] - private int HotspotTilesCount => _hotspotTiles.Count; + public readonly HashSet SuperconductivityTiles = new(1000); [ViewVariables] - private double _hotspotsLastProcess; + public int SuperconductivityTilesCount => SuperconductivityTiles.Count; [ViewVariables] - private readonly HashSet _superconductivityTiles = new(1000); + public readonly HashSet InvalidatedCoords = new(1000); [ViewVariables] - private int SuperconductivityTilesCount => _superconductivityTiles.Count; + public HashSet HighPressureDelta = new(1000); [ViewVariables] - private double _superconductivityLastProcess; + public int HighPressureDeltaCount => HighPressureDelta.Count; [ViewVariables] - private readonly HashSet _invalidatedCoords = new(1000); + public readonly HashSet PipeNets = new(); [ViewVariables] - private int InvalidatedCoordsCount => _invalidatedCoords.Count; + public readonly HashSet AtmosDevices = new(); [ViewVariables] - private HashSet _highPressureDelta = new(1000); + public Queue CurrentRunTiles = new(); [ViewVariables] - private int HighPressureDeltaCount => _highPressureDelta.Count; + public Queue CurrentRunExcitedGroups = new(); [ViewVariables] - private double _highPressureDeltaLastProcess; + public Queue CurrentRunPipeNet = new(); [ViewVariables] - private readonly HashSet _pipeNets = new(); + public Queue CurrentRunAtmosDevices = new(); [ViewVariables] - private double _pipeNetLastProcess; - - [ViewVariables] - private readonly HashSet _atmosDevices = new(); - - [ViewVariables] - private double _atmosDevicesLastProcess; - - [ViewVariables] - private Queue _currentRunTiles = new(); - - [ViewVariables] - private Queue _currentRunExcitedGroups = new(); - - [ViewVariables] - private Queue _currentRunPipeNet = new(); - - [ViewVariables] - private Queue _currentRunAtmosDevices = new(); - - [ViewVariables] - private ProcessState _state = ProcessState.TileEqualize; + public AtmosphereProcessingState State { get; set; } = AtmosphereProcessingState.TileEqualize; public GridAtmosphereComponent() { - _paused = false; - } - - private enum ProcessState - { - TileEqualize, - ActiveTiles, - ExcitedGroups, - HighPressureDelta, - Hotspots, - Superconductivity, - PipeNet, - AtmosDevices, + ProcessingPaused = false; } /// @@ -199,8 +154,8 @@ namespace Content.Server.Atmos.Components if (uniqueMixes.Count == 0) uniqueMixes = null; if (tiles.Count == 0) tiles = null; - _uniqueMixes = uniqueMixes; - _tiles = tiles; + UniqueMixes = uniqueMixes; + TilesUniqueMixes = tiles; } protected override void Initialize() @@ -209,13 +164,13 @@ namespace Content.Server.Atmos.Components 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 { - 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) { @@ -264,12 +219,12 @@ namespace Content.Server.Atmos.Components /// 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); @@ -341,7 +296,7 @@ namespace Content.Server.Atmos.Components } } - _invalidatedCoords.Clear(); + InvalidatedCoords.Clear(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -376,14 +331,14 @@ namespace Content.Server.Atmos.Components { if (tile?.GridIndex != _gridId || tile.Air == null) return; tile.Excited = true; - _activeTiles.Add(tile); + ActiveTiles.Add(tile); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void RemoveActiveTile(TileAtmosphere tile, bool disposeGroup = true) { - _activeTiles.Remove(tile); + ActiveTiles.Remove(tile); tile.Excited = false; if(disposeGroup) tile.ExcitedGroup?.Dispose(); @@ -396,25 +351,25 @@ namespace Content.Server.Atmos.Components public virtual void AddHotspotTile(TileAtmosphere tile) { if (tile?.GridIndex != _gridId || tile?.Air == null) return; - _hotspotTiles.Add(tile); + HotspotTiles.Add(tile); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void RemoveHotspotTile(TileAtmosphere tile) { - _hotspotTiles.Remove(tile); + HotspotTiles.Remove(tile); } public virtual void AddSuperconductivityTile(TileAtmosphere tile) { if (tile?.GridIndex != _gridId || !AtmosphereSystem.Superconduction) return; - _superconductivityTiles.Add(tile); + SuperconductivityTiles.Add(tile); } public virtual void RemoveSuperconductivityTile(TileAtmosphere tile) { - _superconductivityTiles.Remove(tile); + SuperconductivityTiles.Remove(tile); } /// @@ -422,48 +377,48 @@ namespace Content.Server.Atmos.Components public virtual void AddHighPressureDelta(TileAtmosphere tile) { if (tile.GridIndex != _gridId) return; - _highPressureDelta.Add(tile); + HighPressureDelta.Add(tile); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual bool HasHighPressureDelta(TileAtmosphere tile) { - return _highPressureDelta.Contains(tile); + return HighPressureDelta.Contains(tile); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void AddExcitedGroup(ExcitedGroup excitedGroup) { - _excitedGroups.Add(excitedGroup); + ExcitedGroups.Add(excitedGroup); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void RemoveExcitedGroup(ExcitedGroup excitedGroup) { - _excitedGroups.Remove(excitedGroup); + ExcitedGroups.Remove(excitedGroup); } public virtual void AddPipeNet(IPipeNet pipeNet) { - _pipeNets.Add(pipeNet); + PipeNets.Add(pipeNet); } public virtual void RemovePipeNet(IPipeNet pipeNet) { - _pipeNets.Remove(pipeNet); + PipeNets.Remove(pipeNet); } public virtual void AddAtmosDevice(AtmosDeviceComponent atmosDevice) { - _atmosDevices.Add(atmosDevice); + AtmosDevices.Add(atmosDevice); } public virtual void RemoveAtmosDevice(AtmosDeviceComponent atmosDevice) { - _atmosDevices.Remove(atmosDevice); + AtmosDevices.Remove(atmosDevice); } /// @@ -545,349 +500,6 @@ namespace Content.Server.Atmos.Components return _mapGridComponent.Grid.TileSize * cellCount * Atmospherics.CellVolume; } - /// - 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(_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(_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(_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(_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(_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(_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(_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(_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 GetObstructingComponents(Vector2i indices) { var gridLookup = EntitySystem.Get(); diff --git a/Content.Server/Atmos/Components/IGridAtmosphereComponent.cs b/Content.Server/Atmos/Components/IGridAtmosphereComponent.cs index 6e6735475e..e82e0a75b1 100644 --- a/Content.Server/Atmos/Components/IGridAtmosphereComponent.cs +++ b/Content.Server/Atmos/Components/IGridAtmosphereComponent.cs @@ -171,8 +171,6 @@ namespace Content.Server.Atmos.Components /// Dictionary GetAdjacentTiles(Vector2i indices, bool includeAirBlocked = false); - void Update(float frameTime); - void AddPipeNet(IPipeNet pipeNet); void RemovePipeNet(IPipeNet pipeNet); diff --git a/Content.Server/Atmos/Components/UnsimulatedGridAtmosphereComponent.cs b/Content.Server/Atmos/Components/UnsimulatedGridAtmosphereComponent.cs index c59ffa486c..090f506902 100644 --- a/Content.Server/Atmos/Components/UnsimulatedGridAtmosphereComponent.cs +++ b/Content.Server/Atmos/Components/UnsimulatedGridAtmosphereComponent.cs @@ -33,7 +33,7 @@ namespace Content.Server.Atmos.Components public override void Invalidate(Vector2i indices) { } - protected override void Revalidate() { } + public override void Revalidate() { } public override void FixVacuum(Vector2i indices) { } @@ -67,47 +67,5 @@ namespace Content.Server.Atmos.Components public override void AddAtmosDevice(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; - } } } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs index 2c8e0de6ac..f2baf06066 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs @@ -10,6 +10,7 @@ namespace Content.Server.Atmos.EntitySystems public bool ExcitedGroupsSpaceIsAllConsuming { get; private set; } public float AtmosMaxProcessTime { get; private set; } public float AtmosTickRate { get; private set; } + public float AtmosTime => 1f / AtmosTickRate; private void InitializeCVars() { diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs new file mode 100644 index 0000000000..b9ece658f6 --- /dev/null +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs @@ -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(); + + /// + /// Check current execution time every n instances processed. + /// + private const int LagCheckIterations = 30; + + private int _currentRunAtmosphereIndex = 0; + private bool _simulationPaused = false; + + private readonly List _currentRunAtmosphere = new(); + + private bool ProcessTileEqualize(GridAtmosphereComponent atmosphere) + { + if(!atmosphere.ProcessingPaused) + atmosphere.CurrentRunTiles = new Queue(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(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(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(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(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(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(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(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()); + } + + // 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, + } +} diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs index cb0f5d3234..6268319e0d 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs @@ -149,15 +149,10 @@ namespace Content.Server.Atmos.EntitySystems { base.Update(frameTime); + UpdateProcessing(frameTime); + _exposedTimer += frameTime; - foreach (var (mapGridComponent, gridAtmosphereComponent) in EntityManager.ComponentManager.EntityQuery(true)) - { - if (_pauseManager.IsGridPaused(mapGridComponent.GridIndex)) continue; - - gridAtmosphereComponent.Update(frameTime); - } - if (_exposedTimer >= ExposedUpdateDelay) { foreach (var exposed in EntityManager.ComponentManager.EntityQuery(true)) @@ -167,7 +162,7 @@ namespace Content.Server.Atmos.EntitySystems exposed.Update(tile, _exposedTimer); } - _exposedTimer = 0; + _exposedTimer -= ExposedUpdateDelay; } } }