diff --git a/Content.Server/Atmos/AtmosHelpers.cs b/Content.Server/Atmos/AtmosHelpers.cs deleted file mode 100644 index 6203e6badd..0000000000 --- a/Content.Server/Atmos/AtmosHelpers.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using Content.Server.Atmos.EntitySystems; -using Content.Shared.Atmos; -using Robust.Shared.GameObjects; -using Robust.Shared.Map; - -namespace Content.Server.Atmos -{ - public static class AtmosHelpers - { - public static TileAtmosphere? GetTileAtmosphere(this EntityCoordinates coordinates) - { - return EntitySystem.Get().GetGridAtmosphere(coordinates).GetTile(coordinates); - } - - public static GasMixture? GetTileAir(this EntityCoordinates coordinates, IEntityManager? entityManager = null) - { - return coordinates.GetTileAtmosphere()?.Air; - } - - public static bool TryGetTileAtmosphere(this EntityCoordinates coordinates, [NotNullWhen(true)] out TileAtmosphere? atmosphere) - { - // ReSharper disable once ConditionIsAlwaysTrueOrFalse - return !Equals(atmosphere = coordinates.GetTileAtmosphere(), default); - } - - public static bool TryGetTileAir(this EntityCoordinates coordinates, [NotNullWhen(true)] out GasMixture? air, IEntityManager? entityManager = null) - { - // ReSharper disable once ConditionIsAlwaysTrueOrFalse - return !Equals(air = coordinates.GetTileAir(entityManager), default); - } - - public static bool IsTileAirProbablySafe(this EntityCoordinates coordinates) - { - // Note that oxygen mix isn't checked, but survival boxes make that not necessary. - var air = coordinates.GetTileAir(); - if (air == null) - return false; - if (air.Pressure <= Atmospherics.WarningLowPressure) - return false; - if (air.Pressure >= Atmospherics.WarningHighPressure) - return false; - if (air.Temperature <= 260) - return false; - if (air.Temperature >= 360) - return false; - return true; - } - - public static bool InvalidateTileAir(this EntityCoordinates coordinates) - { - if (!coordinates.TryGetTileAtmosphere(out var tileAtmos)) - { - return false; - } - - tileAtmos.Invalidate(); - return true; - } - } -} diff --git a/Content.Server/Atmos/Components/AirtightComponent.cs b/Content.Server/Atmos/Components/AirtightComponent.cs index a6b038e675..4e0eb577a8 100644 --- a/Content.Server/Atmos/Components/AirtightComponent.cs +++ b/Content.Server/Atmos/Components/AirtightComponent.cs @@ -16,7 +16,6 @@ namespace Content.Server.Atmos.Components [Dependency] private readonly IMapManager _mapManager = default!; private (GridId, Vector2i) _lastPosition; - private AtmosphereSystem _atmosphereSystem = default!; public override string Name => "Airtight"; @@ -76,8 +75,6 @@ namespace Content.Server.Atmos.Components { base.Initialize(); - _atmosphereSystem = EntitySystem.Get(); - if (_fixAirBlockedDirectionInitialize) RotateEvent(new RotateEvent(Owner, Angle.Zero, Owner.Transform.WorldRotation)); @@ -132,7 +129,7 @@ namespace Content.Server.Atmos.Components if (_fixVacuum) { - _atmosphereSystem.GetGridAtmosphere(_lastPosition.Item1)?.FixVacuum(_lastPosition.Item2); + EntitySystem.Get().FixVacuum(_lastPosition.Item1, _lastPosition.Item2); } } @@ -164,10 +161,9 @@ namespace Content.Server.Atmos.Components if (!gridId.IsValid()) return; - var gridAtmos = _atmosphereSystem.GetGridAtmosphere(gridId); - - gridAtmos?.UpdateAdjacentBits(pos); - gridAtmos?.Invalidate(pos); + var atmosphereSystem = EntitySystem.Get(); + atmosphereSystem.UpdateAdjacent(gridId, pos); + atmosphereSystem.InvalidateTile(gridId, pos); } } } diff --git a/Content.Server/Atmos/Components/FirelockComponent.cs b/Content.Server/Atmos/Components/FirelockComponent.cs index fdcfb991aa..fde0c1353d 100644 --- a/Content.Server/Atmos/Components/FirelockComponent.cs +++ b/Content.Server/Atmos/Components/FirelockComponent.cs @@ -74,15 +74,12 @@ namespace Content.Server.Atmos.Components { var atmosphereSystem = EntitySystem.Get(); - var gridAtmosphere = atmosphereSystem.GetGridAtmosphere(Owner.Transform.Coordinates); - var minMoles = float.MaxValue; var maxMoles = 0f; - foreach (var (_, adjacent) in gridAtmosphere.GetAdjacentTiles(Owner.Transform.Coordinates)) + foreach (var adjacent in atmosphereSystem.GetAdjacentTileMixtures(Owner.Transform.Coordinates)) { - // includeAirBlocked remains false, and therefore Air must be present - var moles = adjacent.Air!.TotalMoles; + var moles = adjacent.TotalMoles; if (moles < minMoles) minMoles = moles; if (moles > maxMoles) @@ -96,17 +93,18 @@ namespace Content.Server.Atmos.Components { var atmosphereSystem = EntitySystem.Get(); - if (!Owner.Transform.Coordinates.TryGetTileAtmosphere(out var tileAtmos)) + if (!atmosphereSystem.TryGetGridAndTile(Owner.Transform.Coordinates, out var tuple)) return false; - if (tileAtmos.Hotspot.Valid) + if (atmosphereSystem.GetTileMixture(tuple.Value.Grid, tuple.Value.Tile) == null) + return false; + + if (atmosphereSystem.IsHotspotActive(tuple.Value.Grid, tuple.Value.Tile)) return true; - var gridAtmosphere = atmosphereSystem.GetGridAtmosphere(Owner.Transform.Coordinates); - - foreach (var (_, adjacent) in gridAtmosphere.GetAdjacentTiles(tileAtmos.GridIndices)) + foreach (var adjacent in atmosphereSystem.GetAdjacentTiles(Owner.Transform.Coordinates)) { - if (adjacent.Hotspot.Valid) + if (atmosphereSystem.IsHotspotActive(tuple.Value.Grid, adjacent)) return true; } diff --git a/Content.Server/Atmos/Components/GasAnalyzerComponent.cs b/Content.Server/Atmos/Components/GasAnalyzerComponent.cs index 0b2e4de32a..1e09798edd 100644 --- a/Content.Server/Atmos/Components/GasAnalyzerComponent.cs +++ b/Content.Server/Atmos/Components/GasAnalyzerComponent.cs @@ -123,8 +123,7 @@ namespace Content.Server.Atmos.Components { // Already get the pressure before Dirty(), because we can't get the EntitySystem in that thread or smth var pressure = 0f; - var gam = EntitySystem.Get().GetGridAtmosphere(Owner.Transform.Coordinates); - var tile = gam?.GetTile(Owner.Transform.Coordinates)?.Air; + var tile = EntitySystem.Get().GetTileMixture(Owner.Transform.Coordinates); if (tile != null) { pressure = tile.Pressure; @@ -182,9 +181,8 @@ namespace Content.Server.Atmos.Components pos = _position.Value; } - var atmosSystem = EntitySystem.Get(); - var gam = atmosSystem.GetGridAtmosphere(pos); - var tile = gam.GetTile(pos)?.Air; + var atmosphereSystem = EntitySystem.Get(); + var tile = atmosphereSystem.GetTileMixture(pos); if (tile == null) { error = "No Atmosphere!"; @@ -201,7 +199,7 @@ namespace Content.Server.Atmos.Components for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++) { - var gas = atmosSystem.GetGas(i); + var gas = atmosphereSystem.GetGas(i); if (tile.Moles[i] <= Atmospherics.GasMinMoles) continue; diff --git a/Content.Server/Atmos/Components/GasTankComponent.cs b/Content.Server/Atmos/Components/GasTankComponent.cs index 35e9201d25..e98aaed7b9 100644 --- a/Content.Server/Atmos/Components/GasTankComponent.cs +++ b/Content.Server/Atmos/Components/GasTankComponent.cs @@ -278,8 +278,9 @@ namespace Content.Server.Atmos.Components { if (_integrity <= 0) { - var tileAtmos = Owner.Transform.Coordinates.GetTileAtmosphere(); - tileAtmos?.AssumeAir(Air); + var environment = atmosphereSystem.GetTileMixture(Owner.Transform.Coordinates, true); + if(environment != null) + atmosphereSystem.Merge(environment, Air); SoundSystem.Play(Filter.Pvs(Owner), "Audio/Effects/spray.ogg", Owner.Transform.Coordinates, AudioHelpers.WithVariation(0.125f)); @@ -296,12 +297,12 @@ namespace Content.Server.Atmos.Components { if (_integrity <= 0) { - var tileAtmos = Owner.Transform.Coordinates.GetTileAtmosphere(); - if (tileAtmos == null) + var environment = atmosphereSystem.GetTileMixture(Owner.Transform.Coordinates, true); + if (environment == null) return; var leakedGas = Air.RemoveRatio(0.25f); - tileAtmos.AssumeAir(leakedGas); + atmosphereSystem.Merge(environment, leakedGas); } else { diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Grid.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Grid.cs new file mode 100644 index 0000000000..dd31f27527 --- /dev/null +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Grid.cs @@ -0,0 +1,1000 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Content.Server.Atmos.Components; +using Content.Server.Atmos.Reactions; +using Content.Shared.Atmos; +using Robust.Shared.Map; +using Robust.Shared.Maths; + +namespace Content.Server.Atmos.EntitySystems +{ + public partial class AtmosphereSystem + { + #region Get GridAtmosphere + + public IGridAtmosphereComponent? GetGridAtmosphere(GridId gridId) + { + if (!gridId.IsValid()) + return null; + + if (!_mapManager.TryGetGrid(gridId, out var grid)) + return null; + + return ComponentManager.TryGetComponent(grid.GridEntityId, out IGridAtmosphereComponent? gridAtmosphere) + ? gridAtmosphere : null; + } + + public IGridAtmosphereComponent GetGridAtmosphere(EntityCoordinates coordinates) + { + return GetGridAtmosphere(coordinates.ToMap(EntityManager)); + } + + public IGridAtmosphereComponent GetGridAtmosphere(MapCoordinates coordinates) + { + if (coordinates.MapId == MapId.Nullspace) + { + throw new ArgumentException($"Coordinates cannot be in nullspace!", nameof(coordinates)); + } + + if (_mapManager.TryFindGridAt(coordinates, out var grid)) + { + if (ComponentManager.TryGetComponent(grid.GridEntityId, out IGridAtmosphereComponent? atmos)) + { + return atmos; + } + } + + return _mapManager.GetMapEntity(coordinates.MapId).GetComponent(); + } + + /// + /// Unlike GetGridAtmosphere, this doesn't return space grid when not found. + /// + public bool TryGetSimulatedGridAtmosphere(MapCoordinates coordinates, [NotNullWhen(true)] out IGridAtmosphereComponent? atmosphere) + { + if (coordinates.MapId == MapId.Nullspace) + { + atmosphere = null; + return false; + } + + if (_mapManager.TryFindGridAt(coordinates, out var mapGrid) + && ComponentManager.TryGetComponent(mapGrid.GridEntityId, out IGridAtmosphereComponent? atmosGrid) + && atmosGrid.Simulated) + { + atmosphere = atmosGrid; + return true; + } + + atmosphere = null; + return false; + } + + #endregion + + #region Grid Is Simulated + + /// + /// Returns whether a grid has a simulated atmosphere. + /// + /// Coordinates to be checked. + /// Whether the grid has a simulated atmosphere. + public bool IsSimulatedGrid(MapCoordinates coordinates) + { + if (TryGetGridAndTile(coordinates, out var tuple)) + return IsSimulatedGrid(tuple.Value.Grid); + + return false; + } + + /// + /// Returns whether a grid has a simulated atmosphere. + /// + /// Coordinates to be checked. + /// Whether the grid has a simulated atmosphere. + public bool IsSimulatedGrid(EntityCoordinates coordinates) + { + if (TryGetGridAndTile(coordinates, out var tuple)) + return IsSimulatedGrid(tuple.Value.Grid); + + return false; + } + + /// + /// Returns whether a grid has a simulated atmosphere. + /// + /// Grid to be checked. + /// Whether the grid has a simulated atmosphere. + public bool IsSimulatedGrid(GridId grid) + { + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) + return false; + + if (ComponentManager.HasComponent(mapGrid.GridEntityId)) + return true; + + return false; + } + + #endregion + + #region Grid Get All Mixtures + + /// + /// Gets all tile mixtures within a grid atmosphere, optionally invalidating them all. + /// + /// Coordinates where to get the grid to get all tile mixtures from. + /// Whether to invalidate all tiles. + /// All tile mixtures in a grid. + public IEnumerable GetAllTileMixtures(MapCoordinates coordinates, bool invalidate = false) + { + if (TryGetGridAndTile(coordinates, out var tuple)) + return GetAllTileMixtures(tuple.Value.Grid, invalidate); + + return Enumerable.Empty(); + } + + /// + /// Gets all tile mixtures within a grid atmosphere, optionally invalidating them all. + /// + /// Coordinates where to get the grid to get all tile mixtures from. + /// Whether to invalidate all tiles. + /// All tile mixtures in a grid. + public IEnumerable GetAllTileMixtures(EntityCoordinates coordinates, bool invalidate = false) + { + if (TryGetGridAndTile(coordinates, out var tuple)) + return GetAllTileMixtures(tuple.Value.Grid, invalidate); + + return Enumerable.Empty(); + } + + /// + /// Gets all tile mixtures within a grid atmosphere, optionally invalidating them all. + /// + /// Grid where to get all tile mixtures from. + /// Whether to invalidate all tiles. + /// All tile mixtures in a grid. + public IEnumerable GetAllTileMixtures(GridId grid, bool invalidate = false) + { + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) + yield break; + + if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) + { + foreach (var tileAtmos in gridAtmosphere) + { + if (tileAtmos?.Air == null) + continue; + + if(invalidate) + tileAtmos.Invalidate(); + + yield return tileAtmos.Air; + } + } + } + + #endregion + + #region Invalidate + + /// + /// Invalidates a tile at a certain position. + /// + /// + public void InvalidateTile(MapCoordinates coordinates) + { + if(TryGetGridAndTile(coordinates, out var tuple)) + InvalidateTile(tuple.Value.Grid, tuple.Value.Tile); + } + + /// + /// Invalidates a tile at a certain position. + /// + /// + public void InvalidateTile(EntityCoordinates coordinates) + { + if(TryGetGridAndTile(coordinates, out var tuple)) + InvalidateTile(tuple.Value.Grid, tuple.Value.Tile); + } + + /// + /// Invalidates a tile at a certain position. + /// + /// Grid where to invalidate the tile. + /// The tile's indices. + public void InvalidateTile(GridId grid, Vector2i position) + { + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) + return; + + if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) + { + gridAtmosphere.Invalidate(position); + return; + } + } + + #endregion + + #region Tile Active Add + + /// + /// Makes a tile become active and start processing. + /// + /// Coordinates where to get the tile. + public void AddActiveTile(MapCoordinates coordinates) + { + if(TryGetGridAndTile(coordinates, out var tuple)) + AddActiveTile(tuple.Value.Grid, tuple.Value.Tile); + } + + /// + /// Makes a tile become active and start processing. + /// + /// Coordinates where to get the tile. + public void AddActiveTile(EntityCoordinates coordinates) + { + if(TryGetGridAndTile(coordinates, out var tuple)) + AddActiveTile(tuple.Value.Grid, tuple.Value.Tile); + } + + /// + /// Makes a tile become active and start processing. + /// + /// Grid where to get the tile. + /// Indices of the tile to be activated. + public void AddActiveTile(GridId grid, Vector2i tile) + { + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) + return; + + if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) + { + var tileAtmosphere = gridAtmosphere.GetTile(tile)!; + gridAtmosphere.AddActiveTile(tileAtmosphere); + return; + } + } + + #endregion + + #region Tile Active Remove + + /// + /// Makes a tile become inactive and stop processing. + /// + /// Coordinates where to get the tile. + /// Whether to dispose of the tile's + public void RemoveActiveTile(MapCoordinates coordinates, bool disposeExcitedGroup = false) + { + if(TryGetGridAndTile(coordinates, out var tuple)) + RemoveActiveTile(tuple.Value.Grid, tuple.Value.Tile, disposeExcitedGroup); + } + + /// + /// Makes a tile become inactive and stop processing. + /// + /// Coordinates where to get the tile. + /// Whether to dispose of the tile's + public void RemoveActiveTile(EntityCoordinates coordinates, bool disposeExcitedGroup = false) + { + if(TryGetGridAndTile(coordinates, out var tuple)) + RemoveActiveTile(tuple.Value.Grid, tuple.Value.Tile, disposeExcitedGroup); + } + + /// + /// Makes a tile become inactive and stop processing. + /// + /// Grid where to get the tile. + /// Indices of the tile to be activated. + /// Whether to dispose of the tile's + public void RemoveActiveTile(GridId grid, Vector2i tile, bool disposeExcitedGroup = false) + { + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) + return; + + if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) + { + var tileAtmosphere = gridAtmosphere.GetTile(tile)!; + gridAtmosphere.RemoveActiveTile(tileAtmosphere, disposeExcitedGroup); + return; + } + } + + #endregion + + #region Tile Mixture + + /// + /// Returns a reference to the gas mixture on a tile, or null. + /// + /// Coordinates where to get the tile. + /// Whether to invalidate the tile. + /// The tile mixture, or null + public GasMixture? GetTileMixture(MapCoordinates coordinates, bool invalidate = false) + { + return TryGetGridAndTile(coordinates, out var tuple) + ? GetTileMixture(tuple.Value.Grid, tuple.Value.Tile, invalidate) : null; + } + + /// + /// Returns a reference to the gas mixture on a tile, or null. + /// + /// Coordinates where to get the tile. + /// Whether to invalidate the tile. + /// The tile mixture, or null + public GasMixture? GetTileMixture(EntityCoordinates coordinates, bool invalidate = false) + { + return TryGetGridAndTile(coordinates, out var tuple) + ? GetTileMixture(tuple.Value.Grid, tuple.Value.Tile, invalidate) : null; + } + + /// + /// Returns a reference to the gas mixture on a tile, or null. + /// + /// Grid where to get the tile air. + /// Indices of the tile. + /// Whether to invalidate the tile. + /// The tile mixture, or null + public GasMixture? GetTileMixture(GridId grid, Vector2i position, bool invalidate = false) + { + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) + return null; + + if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) + { + // Invalidate the tile if needed. + if(invalidate) + gridAtmosphere.Invalidate(position); + + // Return actual tile air or null. + return gridAtmosphere.GetTile(position)?.Air; + } + + if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out SpaceGridAtmosphereComponent? spaceAtmosphere)) + { + // Always return a new space gas mixture in this case. + return GasMixture.SpaceGas; + } + + return null; + } + + #endregion + + #region Tile React + + /// + /// Causes a gas mixture reaction on a specific tile. + /// + /// Coordinates where to get the tile. + /// Reaction results. + public ReactionResult React(MapCoordinates coordinates) + { + if (TryGetGridAndTile(coordinates, out var tuple)) + return React(tuple.Value.Grid, tuple.Value.Tile); + + return ReactionResult.NoReaction; + } + + /// + /// Causes a gas mixture reaction on a specific tile. + /// + /// Coordinates where to get the tile. + /// Reaction results. + public ReactionResult React(EntityCoordinates coordinates) + { + if (TryGetGridAndTile(coordinates, out var tuple)) + return React(tuple.Value.Grid, tuple.Value.Tile); + + return ReactionResult.NoReaction; + } + + /// + /// Causes a gas mixture reaction on a specific tile. + /// + /// Grid where to get the tile. + /// Indices of the tile. + /// Reaction results. + public ReactionResult React(GridId grid, Vector2i tile) + { + var atmosphere = GetGridAtmosphere(grid); + atmosphere?.Invalidate(tile); + + var tileAtmosphere = atmosphere?.GetTile(tile); + return tileAtmosphere?.Air == null ? ReactionResult.NoReaction : React(tileAtmosphere.Air, tileAtmosphere); + } + + #endregion + + #region Tile Airblocked + + /// + /// Returns if the tile in question is "air-blocked" in a certain direction or not. + /// This could be due to a number of reasons, such as walls, doors, etc. + /// + /// Coordinates where to get the tile. + /// Directions to check. + /// Whether the tile is blocked in the directions specified. + public bool IsTileAirBlocked(MapCoordinates coordinates, AtmosDirection direction = AtmosDirection.All) + { + if (TryGetGridAndTile(coordinates, out var tuple)) + return IsTileAirBlocked(tuple.Value.Grid, tuple.Value.Tile, direction); + + return false; + } + + /// + /// Returns if the tile in question is "air-blocked" in a certain direction or not. + /// This could be due to a number of reasons, such as walls, doors, etc. + /// + /// Coordinates where to get the tile. + /// Directions to check. + /// Whether the tile is blocked in the directions specified. + public bool IsTileAirBlocked(EntityCoordinates coordinates, AtmosDirection direction = AtmosDirection.All) + { + if (TryGetGridAndTile(coordinates, out var tuple)) + return IsTileAirBlocked(tuple.Value.Grid, tuple.Value.Tile, direction); + + return false; + } + + /// + /// Returns if the tile in question is "air-blocked" in a certain direction or not. + /// This could be due to a number of reasons, such as walls, doors, etc. + /// + /// Grid where to get the tile. + /// Indices of the tile. + /// Directions to check. + /// Whether the tile is blocked in the directions specified. + public bool IsTileAirBlocked(GridId grid, Vector2i tile, AtmosDirection direction = AtmosDirection.All) + { + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) + return false; + + if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) + { + return gridAtmosphere.IsAirBlocked(tile, direction); + } + + return false; + } + + #endregion + + #region Tile Space + + /// + /// Returns whether the specified tile is a space tile or not. + /// + /// Coordinates where to check the tile. + /// Whether the tile is space or not. + public bool IsTileSpace(MapCoordinates coordinates) + { + if (TryGetGridAndTile(coordinates, out var tuple)) + return IsTileSpace(tuple.Value.Grid, tuple.Value.Tile); + + return true; + } + + /// + /// Returns whether the specified tile is a space tile or not. + /// + /// Coordinates where to check the tile. + /// Whether the tile is space or not. + public bool IsTileSpace(EntityCoordinates coordinates) + { + if (TryGetGridAndTile(coordinates, out var tuple)) + return IsTileSpace(tuple.Value.Grid, tuple.Value.Tile); + + return true; + } + + /// + /// Returns whether the specified tile is a space tile or not. + /// + /// Grid where to check the tile. + /// Indices of the tile. + /// Whether the tile is space or not. + public bool IsTileSpace(GridId grid, Vector2i tile) + { + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) + return true; + + if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) + { + return gridAtmosphere.IsSpace(tile); + } + + return true; + } + + #endregion + + #region Adjacent Get Positions + + /// + /// Gets all the positions adjacent to a tile. Can include air-blocked directions. + /// + /// Coordinates where to get the tile. + /// Whether to include tiles in directions the tile is air-blocked in. + /// The positions adjacent to the tile. + public IEnumerable GetAdjacentTiles(MapCoordinates coordinates, bool includeBlocked = false) + { + if (TryGetGridAndTile(coordinates, out var tuple)) + return GetAdjacentTiles(tuple.Value.Grid, tuple.Value.Tile, includeBlocked); + + return Enumerable.Empty(); + } + + /// + /// Gets all the positions adjacent to a tile. Can include air-blocked directions. + /// + /// Coordinates where to get the tile. + /// Whether to include tiles in directions the tile is air-blocked in. + /// The positions adjacent to the tile. + public IEnumerable GetAdjacentTiles(EntityCoordinates coordinates, bool includeBlocked = false) + { + if (TryGetGridAndTile(coordinates, out var tuple)) + return GetAdjacentTiles(tuple.Value.Grid, tuple.Value.Tile, includeBlocked); + + return Enumerable.Empty(); + } + + /// + /// Gets all the positions adjacent to a tile. Can include air-blocked directions. + /// + /// Grid where to get the tiles. + /// Indices of the tile. + /// Whether to include tiles in directions the tile is air-blocked in. + /// The positions adjacent to the tile. + public IEnumerable GetAdjacentTiles(GridId grid, Vector2i tile, bool includeBlocked = false) + { + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) + yield break; + + if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) + { + var tileAtmos = gridAtmosphere.GetTile(tile)!; + + for (var i = 0; i < tileAtmos.AdjacentTiles.Count; i++) + { + var adjacentTile = tileAtmos.AdjacentTiles[i]; + // TileAtmosphere has nullable disabled, so just in case... + // ReSharper disable once ConditionIsAlwaysTrueOrFalse + if (adjacentTile?.Air == null) + continue; + + if (!includeBlocked) + { + var direction = (AtmosDirection) (1 << i); + if (tileAtmos.BlockedAirflow.IsFlagSet(direction)) + continue; + } + + yield return adjacentTile.GridIndices; + } + } + } + + #endregion + + #region Adjacent Get Mixture + + /// + /// Gets all tile gas mixtures adjacent to a specific tile, and optionally invalidates them. + /// Does not return the tile in question, only the adjacent ones. Can include air-blocked directions. + /// + /// Coordinates where to get the tile. + /// Whether to include tiles in directions the tile is air-blocked in. + /// Whether to invalidate all adjacent tiles. + /// All adjacent tile gas mixtures to the tile in question + public IEnumerable GetAdjacentTileMixtures(MapCoordinates coordinates, bool includeBlocked = false, bool invalidate = false) + { + if (TryGetGridAndTile(coordinates, out var tuple)) + return GetAdjacentTileMixtures(tuple.Value.Grid, tuple.Value.Tile); + + return Enumerable.Empty(); + } + + /// + /// Gets all tile gas mixtures adjacent to a specific tile, and optionally invalidates them. + /// Does not return the tile in question, only the adjacent ones. + /// + /// Coordinates where to get the tile. + /// Whether to include tiles in directions the tile is air-blocked in. + /// Whether to invalidate all adjacent tiles. + /// All adjacent tile gas mixtures to the tile in question + public IEnumerable GetAdjacentTileMixtures(EntityCoordinates coordinates, bool includeBlocked = false, bool invalidate = false) + { + if (TryGetGridAndTile(coordinates, out var tuple)) + return GetAdjacentTileMixtures(tuple.Value.Grid, tuple.Value.Tile); + + return Enumerable.Empty(); + } + + /// + /// Gets all tile gas mixtures adjacent to a specific tile, and optionally invalidates them. + /// Does not return the tile in question, only the adjacent ones. + /// + /// Grid where to get the tile. + /// Indices of the tile. + /// Whether to include tiles in directions the tile is air-blocked in. + /// Whether to invalidate all adjacent tiles. + /// All adjacent tile gas mixtures to the tile in question + public IEnumerable GetAdjacentTileMixtures(GridId grid, Vector2i tile, bool includeBlocked = false, bool invalidate = false) + { + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) + yield break; + + if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) + { + var tileAtmos = gridAtmosphere.GetTile(tile)!; + + for (var i = 0; i < tileAtmos.AdjacentTiles.Count; i++) + { + var adjacentTile = tileAtmos.AdjacentTiles[i]; + + // TileAtmosphere has nullable disabled, so just in case... + // ReSharper disable once ConditionIsAlwaysTrueOrFalse + if (adjacentTile?.Air == null) + continue; + + if (!includeBlocked) + { + var direction = (AtmosDirection) (1 << i); + if (tileAtmos.BlockedAirflow.IsFlagSet(direction)) + continue; + } + + if (invalidate) + adjacentTile.Invalidate(); + + yield return adjacentTile.Air; + } + } + } + + #endregion + + #region Adjacent Update + + /// + /// Immediately updates a tile's blocked air directions. + /// + /// Coordinates where to get the tile. + public void UpdateAdjacent(MapCoordinates coordinates) + { + if(TryGetGridAndTile(coordinates, out var tuple)) + UpdateAdjacent(tuple.Value.Grid, tuple.Value.Tile); + } + + /// + /// Immediately updates a tile's blocked air directions. + /// + /// Coordinates where to get the tile. + public void UpdateAdjacent(EntityCoordinates coordinates) + { + if(TryGetGridAndTile(coordinates, out var tuple)) + UpdateAdjacent(tuple.Value.Grid, tuple.Value.Tile); + } + + /// + /// Immediately updates a tile's blocked air directions. + /// + /// Grid where to get the tile. + /// Indices of the tile. + public void UpdateAdjacent(GridId grid, Vector2i tile) + { + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) + return; + + if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) + { + gridAtmosphere.UpdateAdjacentBits(tile); + return; + } + } + + #endregion + + #region Hotspot Expose + + /// + /// Exposes temperature to a tile, creating a hotspot (fire) if the conditions are ideal. + /// Can also be used to make an existing hotspot hotter/bigger. Also invalidates the tile. + /// + /// Coordinates where to get the tile. + /// Temperature to expose to the tile. + /// Volume of the exposed temperature. + /// If true, the existing hotspot values will be set to the exposed values, but only if they're smaller. + public void HotspotExpose(MapCoordinates coordinates, float exposedTemperature, float exposedVolume, bool soh = false) + { + if(TryGetGridAndTile(coordinates, out var tuple)) + HotspotExpose(tuple.Value.Grid, tuple.Value.Tile, exposedTemperature, exposedVolume, soh); + } + + /// + /// Exposes temperature to a tile, creating a hotspot (fire) if the conditions are ideal. + /// Can also be used to make an existing hotspot hotter/bigger. Also invalidates the tile. + /// + /// Coordinates where to get the tile. + /// Temperature to expose to the tile. + /// Volume of the exposed temperature. + /// If true, the existing hotspot values will be set to the exposed values, but only if they're smaller. + public void HotspotExpose(EntityCoordinates coordinates, float exposedTemperature, float exposedVolume, bool soh = false) + { + if(TryGetGridAndTile(coordinates, out var tuple)) + HotspotExpose(tuple.Value.Grid, tuple.Value.Tile, exposedTemperature, exposedVolume, soh); + } + + /// + /// Exposes temperature to a tile, creating a hotspot (fire) if the conditions are ideal. + /// Can also be used to make an existing hotspot hotter/bigger. Also invalidates the tile. + /// + /// Grid where to get the tile. + /// Indices of the tile. + /// Temperature to expose to the tile. + /// Volume of the exposed temperature. + /// If true, the existing hotspot values will be set to the exposed values, but only if they're smaller. + public void HotspotExpose(GridId grid, Vector2i tile, float exposedTemperature, float exposedVolume, bool soh = false) + { + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) + return; + + if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) + { + gridAtmosphere.GetTile(tile, false)?.HotspotExpose(exposedTemperature, exposedVolume, soh); + gridAtmosphere.Invalidate(tile); + return; + } + } + + #endregion + + #region Hotspot Extinguish + + /// + /// Extinguishes a hotspot (fire) on a certain tile, if any. Also invalidates the tile. + /// + /// Coordinates where to get the tile. + public void HotspotExtinguish(MapCoordinates coordinates) + { + if(TryGetGridAndTile(coordinates, out var tuple)) + HotspotExtinguish(tuple.Value.Grid, tuple.Value.Tile); + } + + /// + /// Extinguishes a hotspot (fire) on a certain tile, if any. Also invalidates the tile. + /// + /// Coordinates where to get the tile. + public void HotspotExtinguish(EntityCoordinates coordinates) + { + if(TryGetGridAndTile(coordinates, out var tuple)) + HotspotExtinguish(tuple.Value.Grid, tuple.Value.Tile); + } + + /// + /// Extinguishes a hotspot (fire) on a certain tile, if any. Also invalidates the tile. + /// + /// Grid where to get the tile. + /// Indices of the tile. + public void HotspotExtinguish(GridId grid, Vector2i tile) + { + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) + return; + + if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) + { + var tileAtmos = gridAtmosphere.GetTile(tile); + + if (tileAtmos != null) + { + tileAtmos.Hotspot = new Hotspot(); + gridAtmosphere.Invalidate(tile); + } + + return; + } + } + + #endregion + + #region Hotspot Active + + /// + /// Returns whether there's an active hotspot (fire) on a certain tile. + /// + /// Position where to get the tile. + /// Whether the hotspot is active or not. + public bool IsHotspotActive(MapCoordinates coordinates) + { + if (TryGetGridAndTile(coordinates, out var tuple)) + return IsHotspotActive(tuple.Value.Grid, tuple.Value.Tile); + + return false; + } + + /// + /// Returns whether there's an active hotspot (fire) on a certain tile. + /// + /// Position where to get the tile. + /// Whether the hotspot is active or not. + public bool IsHotspotActive(EntityCoordinates coordinates) + { + if (TryGetGridAndTile(coordinates, out var tuple)) + return IsHotspotActive(tuple.Value.Grid, tuple.Value.Tile); + + return false; + } + + /// + /// Returns whether there's an active hotspot (fire) on a certain tile. + /// + /// Grid where to get the tile + /// Indices for the tile + /// Whether the hotspot is active or not. + public bool IsHotspotActive(GridId grid, Vector2i tile) + { + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) + return false; + + if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) + { + return gridAtmosphere.GetTile(tile, false)?.Hotspot.Valid ?? false; + } + + return false; + } + + #endregion + + #region Mixture Safety + + /// + /// Checks whether a tile's gas mixture is probably safe. + /// This only checks temperature and pressure, not gas composition. + /// + /// Coordinates where to get the tile. + /// Whether the tile's gas mixture is probably safe. + public bool IsTileMixtureProbablySafe(MapCoordinates coordinates) + { + return IsMixtureProbablySafe(GetTileMixture(coordinates)); + } + + /// + /// Checks whether a tile's gas mixture is probably safe. + /// This only checks temperature and pressure, not gas composition. + /// + /// Coordinates where to get the tile. + /// Whether the tile's gas mixture is probably safe. + public bool IsTileMixtureProbablySafe(EntityCoordinates coordinates) + { + return IsMixtureProbablySafe(GetTileMixture(coordinates)); + } + + /// + /// Checks whether a tile's gas mixture is probably safe. + /// This only checks temperature and pressure, not gas composition. + /// + /// Grid where to get the tile. + /// Indices of the tile. + /// Whether the tile's gas mixture is probably safe. + public bool IsTileMixtureProbablySafe(GridId grid, Vector2i tile) + { + return IsMixtureProbablySafe(GetTileMixture(grid, tile)); + } + + /// + /// Checks whether a gas mixture is probably safe. + /// This only checks temperature and pressure, not gas composition. + /// + /// Mixture to be checked. + /// Whether the mixture is probably safe. + public bool IsMixtureProbablySafe(GasMixture? air) + { + // Note that oxygen mix isn't checked, but survival boxes make that not necessary. + if (air == null) + return false; + + switch (air.Pressure) + { + case <= Atmospherics.WarningLowPressure: + case >= Atmospherics.WarningHighPressure: + return false; + } + + switch (air.Temperature) + { + case <= 260: + case >= 360: + return false; + } + + return true; + } + + #endregion + + #region Fix Vacuum + + /// + /// Attempts to fix a sudden vacuum by creating gas based on adjacent tiles. + /// + /// Coordinates where to get the tile. + public void FixVacuum(MapCoordinates coordinates) + { + if(TryGetGridAndTile(coordinates, out var tuple)) + FixVacuum(tuple.Value.Grid, tuple.Value.Tile); + } + + /// + /// Attempts to fix a sudden vacuum by creating gas based on adjacent tiles. + /// + /// Coordinates where to get the tile. + public void FixVacuum(EntityCoordinates coordinates) + { + if(TryGetGridAndTile(coordinates, out var tuple)) + FixVacuum(tuple.Value.Grid, tuple.Value.Tile); + } + + /// + /// Attempts to fix a sudden vacuum by creating gas based on adjacent tiles. + /// + /// Grid where to get the tile. + /// Indices of the tile. + public void FixVacuum(GridId grid, Vector2i tile) + { + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) + return; + + if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) + { + gridAtmosphere.FixVacuum(tile); + + return; + } + } + + #endregion + + #region Position Helpers + + public bool TryGetGridAndTile(MapCoordinates coordinates, [NotNullWhen(true)] out (GridId Grid, Vector2i Tile)? tuple) + { + if (!_mapManager.TryFindGridAt(coordinates, out var grid)) + { + tuple = null; + return false; + } + + tuple = (grid.Index, grid.TileIndicesFor(coordinates)); + return true; + } + + public bool TryGetGridAndTile(EntityCoordinates coordinates, [NotNullWhen(true)] out (GridId Grid, Vector2i Tile)? tuple) + { + if (!coordinates.IsValid(EntityManager)) + { + tuple = null; + return false; + } + + var gridId = coordinates.GetGridId(EntityManager); + + if (!_mapManager.TryGetGrid(gridId, out var grid)) + { + tuple = null; + return false; + } + + tuple = (gridId, grid.TileIndicesFor(coordinates)); + return true; + } + + #endregion + } +} diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs index 2094d2a52e..4d6163868a 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs @@ -1,17 +1,12 @@ -using System; -using System.Diagnostics.CodeAnalysis; using Content.Server.Atmos.Components; using Content.Server.NodeContainer.EntitySystems; using Content.Shared.Atmos.EntitySystems; using Content.Shared.Maps; using JetBrains.Annotations; -using Robust.Server.GameObjects; using Robust.Shared.Configuration; -using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Map; using Robust.Shared.Prototypes; -using Robust.Shared.Timing; namespace Content.Server.Atmos.EntitySystems { @@ -20,16 +15,11 @@ namespace Content.Server.Atmos.EntitySystems { [Dependency] private readonly IPrototypeManager _protoMan = default!; [Dependency] private readonly IMapManager _mapManager = default!; - [Dependency] private readonly IPauseManager _pauseManager = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; - private GridTileLookupSystem? _gridTileLookup = null; - private const float ExposedUpdateDelay = 1f; private float _exposedTimer = 0f; - public GridTileLookupSystem GridTileLookupSystem => _gridTileLookup ??= Get(); - public override void Initialize() { base.Initialize(); @@ -81,73 +71,6 @@ namespace Content.Server.Atmos.EntitySystems map.AddComponent(); } - #region Helper Methods - public IGridAtmosphereComponent? GetGridAtmosphere(GridId gridId) - { - if (!gridId.IsValid()) - return null; - - if (!_mapManager.TryGetGrid(gridId, out var grid)) - return null; - - return ComponentManager.TryGetComponent(grid.GridEntityId, out IGridAtmosphereComponent? gridAtmosphere) - ? gridAtmosphere : null; - } - - public IGridAtmosphereComponent GetGridAtmosphere(EntityCoordinates coordinates) - { - return GetGridAtmosphere(coordinates.ToMap(EntityManager)); - } - - public IGridAtmosphereComponent GetGridAtmosphere(MapCoordinates coordinates) - { - if (coordinates.MapId == MapId.Nullspace) - { - throw new ArgumentException($"Coordinates cannot be in nullspace!", nameof(coordinates)); - } - - if (_mapManager.TryFindGridAt(coordinates, out var grid)) - { - if (ComponentManager.TryGetComponent(grid.GridEntityId, out IGridAtmosphereComponent? atmos)) - { - return atmos; - } - } - - return _mapManager.GetMapEntity(coordinates.MapId).GetComponent(); - } - - /// - /// Unlike , this doesn't return space grid when not found. - /// - public bool TryGetSimulatedGridAtmosphere(MapCoordinates coordinates, [NotNullWhen(true)] out IGridAtmosphereComponent? atmosphere) - { - if (coordinates.MapId == MapId.Nullspace) - { - atmosphere = null; - return false; - } - - if (_mapManager.TryFindGridAt(coordinates, out var mapGrid) - && ComponentManager.TryGetComponent(mapGrid.GridEntityId, out IGridAtmosphereComponent? atmosGrid) - && atmosGrid.Simulated) - { - atmosphere = atmosGrid; - return true; - } - - if (_mapManager.GetMapEntity(coordinates.MapId).TryGetComponent(out IGridAtmosphereComponent? atmosMap) - && atmosMap.Simulated) - { - atmosphere = atmosMap; - return true; - } - - atmosphere = null; - return false; - } - #endregion - public override void Update(float frameTime) { base.Update(frameTime); @@ -158,9 +81,11 @@ namespace Content.Server.Atmos.EntitySystems if (_exposedTimer >= ExposedUpdateDelay) { - foreach (var exposed in EntityManager.ComponentManager.EntityQuery(true)) + foreach (var exposed in EntityManager.ComponentManager.EntityQuery()) { - var tile = exposed.Owner.Transform.Coordinates.GetTileAtmosphere(); + // TODO ATMOS: Kill this with fire. + var atmos = GetGridAtmosphere(exposed.Owner.Transform.Coordinates); + var tile = atmos.GetTile(exposed.Owner.Transform.Coordinates); if (tile == null) continue; exposed.Update(tile, _exposedTimer, this); } diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasDualPortVentPumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasDualPortVentPumpSystem.cs index 861b2b84bc..0782523559 100644 --- a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasDualPortVentPumpSystem.cs +++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasDualPortVentPumpSystem.cs @@ -46,10 +46,11 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems || !nodeContainer.TryGetNode(vent.OutletName, out PipeNode? outlet)) return; - var environment = args.Atmosphere.GetTile(vent.Owner.Transform.Coordinates)!; + var atmosphereSystem = Get(); + var environment = atmosphereSystem.GetTileMixture(vent.Owner.Transform.Coordinates, true); // We're in an air-blocked tile... Do nothing. - if (environment.Air == null) + if (environment == null) return; if (vent.PumpDirection == VentPumpDirection.Releasing) @@ -58,38 +59,37 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems var pressureDelta = 10000f; if ((vent.PressureChecks & DualPortVentPressureBound.ExternalBound) != 0) - pressureDelta = MathF.Min(pressureDelta, (vent.ExternalPressureBound - environment.Air.Pressure)); + pressureDelta = MathF.Min(pressureDelta, (vent.ExternalPressureBound - environment.Pressure)); if ((vent.PressureChecks & DualPortVentPressureBound.InputMinimum) != 0) pressureDelta = MathF.Min(pressureDelta, (inlet.Air.Pressure - vent.InputPressureMin)); if (pressureDelta > 0 && inlet.Air.Temperature > 0) { - var transferMoles = pressureDelta * environment.Air.Volume / inlet.Air.Temperature * Atmospherics.R; + var transferMoles = pressureDelta * environment.Volume / inlet.Air.Temperature * Atmospherics.R; var removed = inlet.Air.Remove(transferMoles); - environment.AssumeAir(removed); + atmosphereSystem.Merge(environment, removed); } } - else if (vent.PumpDirection == VentPumpDirection.Siphoning && environment.Air.Pressure > 0f) + else if (vent.PumpDirection == VentPumpDirection.Siphoning && environment.Pressure > 0f) { appearance?.SetData(VentPumpVisuals.State, VentPumpState.In); - var ourMultiplier = outlet.Air.Volume / environment.Air.Temperature * Atmospherics.R; + var ourMultiplier = outlet.Air.Volume / environment.Temperature * Atmospherics.R; var molesDelta = 10000 * ourMultiplier; if ((vent.PressureChecks & DualPortVentPressureBound.ExternalBound) != 0) molesDelta = MathF.Min(molesDelta, - (environment.Air.Pressure - vent.OutputPressureMax) * environment.Air.Volume / (environment.Air.Temperature * Atmospherics.R)); + (environment.Pressure - vent.OutputPressureMax) * environment.Volume / (environment.Temperature * Atmospherics.R)); if ((vent.PressureChecks &DualPortVentPressureBound.InputMinimum) != 0) molesDelta = MathF.Min(molesDelta, (vent.InputPressureMin - outlet.Air.Pressure) * ourMultiplier); if (molesDelta > 0) { - var removed = environment.Air.Remove(molesDelta); + var removed = environment.Remove(molesDelta); Get().Merge(outlet.Air, removed); - environment.Invalidate(); } } } diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs index 48e253167b..ba4fd92866 100644 --- a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs +++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs @@ -1,3 +1,4 @@ +using Content.Server.Atmos.EntitySystems; using Content.Server.Atmos.Piping.Binary.Components; using Content.Server.Atmos.Piping.Components; using Content.Server.NodeContainer; @@ -55,12 +56,13 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems // Some of the gas from the mixture leaks when overclocked. if (pump.Overclocked) { - var tile = args.Atmosphere.GetTile(pump.Owner.Transform.Coordinates); + var atmosphereSystem = Get(); + var tile = atmosphereSystem.GetTileMixture(pump.Owner.Transform.Coordinates, true); if (tile != null) { var leaked = removed.RemoveRatio(pump.LeakRatio); - tile.AssumeAir(leaked); + atmosphereSystem.Merge(tile, leaked); } } diff --git a/Content.Server/Atmos/Piping/EntitySystems/AtmosUnsafeUnanchorSystem.cs b/Content.Server/Atmos/Piping/EntitySystems/AtmosUnsafeUnanchorSystem.cs index 2f63c28b59..c14fc7dafa 100644 --- a/Content.Server/Atmos/Piping/EntitySystems/AtmosUnsafeUnanchorSystem.cs +++ b/Content.Server/Atmos/Piping/EntitySystems/AtmosUnsafeUnanchorSystem.cs @@ -1,3 +1,4 @@ +using System.Buffers; using Content.Server.Atmos.EntitySystems; using Content.Server.Atmos.Piping.Components; using Content.Server.Construction.Components; @@ -25,7 +26,7 @@ namespace Content.Server.Atmos.Piping.EntitySystems if (!component.Enabled || !ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodes)) return; - if (!component.Owner.Transform.Coordinates.TryGetTileAir(out var environment, EntityManager)) + if (Get().GetTileMixture(component.Owner.Transform.Coordinates) is not {} environment) return; foreach (var node in nodes.Nodes.Values) @@ -46,12 +47,10 @@ namespace Content.Server.Atmos.Piping.EntitySystems if (!component.Enabled || !ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodes)) return; - if (!component.Owner.Transform.Coordinates.TryGetTileAtmosphere(out var environment)) - environment = null; + var atmosphereSystem = Get(); - var environmentPressure = environment?.Air?.Pressure ?? 0f; - var environmentVolume = environment?.Air?.Volume ?? Atmospherics.CellVolume; - var environmentTemperature = environment?.Air?.Volume ?? Atmospherics.TCMB; + if (atmosphereSystem.GetTileMixture(component.Owner.Transform.Coordinates, true) is not {} environment) + environment = GasMixture.SpaceGas; var lost = 0f; var timesLost = 0; @@ -60,16 +59,14 @@ namespace Content.Server.Atmos.Piping.EntitySystems { if (node is not PipeNode pipe) continue; - var difference = pipe.Air.Pressure - environmentPressure; - lost += difference * environmentVolume / (environmentTemperature * Atmospherics.R); + var difference = pipe.Air.Pressure - environment.Pressure; + lost += difference * environment.Volume / (environment.Temperature * Atmospherics.R); timesLost++; } var sharedLoss = lost / timesLost; var buffer = new GasMixture(); - var atmosphereSystem = Get(); - foreach (var node in nodes.Nodes.Values) { if (node is not PipeNode pipe) continue; @@ -77,7 +74,7 @@ namespace Content.Server.Atmos.Piping.EntitySystems atmosphereSystem.Merge(buffer, pipe.Air.Remove(sharedLoss)); } - environment?.AssumeAir(buffer); + atmosphereSystem.Merge(environment, buffer); } } } diff --git a/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs b/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs index 142a929de8..d1e61c7b98 100644 --- a/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs +++ b/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs @@ -1,5 +1,6 @@ using System.Diagnostics.CodeAnalysis; using Content.Server.Atmos.Components; +using Content.Server.Atmos.EntitySystems; using Content.Server.Atmos.Piping.Components; using Content.Server.Atmos.Piping.Other.Components; using Content.Shared.Atmos; @@ -20,7 +21,9 @@ namespace Content.Server.Atmos.Piping.Other.EntitySystems private void OnMinerUpdated(EntityUid uid, GasMinerComponent miner, AtmosDeviceUpdateEvent args) { - if (!CheckMinerOperation(args.Atmosphere, miner, out var tile) || !miner.Enabled || !miner.SpawnGas.HasValue || miner.SpawnAmount <= 0f) + var atmosphereSystem = Get(); + + if (!CheckMinerOperation(atmosphereSystem, miner, out var environment) || !miner.Enabled || !miner.SpawnGas.HasValue || miner.SpawnAmount <= 0f) return; // Time to mine some gas. @@ -28,22 +31,22 @@ namespace Content.Server.Atmos.Piping.Other.EntitySystems var merger = new GasMixture(1) { Temperature = miner.SpawnTemperature }; merger.SetMoles(miner.SpawnGas.Value, miner.SpawnAmount); - tile.AssumeAir(merger); + atmosphereSystem.Merge(environment, merger); } - private bool CheckMinerOperation(IGridAtmosphereComponent atmosphere, GasMinerComponent miner, [NotNullWhen(true)] out TileAtmosphere? tile) + private bool CheckMinerOperation(AtmosphereSystem atmosphereSystem, GasMinerComponent miner, [NotNullWhen(true)] out GasMixture? environment) { - tile = atmosphere.GetTile(miner.Owner.Transform.Coordinates)!; + environment = atmosphereSystem.GetTileMixture(miner.Owner.Transform.Coordinates, true); // Space. - if (atmosphere.IsSpace(tile.GridIndices)) + if (atmosphereSystem.IsTileSpace(miner.Owner.Transform.Coordinates)) { miner.Broken = true; return false; } - // Airblocked location. - if (tile.Air == null) + // Air-blocked location. + if (environment == null) { miner.Broken = true; return false; @@ -51,14 +54,14 @@ namespace Content.Server.Atmos.Piping.Other.EntitySystems // External pressure above threshold. if (!float.IsInfinity(miner.MaxExternalPressure) && - tile.Air.Pressure > miner.MaxExternalPressure - miner.SpawnAmount * miner.SpawnTemperature * Atmospherics.R / tile.Air.Volume) + environment.Pressure > miner.MaxExternalPressure - miner.SpawnAmount * miner.SpawnTemperature * Atmospherics.R / environment.Volume) { miner.Broken = true; return false; } // External gas amount above threshold. - if (!float.IsInfinity(miner.MaxExternalAmount) && tile.Air.TotalMoles > miner.MaxExternalAmount) + if (!float.IsInfinity(miner.MaxExternalAmount) && environment.TotalMoles > miner.MaxExternalAmount) { miner.Broken = true; return false; diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs index f3b0d97682..afc56ec96c 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs @@ -165,9 +165,8 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems } else { - var tileAtmosphere = canister.Owner.Transform.Coordinates.GetTileAtmosphere(); - atmosphereSystem.ReleaseGasTo(canister.Air, tileAtmosphere?.Air, canister.ReleasePressure); - tileAtmosphere?.Invalidate(); + var environment = atmosphereSystem.GetTileMixture(canister.Owner.Transform.Coordinates, true); + atmosphereSystem.ReleaseGasTo(canister.Air, environment, canister.ReleasePressure); } } diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasOutletInjectorSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasOutletInjectorSystem.cs index 1d275837ea..63f9665d44 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasOutletInjectorSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasOutletInjectorSystem.cs @@ -1,3 +1,4 @@ +using Content.Server.Atmos.EntitySystems; using Content.Server.Atmos.Piping.Components; using Content.Server.Atmos.Piping.Unary.Components; using Content.Server.NodeContainer; @@ -31,9 +32,10 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems if (!nodeContainer.TryGetNode(injector.InletName, out PipeNode? inlet)) return; - var environment = args.Atmosphere.GetTile(injector.Owner.Transform.Coordinates)!; + var atmosphereSystem = Get(); + var environment = atmosphereSystem.GetTileMixture(injector.Owner.Transform.Coordinates, true); - if (environment.Air == null) + if (environment == null) return; if (inlet.Air.Temperature > 0) @@ -42,8 +44,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems var removed = inlet.Air.Remove(transferMoles); - environment.AssumeAir(removed); - environment.Invalidate(); + atmosphereSystem.Merge(environment, removed); } } } diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPassiveVentSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPassiveVentSystem.cs index e984bd3515..5a61cbc350 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPassiveVentSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPassiveVentSystem.cs @@ -1,4 +1,5 @@ using System; +using Content.Server.Atmos.EntitySystems; using Content.Server.Atmos.Piping.Components; using Content.Server.Atmos.Piping.Unary.Components; using Content.Server.NodeContainer; @@ -21,9 +22,10 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems private void OnPassiveVentUpdated(EntityUid uid, GasPassiveVentComponent vent, AtmosDeviceUpdateEvent args) { - var environment = args.Atmosphere.GetTile(vent.Owner.Transform.Coordinates)!; + var atmosphereSystem = Get(); + var environment = atmosphereSystem.GetTileMixture(vent.Owner.Transform.Coordinates, true); - if (environment.Air == null) + if (environment == null) return; if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)) @@ -32,27 +34,26 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems if (!nodeContainer.TryGetNode(vent.InletName, out PipeNode? inlet)) return; - var environmentPressure = environment.Air.Pressure; + var environmentPressure = environment.Pressure; var pressureDelta = MathF.Abs(environmentPressure - inlet.Air.Pressure); - if ((environment.Air.Temperature > 0 || inlet.Air.Temperature > 0) && pressureDelta > 0.5f) + if ((environment.Temperature > 0 || inlet.Air.Temperature > 0) && pressureDelta > 0.5f) { if (environmentPressure < inlet.Air.Pressure) { var airTemperature = environment.Temperature > 0 ? environment.Temperature : inlet.Air.Temperature; - var transferMoles = pressureDelta * environment.Air.Volume / (airTemperature * Atmospherics.R); + var transferMoles = pressureDelta * environment.Volume / (airTemperature * Atmospherics.R); var removed = inlet.Air.Remove(transferMoles); - environment.AssumeAir(removed); + atmosphereSystem.Merge(environment, removed); } else { var airTemperature = inlet.Air.Temperature > 0 ? inlet.Air.Temperature : environment.Temperature; var outputVolume = inlet.Air.Volume; var transferMoles = (pressureDelta * outputVolume) / (airTemperature * Atmospherics.R); - transferMoles = MathF.Min(transferMoles, environment.Air.TotalMoles * inlet.Air.Volume / environment.Air.Volume); - var removed = environment.Air.Remove(transferMoles); + transferMoles = MathF.Min(transferMoles, environment.TotalMoles * inlet.Air.Volume / environment.Volume); + var removed = environment.Remove(transferMoles); inlet.AssumeAir(removed); - environment.Invalidate(); } } diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs index 16046fd61e..5e69a4f3b4 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs @@ -1,4 +1,5 @@ using System; +using Content.Server.Atmos.EntitySystems; using Content.Server.Atmos.Piping.Components; using Content.Server.Atmos.Piping.Unary.Components; using Content.Server.NodeContainer; @@ -43,10 +44,11 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems if (!nodeContainer.TryGetNode(vent.InletName, out PipeNode? pipe)) return; - var environment = args.Atmosphere.GetTile(vent.Owner.Transform.Coordinates)!; + var atmosphereSystem = Get(); + var environment = atmosphereSystem.GetTileMixture(vent.Owner.Transform.Coordinates, true); // We're in an air-blocked tile... Do nothing. - if (environment.Air == null) + if (environment == null) return; if (vent.PumpDirection == VentPumpDirection.Releasing) @@ -55,37 +57,36 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems var pressureDelta = 10000f; if ((vent.PressureChecks & VentPressureBound.ExternalBound) != 0) - pressureDelta = MathF.Min(pressureDelta, vent.ExternalPressureBound - environment.Air.Pressure); + pressureDelta = MathF.Min(pressureDelta, vent.ExternalPressureBound - environment.Pressure); if ((vent.PressureChecks & VentPressureBound.InternalBound) != 0) pressureDelta = MathF.Min(pressureDelta, pipe.Air.Pressure - vent.InternalPressureBound); if (pressureDelta > 0 && pipe.Air.Temperature > 0) { - var transferMoles = pressureDelta * environment.Air.Volume / (pipe.Air.Temperature * Atmospherics.R); + var transferMoles = pressureDelta * environment.Volume / (pipe.Air.Temperature * Atmospherics.R); - environment.AssumeAir(pipe.Air.Remove(transferMoles)); + atmosphereSystem.Merge(environment, pipe.Air.Remove(transferMoles)); } } - else if (vent.PumpDirection == VentPumpDirection.Siphoning && environment.Air.Pressure > 0) + else if (vent.PumpDirection == VentPumpDirection.Siphoning && environment.Pressure > 0) { appearance?.SetData(VentPumpVisuals.State, VentPumpState.In); - var ourMultiplier = pipe.Air.Volume / (environment.Air.Temperature * Atmospherics.R); + var ourMultiplier = pipe.Air.Volume / (environment.Temperature * Atmospherics.R); var molesDelta = 10000f * ourMultiplier; if ((vent.PressureChecks & VentPressureBound.ExternalBound) != 0) molesDelta = MathF.Min(molesDelta, - (environment.Air.Pressure - vent.ExternalPressureBound) * environment.Air.Volume / - (environment.Air.Temperature * Atmospherics.R)); + (environment.Pressure - vent.ExternalPressureBound) * environment.Volume / + (environment.Temperature * Atmospherics.R)); if ((vent.PressureChecks & VentPressureBound.InternalBound) != 0) molesDelta = MathF.Min(molesDelta, (vent.InternalPressureBound - pipe.Air.Pressure) * ourMultiplier); if (molesDelta > 0) { - var removed = environment.Air.Remove(molesDelta); + var removed = environment.Remove(molesDelta); pipe.AssumeAir(removed); - environment.Invalidate(); } } } diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs index 262924c2b6..399ba29a38 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs @@ -45,17 +45,17 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems if (!nodeContainer.TryGetNode(scrubber.OutletName, out PipeNode? outlet)) return; - var environment = args.Atmosphere.GetTile(scrubber.Owner.Transform.Coordinates)!; + var atmosphereSystem = Get(); + var environment = atmosphereSystem.GetTileMixture(scrubber.Owner.Transform.Coordinates, true); - Scrub(scrubber, appearance, environment, outlet); + Scrub(atmosphereSystem, scrubber, appearance, environment, outlet); if (!scrubber.WideNet) return; // Scrub adjacent tiles too. - foreach (var adjacent in environment.AdjacentTiles) + foreach (var adjacent in atmosphereSystem.GetAdjacentTileMixtures(scrubber.Owner.Transform.Coordinates, false, true)) { - // Pass null appearance, we don't need to set it there. - Scrub(scrubber, null, adjacent, outlet); + Scrub(atmosphereSystem, scrubber, null, adjacent, outlet); } } @@ -67,10 +67,10 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems } } - private void Scrub(GasVentScrubberComponent scrubber, AppearanceComponent? appearance, TileAtmosphere? tile, PipeNode outlet) + private void Scrub(AtmosphereSystem atmosphereSystem, GasVentScrubberComponent scrubber, AppearanceComponent? appearance, GasMixture? tile, PipeNode outlet) { // Cannot scrub if tile is null or air-blocked. - if (tile?.Air == null) + if (tile == null) return; // Cannot scrub if pressure too high. @@ -80,30 +80,28 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems if (scrubber.PumpDirection == ScrubberPumpDirection.Scrubbing) { appearance?.SetData(ScrubberVisuals.State, scrubber.WideNet ? ScrubberState.WideScrub : ScrubberState.Scrub); - var transferMoles = MathF.Min(1f, (scrubber.VolumeRate / tile.Air.Volume) * tile.Air.TotalMoles); + var transferMoles = MathF.Min(1f, (scrubber.VolumeRate / tile.Volume) * tile.TotalMoles); // Take a gas sample. - var removed = tile.Air.Remove(transferMoles); + var removed = tile.Remove(transferMoles); // Nothing left to remove from the tile. if (MathHelper.CloseTo(removed.TotalMoles, 0f)) return; - // TODO: Entity system dependency - Get().ScrubInto(removed, outlet.Air, scrubber.FilterGases); + atmosphereSystem.ScrubInto(removed, outlet.Air, scrubber.FilterGases); // Remix the gases. - tile.AssumeAir(removed); + atmosphereSystem.Merge(tile, removed); } else if (scrubber.PumpDirection == ScrubberPumpDirection.Siphoning) { appearance?.SetData(ScrubberVisuals.State, ScrubberState.Siphon); - var transferMoles = tile.Air.TotalMoles * (scrubber.VolumeRate / tile.Air.Volume); + var transferMoles = tile.TotalMoles * (scrubber.VolumeRate / tile.Volume); - var removed = tile.Air.Remove(transferMoles); + var removed = tile.Remove(transferMoles); outlet.AssumeAir(removed); - tile.Invalidate(); } } } diff --git a/Content.Server/Body/Behavior/LungBehavior.cs b/Content.Server/Body/Behavior/LungBehavior.cs index 428ecb5698..8616817612 100644 --- a/Content.Server/Body/Behavior/LungBehavior.cs +++ b/Content.Server/Body/Behavior/LungBehavior.cs @@ -148,7 +148,7 @@ namespace Content.Server.Body.Behavior return; } - if (!Owner.Transform.Coordinates.TryGetTileAir(out var tileAir)) + if (EntitySystem.Get().GetTileMixture(Owner.Transform.Coordinates, true) is not {} tileAir) { return; } @@ -166,7 +166,7 @@ namespace Content.Server.Body.Behavior public void Exhale(float frameTime) { - if (!Owner.Transform.Coordinates.TryGetTileAir(out var tileAir)) + if (EntitySystem.Get().GetTileMixture(Owner.Transform.Coordinates, true) is not {} tileAir) { return; } diff --git a/Content.Server/Botany/Components/PlantHolderComponent.cs b/Content.Server/Botany/Components/PlantHolderComponent.cs index c7dc1f7eea..7505bae109 100644 --- a/Content.Server/Botany/Components/PlantHolderComponent.cs +++ b/Content.Server/Botany/Components/PlantHolderComponent.cs @@ -2,6 +2,7 @@ using System; using System.Linq; using System.Threading.Tasks; using Content.Server.Atmos; +using Content.Server.Atmos.EntitySystems; using Content.Server.Chemistry.Components; using Content.Server.Fluids.Components; using Content.Server.Hands.Components; @@ -247,8 +248,7 @@ namespace Content.Server.Botany.Components _updateSpriteAfterUpdate = true; } - var tileAtmos = Owner.Transform.Coordinates.GetTileAtmosphere(); - var environment = tileAtmos?.Air ?? GasMixture.SpaceGas; + var environment = EntitySystem.Get().GetTileMixture(Owner.Transform.Coordinates, true)?? GasMixture.SpaceGas; if (Seed.ConsumeGasses.Count > 0) { diff --git a/Content.Server/Chemistry/TileReactions/ExtinguishTileReaction.cs b/Content.Server/Chemistry/TileReactions/ExtinguishTileReaction.cs index 699ce8dfaf..5a1cdb877b 100644 --- a/Content.Server/Chemistry/TileReactions/ExtinguishTileReaction.cs +++ b/Content.Server/Chemistry/TileReactions/ExtinguishTileReaction.cs @@ -21,16 +21,23 @@ namespace Content.Server.Chemistry.TileReactions public ReagentUnit TileReact(TileRef tile, ReagentPrototype reagent, ReagentUnit reactVolume) { - if (reactVolume <= ReagentUnit.Zero || tile.Tile.IsEmpty) return ReagentUnit.Zero; - var tileAtmos = tile.GridPosition().GetTileAtmosphere(); - if (tileAtmos == null || !tileAtmos.Hotspot.Valid || tileAtmos.Air == null) return ReagentUnit.Zero; - tileAtmos.Air.Temperature = - MathF.Max(MathF.Min(tileAtmos.Air.Temperature - (_coolingTemperature * 1000f), - tileAtmos.Air.Temperature / _coolingTemperature), - Atmospherics.TCMB); - EntitySystem.Get().React(tileAtmos.Air, tileAtmos); - tileAtmos.Hotspot = new Hotspot(); - tileAtmos.UpdateVisuals(); + if (reactVolume <= ReagentUnit.Zero || tile.Tile.IsEmpty) + return ReagentUnit.Zero; + + var atmosphereSystem = EntitySystem.Get(); + + var environment = atmosphereSystem.GetTileMixture(tile.GridIndex, tile.GridIndices, true); + + if (environment == null || !atmosphereSystem.IsHotspotActive(tile.GridIndex, tile.GridIndices)) + return ReagentUnit.Zero; + + environment.Temperature = + MathF.Max(MathF.Min(environment.Temperature - (_coolingTemperature * 1000f), + environment.Temperature / _coolingTemperature), Atmospherics.TCMB); + + atmosphereSystem.React(tile.GridIndex, tile.GridIndices); + atmosphereSystem.HotspotExtinguish(tile.GridIndex, tile.GridIndices); + return ReagentUnit.Zero; } } diff --git a/Content.Server/Chemistry/TileReactions/FlammableTileReaction.cs b/Content.Server/Chemistry/TileReactions/FlammableTileReaction.cs index da0b9f54be..b82c9288e6 100644 --- a/Content.Server/Chemistry/TileReactions/FlammableTileReaction.cs +++ b/Content.Server/Chemistry/TileReactions/FlammableTileReaction.cs @@ -20,11 +20,18 @@ namespace Content.Server.Chemistry.TileReactions public ReagentUnit TileReact(TileRef tile, ReagentPrototype reagent, ReagentUnit reactVolume) { - if (reactVolume <= ReagentUnit.Zero || tile.Tile.IsEmpty) return ReagentUnit.Zero; - var tileAtmos = tile.GridPosition().GetTileAtmosphere(); - if (tileAtmos?.Air == null || !tileAtmos.Hotspot.Valid) return ReagentUnit.Zero; - tileAtmos.Air.Temperature *= MathF.Max(_temperatureMultiplier * reactVolume.Float(), 1f); - EntitySystem.Get().React(tileAtmos.Air, tileAtmos); + if (reactVolume <= ReagentUnit.Zero || tile.Tile.IsEmpty) + return ReagentUnit.Zero; + + var atmosphereSystem = EntitySystem.Get(); + + var environment = atmosphereSystem.GetTileMixture(tile.GridIndex, tile.GridIndices, true); + if (environment == null || !atmosphereSystem.IsHotspotActive(tile.GridIndex, tile.GridIndices)) + return ReagentUnit.Zero; + + environment.Temperature *= MathF.Max(_temperatureMultiplier * reactVolume.Float(), 1f); + atmosphereSystem.React(tile.GridIndex, tile.GridIndices); + return reactVolume; } } diff --git a/Content.Server/Commands/Atmos/AddGasCommand.cs b/Content.Server/Commands/Atmos/AddGasCommand.cs index 1f55647229..f8c96ff37c 100644 --- a/Content.Server/Commands/Atmos/AddGasCommand.cs +++ b/Content.Server/Commands/Atmos/AddGasCommand.cs @@ -1,5 +1,6 @@ using Content.Server.Administration; using Content.Server.Atmos.Components; +using Content.Server.Atmos.EntitySystems; using Content.Shared.Administration; using Content.Shared.Atmos; using Robust.Shared.Console; @@ -28,46 +29,17 @@ namespace Content.Server.Commands.Atmos var gridId = new GridId(id); - var mapMan = IoCManager.Resolve(); - - if (!gridId.IsValid() || !mapMan.TryGetGrid(gridId, out var gridComp)) - { - shell.WriteLine("Invalid grid ID."); - return; - } - - var entMan = IoCManager.Resolve(); - - if (!entMan.TryGetEntity(gridComp.GridEntityId, out var grid)) - { - shell.WriteLine("Failed to get grid entity."); - return; - } - - if (!grid.HasComponent()) - { - shell.WriteLine("Grid doesn't have an atmosphere."); - return; - } - - var gam = grid.GetComponent(); + var atmosphereSystem = EntitySystem.Get(); var indices = new Vector2i(x, y); - var tile = gam.GetTile(indices); + var tile = atmosphereSystem.GetTileMixture(gridId, indices, true); if (tile == null) { - shell.WriteLine("Invalid coordinates."); + shell.WriteLine("Invalid coordinates or tile."); return; } - if (tile.Air == null) - { - shell.WriteLine("Can't add gas to that tile."); - return; - } - - tile.Air.AdjustMoles(gasId, moles); - tile.Invalidate(); + tile.AdjustMoles(gasId, moles); } } } diff --git a/Content.Server/Commands/Atmos/DeleteGasCommand.cs b/Content.Server/Commands/Atmos/DeleteGasCommand.cs index 2752d07f93..4a318e5e9b 100644 --- a/Content.Server/Commands/Atmos/DeleteGasCommand.cs +++ b/Content.Server/Commands/Atmos/DeleteGasCommand.cs @@ -1,6 +1,7 @@ using System; using Content.Server.Administration; using Content.Server.Atmos.Components; +using Content.Server.Atmos.EntitySystems; using Content.Shared.Administration; using Content.Shared.Atmos; using Robust.Server.Player; @@ -127,55 +128,39 @@ namespace Content.Server.Commands.Atmos var mapManager = IoCManager.Resolve(); - if (!mapManager.TryGetGrid(gridId, out var grid)) + if (!mapManager.TryGetGrid(gridId, out _)) { shell.WriteLine($"No grid exists with id {gridId}"); return; } - var entityManager = IoCManager.Resolve(); - - if (!entityManager.TryGetEntity(grid.GridEntityId, out var gridEntity)) - { - shell.WriteLine($"Grid {gridId} has no entity."); - return; - } - - if (!gridEntity.TryGetComponent(out GridAtmosphereComponent? atmosphere)) - { - shell.WriteLine($"Grid {gridId} has no {nameof(GridAtmosphereComponent)}"); - return; - } + var atmosphereSystem = EntitySystem.Get(); var tiles = 0; var moles = 0f; if (gas == null) { - foreach (var tile in atmosphere) + foreach (var tile in atmosphereSystem.GetAllTileMixtures(gridId, true)) { - if (tile.Air == null || tile.Air.Immutable) continue; + if (tile.Immutable) continue; tiles++; - moles += tile.Air.TotalMoles; + moles += tile.TotalMoles; - tile.Air.Clear(); - - tile.Invalidate(); + tile.Clear(); } } else { - foreach (var tile in atmosphere) + foreach (var tile in atmosphereSystem.GetAllTileMixtures(gridId, true)) { - if (tile.Air == null || tile.Air.Immutable) continue; + if (tile.Immutable) continue; tiles++; - moles += tile.Air.TotalMoles; + moles += tile.TotalMoles; - tile.Air.SetMoles(gas.Value, 0); - - tile.Invalidate(); + tile.SetMoles(gas.Value, 0); } } diff --git a/Content.Server/Commands/Atmos/FillGasCommand.cs b/Content.Server/Commands/Atmos/FillGasCommand.cs index 0a70ffbec0..e133200bc8 100644 --- a/Content.Server/Commands/Atmos/FillGasCommand.cs +++ b/Content.Server/Commands/Atmos/FillGasCommand.cs @@ -1,5 +1,6 @@ using Content.Server.Administration; using Content.Server.Atmos.Components; +using Content.Server.Atmos.EntitySystems; using Content.Shared.Administration; using Content.Shared.Atmos; using Robust.Shared.Console; @@ -27,32 +28,17 @@ namespace Content.Server.Commands.Atmos var mapMan = IoCManager.Resolve(); - if (!gridId.IsValid() || !mapMan.TryGetGrid(gridId, out var gridComp)) + if (!gridId.IsValid() || !mapMan.TryGetGrid(gridId, out _)) { shell.WriteLine("Invalid grid ID."); return; } - var entMan = IoCManager.Resolve(); + var atmosphereSystem = EntitySystem.Get(); - if (!entMan.TryGetEntity(gridComp.GridEntityId, out var grid)) + foreach (var tile in atmosphereSystem.GetAllTileMixtures(gridId, true)) { - shell.WriteLine("Failed to get grid entity."); - return; - } - - if (!grid.HasComponent()) - { - shell.WriteLine("Grid doesn't have an atmosphere."); - return; - } - - var gam = grid.GetComponent(); - - foreach (var tile in gam) - { - tile.Air?.AdjustMoles(gasId, moles); - tile.Invalidate(); + tile.AdjustMoles(gasId, moles); } } } diff --git a/Content.Server/Commands/Atmos/FixGridAtmos.cs b/Content.Server/Commands/Atmos/FixGridAtmos.cs index 18a2e95ded..e41570e781 100644 --- a/Content.Server/Commands/Atmos/FixGridAtmos.cs +++ b/Content.Server/Commands/Atmos/FixGridAtmos.cs @@ -1,6 +1,7 @@ using Content.Server.Administration; using Content.Server.Atmos; using Content.Server.Atmos.Components; +using Content.Server.Atmos.EntitySystems; using Content.Shared.Administration; using Content.Shared.Atmos; using Robust.Shared.Console; @@ -25,7 +26,7 @@ namespace Content.Server.Commands.Atmos } var mapManager = IoCManager.Resolve(); - var entityManager = IoCManager.Resolve(); + var atmosphereSystem = EntitySystem.Get(); var mixture = new GasMixture(Atmospherics.CellVolume) { Temperature = Atmospherics.T20C }; mixture.AdjustMoles(Gas.Oxygen, Atmospherics.OxygenMolesStandard); @@ -40,32 +41,19 @@ namespace Content.Server.Commands.Atmos continue; } - if (!mapManager.TryGetGrid(new GridId(i), out var grid)) + var gridId = new GridId(i); + + if (!mapManager.TryGetGrid(gridId, out _)) { shell.WriteError($"Grid \"{i}\" doesn't exist."); continue; } - if (!entityManager.TryGetEntity(grid.GridEntityId, out var entity)) + foreach (var tile in atmosphereSystem.GetAllTileMixtures(gridId, true)) { - shell.WriteError($"Grid entity for grid \"{i}\" doesn't exist."); - continue; - } - - var gridAtmosphere = new GridAtmosphereComponent() {Owner = entity}; - - // Inject dependencies manually or a NRE will eat your face. - IoCManager.InjectDependencies(gridAtmosphere); - - entityManager.ComponentManager.AddComponent(entity, gridAtmosphere, true); - - gridAtmosphere.RepopulateTiles(); - - foreach (var tile in gridAtmosphere) - { - tile.Air = (GasMixture) mixture.Clone(); - tile.Air.Volume = gridAtmosphere.GetVolumeForCells(1); - tile.Invalidate(); + tile.Clear(); + atmosphereSystem.Merge(tile, mixture); + tile.Temperature = mixture.Temperature; } } } diff --git a/Content.Server/Commands/Atmos/RemoveGasCommand.cs b/Content.Server/Commands/Atmos/RemoveGasCommand.cs index ad4a213dab..206aeb1f54 100644 --- a/Content.Server/Commands/Atmos/RemoveGasCommand.cs +++ b/Content.Server/Commands/Atmos/RemoveGasCommand.cs @@ -1,5 +1,6 @@ using Content.Server.Administration; using Content.Server.Atmos.Components; +using Content.Server.Atmos.EntitySystems; using Content.Shared.Administration; using Robust.Shared.Console; using Robust.Shared.GameObjects; @@ -27,50 +28,20 @@ namespace Content.Server.Commands.Atmos var gridId = new GridId(id); - var mapMan = IoCManager.Resolve(); - - if (!gridId.IsValid() || !mapMan.TryGetGrid(gridId, out var gridComp)) - { - shell.WriteLine("Invalid grid ID."); - return; - } - - var entMan = IoCManager.Resolve(); - - if (!entMan.TryGetEntity(gridComp.GridEntityId, out var grid)) - { - shell.WriteLine("Failed to get grid entity."); - return; - } - - if (!grid.HasComponent()) - { - shell.WriteLine("Grid doesn't have an atmosphere."); - return; - } - - var gam = grid.GetComponent(); + var atmosphereSystem = EntitySystem.Get(); var indices = new Vector2i(x, y); - var tile = gam.GetTile(indices); + var tile = atmosphereSystem.GetTileMixture(gridId, indices, true); if (tile == null) { - shell.WriteLine("Invalid coordinates."); - return; - } - - if (tile.Air == null) - { - shell.WriteLine("Can't remove gas from that tile."); + shell.WriteLine("Invalid coordinates or tile."); return; } if (ratio) - tile.Air.RemoveRatio(amount); + tile.RemoveRatio(amount); else - tile.Air.Remove(amount); - - tile.Invalidate(); + tile.Remove(amount); } } diff --git a/Content.Server/Commands/Atmos/SetAtmosTemperatureCommand.cs b/Content.Server/Commands/Atmos/SetAtmosTemperatureCommand.cs index 18836eace9..a9bf0bf681 100644 --- a/Content.Server/Commands/Atmos/SetAtmosTemperatureCommand.cs +++ b/Content.Server/Commands/Atmos/SetAtmosTemperatureCommand.cs @@ -1,5 +1,6 @@ using Content.Server.Administration; using Content.Server.Atmos.Components; +using Content.Server.Atmos.EntitySystems; using Content.Shared.Administration; using Content.Shared.Atmos; using Robust.Shared.Console; @@ -38,32 +39,13 @@ namespace Content.Server.Commands.Atmos return; } - var entMan = IoCManager.Resolve(); - - if (!entMan.TryGetEntity(gridComp.GridEntityId, out var grid)) - { - shell.WriteLine("Failed to get grid entity."); - return; - } - - if (!grid.HasComponent()) - { - shell.WriteLine("Grid doesn't have an atmosphere."); - return; - } - - var gam = grid.GetComponent(); + var atmosphereSystem = EntitySystem.Get(); var tiles = 0; - foreach (var tile in gam) + foreach (var tile in atmosphereSystem.GetAllTileMixtures(gridId, true)) { - if (tile.Air == null) - continue; - tiles++; - - tile.Air.Temperature = temperature; - tile.Invalidate(); + tile.Temperature = temperature; } shell.WriteLine($"Changed the temperature of {tiles} tiles."); diff --git a/Content.Server/Commands/Atmos/SetTemperatureCommand.cs b/Content.Server/Commands/Atmos/SetTemperatureCommand.cs index 278320bc6a..f497b1b835 100644 --- a/Content.Server/Commands/Atmos/SetTemperatureCommand.cs +++ b/Content.Server/Commands/Atmos/SetTemperatureCommand.cs @@ -1,5 +1,6 @@ using Content.Server.Administration; using Content.Server.Atmos.Components; +using Content.Server.Atmos.EntitySystems; using Content.Shared.Administration; using Content.Shared.Atmos; using Robust.Shared.Console; @@ -27,52 +28,23 @@ namespace Content.Server.Commands.Atmos var gridId = new GridId(id); - var mapMan = IoCManager.Resolve(); - if (temperature < Atmospherics.TCMB) { shell.WriteLine("Invalid temperature."); return; } - if (!gridId.IsValid() || !mapMan.TryGetGrid(gridId, out var gridComp)) - { - shell.WriteLine("Invalid grid ID."); - return; - } - - var entMan = IoCManager.Resolve(); - - if (!entMan.TryGetEntity(gridComp.GridEntityId, out var grid)) - { - shell.WriteLine("Failed to get grid entity."); - return; - } - - if (!grid.HasComponent()) - { - shell.WriteLine("Grid doesn't have an atmosphere."); - return; - } - - var gam = grid.GetComponent(); + var atmosphereSystem = EntitySystem.Get(); var indices = new Vector2i(x, y); - var tile = gam.GetTile(indices); + var tile = atmosphereSystem.GetTileMixture(gridId, indices, true); if (tile == null) { - shell.WriteLine("Invalid coordinates."); + shell.WriteLine("Invalid coordinates or tile."); return; } - if (tile.Air == null) - { - shell.WriteLine("Can't change that tile's temperature."); - return; - } - - tile.Air.Temperature = temperature; - tile.Invalidate(); + tile.Temperature = temperature; } } } diff --git a/Content.Server/Disposal/Unit/Components/DisposalHolderComponent.cs b/Content.Server/Disposal/Unit/Components/DisposalHolderComponent.cs index 2797b1c4db..ea5d423c3d 100644 --- a/Content.Server/Disposal/Unit/Components/DisposalHolderComponent.cs +++ b/Content.Server/Disposal/Unit/Components/DisposalHolderComponent.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using Content.Server.Atmos; +using Content.Server.Atmos.EntitySystems; using Content.Server.Disposal.Tube.Components; using Content.Server.Interfaces; using Content.Server.Items; @@ -135,10 +136,11 @@ namespace Content.Server.Disposal.Unit.Components } } - if (Owner.Transform.Coordinates.TryGetTileAtmosphere(out var tileAtmos) && - tileAtmos.Air != null) + var atmosphereSystem = EntitySystem.Get(); + + if (atmosphereSystem.GetTileMixture(Owner.Transform.Coordinates, true) is {} environment) { - tileAtmos.AssumeAir(Air); + atmosphereSystem.Merge(environment, Air); Air.Clear(); } diff --git a/Content.Server/Disposal/Unit/Components/DisposalUnitComponent.cs b/Content.Server/Disposal/Unit/Components/DisposalUnitComponent.cs index c932e96d7c..4563f0925c 100644 --- a/Content.Server/Disposal/Unit/Components/DisposalUnitComponent.cs +++ b/Content.Server/Disposal/Unit/Components/DisposalUnitComponent.cs @@ -274,19 +274,13 @@ namespace Content.Server.Disposal.Unit.Components var entryComponent = Owner.EntityManager.ComponentManager.GetComponent(entry); - if (Owner.Transform.Coordinates.TryGetTileAtmosphere(out var tileAtmos) && - tileAtmos.Air != null && - tileAtmos.Air.Temperature > 0) + var atmosphereSystem = EntitySystem.Get(); + + if (atmosphereSystem.GetTileMixture(Owner.Transform.Coordinates, true) is {Temperature: > 0} environment) { - var tileAir = tileAtmos.Air; - var transferMoles = 0.1f * (0.05f * Atmospherics.OneAtmosphere * 1.01f - Air.Pressure) * Air.Volume / (tileAir.Temperature * Atmospherics.R); + var transferMoles = 0.1f * (0.05f * Atmospherics.OneAtmosphere * 1.01f - Air.Pressure) * Air.Volume / (environment.Temperature * Atmospherics.R); - Air = tileAir.Remove(transferMoles); - - var atmosSystem = EntitySystem.Get(); - atmosSystem - .GetGridAtmosphere(Owner.Transform.Coordinates)? - .Invalidate(tileAtmos.GridIndices); + Air = environment.Remove(transferMoles); } entryComponent.TryInsert(this); diff --git a/Content.Server/GameTicking/Presets/PresetTraitorDeathMatch.cs b/Content.Server/GameTicking/Presets/PresetTraitorDeathMatch.cs index a4a8bb6e06..6886a01401 100644 --- a/Content.Server/GameTicking/Presets/PresetTraitorDeathMatch.cs +++ b/Content.Server/GameTicking/Presets/PresetTraitorDeathMatch.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using Content.Server.Atmos; +using Content.Server.Atmos.EntitySystems; using Content.Server.Chat.Managers; using Content.Server.GameTicking.Rules; using Content.Server.Hands.Components; @@ -162,10 +163,12 @@ namespace Content.Server.GameTicking.Presets _robustRandom.Shuffle(ents); var foundATarget = false; bestTarget = EntityCoordinates.Invalid; + var atmosphereSystem = EntitySystem.Get(); foreach (var entity in ents) { - if (!entity.Transform.Coordinates.IsTileAirProbablySafe()) + if (!atmosphereSystem.IsTileMixtureProbablySafe(entity.Transform.Coordinates)) continue; + var distanceFromNearest = float.PositiveInfinity; foreach (var existing in existingPlayerPoints) { diff --git a/Content.Server/Metabolism/MetabolismComponent.cs b/Content.Server/Metabolism/MetabolismComponent.cs index 1c1acde1d9..4898692ab9 100644 --- a/Content.Server/Metabolism/MetabolismComponent.cs +++ b/Content.Server/Metabolism/MetabolismComponent.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using Content.Server.Alert; using Content.Server.Atmos; +using Content.Server.Atmos.EntitySystems; using Content.Server.Body.Behavior; using Content.Server.Body.Circulatory; using Content.Server.Temperature.Components; @@ -282,7 +283,7 @@ namespace Content.Server.Metabolism } // creadth: sweating does not help in airless environment - if (Owner.Transform.Coordinates.TryGetTileAir(out _, Owner.EntityManager)) + if (EntitySystem.Get().GetTileMixture(Owner.Transform.Coordinates) is not {}) { temperatureComponent.RemoveHeat(Math.Min(targetHeat, SweatHeatRegulation)); } diff --git a/Content.Server/StationEvents/Events/GasLeak.cs b/Content.Server/StationEvents/Events/GasLeak.cs index 07d3328e19..b1108edcae 100644 --- a/Content.Server/StationEvents/Events/GasLeak.cs +++ b/Content.Server/StationEvents/Events/GasLeak.cs @@ -1,4 +1,5 @@ using Content.Server.Atmos.Components; +using Content.Server.Atmos.EntitySystems; using Content.Server.GameTicking; using Content.Shared.Atmos; using Robust.Shared.Audio; @@ -113,19 +114,20 @@ namespace Content.Server.StationEvents.Events if (_timeUntilLeak > 0f) return; _timeUntilLeak += LeakCooldown; + var atmosphereSystem = EntitySystem.Get(); + if (!_foundTile || _targetGrid == null || _targetGrid.Deleted || - !_targetGrid.TryGetComponent(out GridAtmosphereComponent? gridAtmos)) + !atmosphereSystem.IsSimulatedGrid(_targetGrid.Transform.GridID)) { Running = false; return; } - var atmos = gridAtmos.GetTile(_targetTile); + var environment = atmosphereSystem.GetTileMixture(_targetGrid.Transform.GridID, _targetTile, true); - atmos?.Air?.AdjustMoles(_leakGas, LeakCooldown * _molesPerSecond); - atmos?.Invalidate(); + environment?.AdjustMoles(_leakGas, LeakCooldown * _molesPerSecond); } public override void Shutdown() @@ -144,21 +146,21 @@ namespace Content.Server.StationEvents.Events private void Spark() { + var atmosphereSystem = EntitySystem.Get(); var robustRandom = IoCManager.Resolve(); if (robustRandom.NextFloat() <= SparkChance) { if (!_foundTile || _targetGrid == null || _targetGrid.Deleted || - !_targetGrid.TryGetComponent(out GridAtmosphereComponent? gridAtmos)) + !atmosphereSystem.IsSimulatedGrid(_targetGrid.Transform.GridID)) { return; } - var atmos = gridAtmos.GetTile(_targetTile); // Don't want it to be so obnoxious as to instantly murder anyone in the area but enough that // it COULD start potentially start a bigger fire. - atmos?.HotspotExpose(700f, 50f, true); + atmosphereSystem.HotspotExpose(_targetGrid.Transform.GridID, _targetTile, 700f, 50f, true); SoundSystem.Play(Filter.Pvs(_targetCoords), "/Audio/Effects/sparks4.ogg", _targetCoords); } } @@ -171,7 +173,7 @@ namespace Content.Server.StationEvents.Events if (!IoCManager.Resolve().TryGetGrid(defaultGridId, out var grid) || !IoCManager.Resolve().TryGetEntity(grid.GridEntityId, out _targetGrid)) return false; - _targetGrid.EnsureComponent(out GridAtmosphereComponent gridAtmos); + var atmosphereSystem = EntitySystem.Get(); robustRandom ??= IoCManager.Resolve(); var found = false; var gridBounds = grid.WorldBounds; @@ -183,7 +185,7 @@ namespace Content.Server.StationEvents.Events var randomY = robustRandom.Next((int) gridBounds.Bottom, (int) gridBounds.Top); tile = new Vector2i(randomX - (int) gridPos.X, randomY - (int) gridPos.Y); - if (gridAtmos.IsSpace(tile) || gridAtmos.IsAirBlocked(tile)) continue; + if (atmosphereSystem.IsTileSpace(defaultGridId, tile) || atmosphereSystem.IsTileAirBlocked(defaultGridId, tile)) continue; found = true; _targetCoords = grid.GridTileToLocal(tile); break; diff --git a/Content.Server/Tools/Components/WelderComponent.cs b/Content.Server/Tools/Components/WelderComponent.cs index 31102eca1f..3cb9fdb4f3 100644 --- a/Content.Server/Tools/Components/WelderComponent.cs +++ b/Content.Server/Tools/Components/WelderComponent.cs @@ -2,6 +2,7 @@ using System; using System.Threading.Tasks; using Content.Server.Act; using Content.Server.Atmos; +using Content.Server.Atmos.EntitySystems; using Content.Server.Chat.Managers; using Content.Server.Chemistry.Components; using Content.Server.Explosion; @@ -212,8 +213,7 @@ namespace Content.Server.Tools.Components PlaySoundCollection("WelderOn", -5); _welderSystem.Subscribe(this); - Owner.Transform.Coordinates - .GetTileAtmosphere()?.HotspotExpose(700f, 50f, true); + EntitySystem.Get().HotspotExpose(Owner.Transform.Coordinates, 700, 50, true); return true; } @@ -256,8 +256,7 @@ namespace Content.Server.Tools.Components _solutionComponent?.TryRemoveReagent("WeldingFuel", ReagentUnit.New(FuelLossRate * frameTime)); - Owner.Transform.Coordinates - .GetTileAtmosphere()?.HotspotExpose(700f, 50f, true); + EntitySystem.Get().HotspotExpose(Owner.Transform.Coordinates, 700, 50, true); if (Fuel == 0) ToggleWelderStatus(); diff --git a/Content.Server/Weapon/Ranged/ServerRangedWeaponComponent.cs b/Content.Server/Weapon/Ranged/ServerRangedWeaponComponent.cs index 360786624d..c1a72785ff 100644 --- a/Content.Server/Weapon/Ranged/ServerRangedWeaponComponent.cs +++ b/Content.Server/Weapon/Ranged/ServerRangedWeaponComponent.cs @@ -1,5 +1,6 @@ using System; using Content.Server.Atmos; +using Content.Server.Atmos.EntitySystems; using Content.Server.CombatMode; using Content.Server.Hands.Components; using Content.Server.Interaction.Components; @@ -182,9 +183,9 @@ namespace Content.Server.Weapon.Ranged return; } - if (_canHotspot && user.Transform.Coordinates.TryGetTileAtmosphere(out var tile)) + if (_canHotspot) { - tile.HotspotExpose(700, 50); + EntitySystem.Get().HotspotExpose(user.Transform.Coordinates, 700, 50); } FireHandler?.Invoke(user, targetPos); }