using Robust.Shared.Map.Components;
using Robust.Shared.Utility;
-namespace Content.Server.Atmos.EntitySystems
+namespace Content.Server.Atmos.EntitySystems;
+
+public sealed partial class AtmosphereSystem
{
- public sealed partial class AtmosphereSystem
+ /*
+ Handles Excited Groups, an optimization routine executed during LINDA
+ that groups active tiles together.
+
+ Groups of active tiles that have very low mole deltas between them
+ are dissolved after a cooldown period, performing a final equalization
+ on all tiles in the group before deactivating them.
+
+ If tiles are so close together in pressure that the final equalization
+ would result in negligible gas transfer, the group is dissolved without
+ performing an equalization.
+
+ This prevents LINDA from constantly transferring tiny amounts of gas
+ between tiles that are already nearly equalized.
+ */
+
+ /// <summary>
+ /// Adds a tile to an <see cref="ExcitedGroups"/>, resetting the group's cooldowns in the process.
+ /// </summary>
+ /// <param name="excitedGroup">The <see cref="ExcitedGroups"/> to add the tile to.</param>
+ /// <param name="tile">The <see cref="TileAtmosphere"/> to add.</param>
+ private void ExcitedGroupAddTile(ExcitedGroup excitedGroup, TileAtmosphere tile)
{
- private void ExcitedGroupAddTile(ExcitedGroup excitedGroup, TileAtmosphere tile)
- {
- DebugTools.Assert(!excitedGroup.Disposed, "Excited group is disposed!");
- DebugTools.Assert(tile.ExcitedGroup == null, "Tried to add a tile to an excited group when it's already in another one!");
- excitedGroup.Tiles.Add(tile);
- tile.ExcitedGroup = excitedGroup;
- ExcitedGroupResetCooldowns(excitedGroup);
- }
+ DebugTools.Assert(!excitedGroup.Disposed, "Excited group is disposed!");
+ DebugTools.Assert(tile.ExcitedGroup == null, "Tried to add a tile to an excited group when it's already in another one!");
+ excitedGroup.Tiles.Add(tile);
+ tile.ExcitedGroup = excitedGroup;
+ ExcitedGroupResetCooldowns(excitedGroup);
+ }
- private void ExcitedGroupRemoveTile(ExcitedGroup excitedGroup, TileAtmosphere tile)
- {
- DebugTools.Assert(!excitedGroup.Disposed, "Excited group is disposed!");
- DebugTools.Assert(tile.ExcitedGroup == excitedGroup, "Tried to remove a tile from an excited group it's not present in!");
- tile.ExcitedGroup = null;
- excitedGroup.Tiles.Remove(tile);
- }
+ /// <summary>
+ /// Removes a tile from an <see cref="ExcitedGroups"/>.
+ /// </summary>
+ /// <param name="excitedGroup">The <see cref="ExcitedGroups"/> to remove the tile from.</param>
+ /// <param name="tile">The <see cref="TileAtmosphere"/> to remove.</param>
+ private void ExcitedGroupRemoveTile(ExcitedGroup excitedGroup, TileAtmosphere tile)
+ {
+ DebugTools.Assert(!excitedGroup.Disposed, "Excited group is disposed!");
+ DebugTools.Assert(tile.ExcitedGroup == excitedGroup, "Tried to remove a tile from an excited group it's not present in!");
+ tile.ExcitedGroup = null;
+ excitedGroup.Tiles.Remove(tile);
+ }
- private void ExcitedGroupMerge(GridAtmosphereComponent gridAtmosphere, ExcitedGroup ourGroup, ExcitedGroup otherGroup)
+ /// <summary>
+ /// Merges two <see cref="ExcitedGroups"/>, transferring all tiles from one to the other.
+ /// The larger group receives the tiles of the smaller group.
+ /// The smaller group is then disposed of without deactivating its tiles.
+ /// </summary>
+ /// <param name="gridAtmosphere">The <see cref="GridAtmosphereComponent"/> of the grid.</param>
+ /// <param name="ourGroup">The first <see cref="ExcitedGroups"/> to merge.</param>
+ /// <param name="otherGroup">The second <see cref="ExcitedGroups"/> to merge.</param>
+ private void ExcitedGroupMerge(GridAtmosphereComponent gridAtmosphere, ExcitedGroup ourGroup, ExcitedGroup otherGroup)
+ {
+ DebugTools.Assert(!ourGroup.Disposed, "Excited group is disposed!");
+ DebugTools.Assert(!otherGroup.Disposed, "Excited group is disposed!");
+ DebugTools.Assert(gridAtmosphere.ExcitedGroups.Contains(ourGroup), "Grid Atmosphere does not contain Excited Group!");
+ DebugTools.Assert(gridAtmosphere.ExcitedGroups.Contains(otherGroup), "Grid Atmosphere does not contain Excited Group!");
+ var ourSize = ourGroup.Tiles.Count;
+ var otherSize = otherGroup.Tiles.Count;
+
+ ExcitedGroup winner;
+ ExcitedGroup loser;
+
+ if (ourSize > otherSize)
{
- DebugTools.Assert(!ourGroup.Disposed, "Excited group is disposed!");
- DebugTools.Assert(!otherGroup.Disposed, "Excited group is disposed!");
- DebugTools.Assert(gridAtmosphere.ExcitedGroups.Contains(ourGroup), "Grid Atmosphere does not contain Excited Group!");
- DebugTools.Assert(gridAtmosphere.ExcitedGroups.Contains(otherGroup), "Grid Atmosphere does not contain Excited Group!");
- var ourSize = ourGroup.Tiles.Count;
- var otherSize = otherGroup.Tiles.Count;
-
- ExcitedGroup winner;
- ExcitedGroup loser;
-
- if (ourSize > otherSize)
- {
- winner = ourGroup;
- loser = otherGroup;
- }
- else
- {
- winner = otherGroup;
- loser = ourGroup;
- }
-
- foreach (var tile in loser.Tiles)
- {
- tile.ExcitedGroup = winner;
- winner.Tiles.Add(tile);
- }
-
- loser.Tiles.Clear();
- ExcitedGroupDispose(gridAtmosphere, loser);
- ExcitedGroupResetCooldowns(winner);
+ winner = ourGroup;
+ loser = otherGroup;
}
-
- private void ExcitedGroupResetCooldowns(ExcitedGroup excitedGroup)
+ else
{
- DebugTools.Assert(!excitedGroup.Disposed, "Excited group is disposed!");
- excitedGroup.BreakdownCooldown = 0;
- excitedGroup.DismantleCooldown = 0;
+ winner = otherGroup;
+ loser = ourGroup;
}
- private void ExcitedGroupSelfBreakdown(
- Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent> ent,
- ExcitedGroup excitedGroup)
+ foreach (var tile in loser.Tiles)
{
- DebugTools.Assert(!excitedGroup.Disposed, "Excited group is disposed!");
- DebugTools.Assert(ent.Comp1.ExcitedGroups.Contains(excitedGroup), "Grid Atmosphere does not contain Excited Group!");
- var combined = new GasMixture(Atmospherics.CellVolume);
-
- var tileSize = excitedGroup.Tiles.Count;
+ tile.ExcitedGroup = winner;
+ winner.Tiles.Add(tile);
+ }
- if (excitedGroup.Disposed)
- return;
+ loser.Tiles.Clear();
+ ExcitedGroupDispose(gridAtmosphere, loser);
+ ExcitedGroupResetCooldowns(winner);
+ }
- if (tileSize == 0)
- {
- ExcitedGroupDispose(ent.Comp1, excitedGroup);
- return;
- }
+ /// <summary>
+ /// Resets the cooldowns of an excited group.
+ /// </summary>
+ /// <param name="excitedGroup">The <see cref="ExcitedGroups"/> to reset cooldowns for.</param>
+ private void ExcitedGroupResetCooldowns(ExcitedGroup excitedGroup)
+ {
+ DebugTools.Assert(!excitedGroup.Disposed, "Excited group is disposed!");
+ excitedGroup.BreakdownCooldown = 0;
+ excitedGroup.DismantleCooldown = 0;
+ }
- foreach (var tile in excitedGroup.Tiles)
- {
- if (tile?.Air == null)
- continue;
+ /// <summary>
+ /// Performs a final equalization on all tiles in an excited group before deactivating it.
+ /// </summary>
+ /// <param name="ent">The grid.</param>
+ /// <param name="excitedGroup">The <see cref="ExcitedGroups"/> to equalize and dissolve.</param>
+ private void ExcitedGroupSelfBreakdown(
+ Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent> ent,
+ ExcitedGroup excitedGroup)
+ {
+ DebugTools.Assert(!excitedGroup.Disposed, "Excited group is disposed!");
+ DebugTools.Assert(ent.Comp1.ExcitedGroups.Contains(excitedGroup), "Grid Atmosphere does not contain Excited Group!");
+ var combined = new GasMixture(Atmospherics.CellVolume);
- Merge(combined, tile.Air);
+ var tileSize = excitedGroup.Tiles.Count;
- if (!ExcitedGroupsSpaceIsAllConsuming || !tile.Space)
- continue;
+ if (excitedGroup.Disposed)
+ return;
- combined.Clear();
- break;
- }
+ if (tileSize == 0)
+ {
+ ExcitedGroupDispose(ent.Comp1, excitedGroup);
+ return;
+ }
- combined.Multiply(1 / (float)tileSize);
+ // Combine all gasses in the group into a single mixture
+ // for distribution into each individual tile.
+ foreach (var tile in excitedGroup.Tiles)
+ {
+ if (tile?.Air == null)
+ continue;
- foreach (var tile in excitedGroup.Tiles)
- {
- if (tile?.Air == null)
- continue;
+ Merge(combined, tile.Air);
- tile.Air.CopyFrom(combined);
- InvalidateVisuals(ent, tile);
- }
+ // If this tile is space and space is all-consuming, the final equalization
+ // will result in a vacuum, so we can skip the rest of the equalization.
+ if (!ExcitedGroupsSpaceIsAllConsuming || !tile.Space)
+ continue;
- excitedGroup.BreakdownCooldown = 0;
+ combined.Clear();
+ break;
}
- /// <summary>
- /// This de-activates and removes all tiles in an excited group.
- /// </summary>
- private void DeactivateGroupTiles(GridAtmosphereComponent gridAtmosphere, ExcitedGroup excitedGroup)
+ combined.Multiply(1 / (float)tileSize);
+
+ // Distribute the combined mixture evenly to all tiles in the group.
+ foreach (var tile in excitedGroup.Tiles)
{
- foreach (var tile in excitedGroup.Tiles)
- {
- tile.ExcitedGroup = null;
- RemoveActiveTile(gridAtmosphere, tile);
- }
+ if (tile?.Air == null)
+ continue;
- excitedGroup.Tiles.Clear();
+ tile.Air.CopyFrom(combined);
+ InvalidateVisuals(ent, tile);
}
- /// <summary>
- /// This removes an excited group without de-activating its tiles.
- /// </summary>
- private void ExcitedGroupDispose(GridAtmosphereComponent gridAtmosphere, ExcitedGroup excitedGroup)
+ excitedGroup.BreakdownCooldown = 0;
+ }
+
+ /// <summary>
+ /// Deactivates and removes all tiles from an excited group without performing a final equalization.
+ /// Used when an excited group is expected to be nearly equalized already to avoid unnecessary processing.
+ /// </summary>
+ /// <param name="gridAtmosphere">The <see cref="GridAtmosphereComponent"/> of the grid.</param>
+ /// <param name="excitedGroup">The <see cref="ExcitedGroups"/> to dissolve.</param>
+ private void DeactivateGroupTiles(GridAtmosphereComponent gridAtmosphere, ExcitedGroup excitedGroup)
+ {
+ foreach (var tile in excitedGroup.Tiles)
{
- if (excitedGroup.Disposed)
- return;
+ tile.ExcitedGroup = null;
+ RemoveActiveTile(gridAtmosphere, tile);
+ }
+
+ excitedGroup.Tiles.Clear();
+ }
- DebugTools.Assert(gridAtmosphere.ExcitedGroups.Contains(excitedGroup), "Grid Atmosphere does not contain Excited Group!");
+ /// <summary>
+ /// Removes and disposes of an excited group without performing any final equalization
+ /// or deactivation of its tiles.
+ /// </summary>
+ private void ExcitedGroupDispose(GridAtmosphereComponent gridAtmosphere, ExcitedGroup excitedGroup)
+ {
+ if (excitedGroup.Disposed)
+ return;
- excitedGroup.Disposed = true;
- gridAtmosphere.ExcitedGroups.Remove(excitedGroup);
+ DebugTools.Assert(gridAtmosphere.ExcitedGroups.Contains(excitedGroup), "Grid Atmosphere does not contain Excited Group!");
- foreach (var tile in excitedGroup.Tiles)
- {
- tile.ExcitedGroup = null;
- }
+ excitedGroup.Disposed = true;
+ gridAtmosphere.ExcitedGroups.Remove(excitedGroup);
- excitedGroup.Tiles.Clear();
+ foreach (var tile in excitedGroup.Tiles)
+ {
+ tile.ExcitedGroup = null;
}
+
+ excitedGroup.Tiles.Clear();
}
}