Files
tbd-station-14/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Grid.cs
Vera Aguilera Puerto c8ba345cdc ECS Atmos Part 3: Removes AtmosHelpers, add many methods to AtmosphereSystem. (#4285)
* ECS Atmos Part 3: Removes AtmosHelpers, add many methods to AtmosphereSystem

* Adds API for adding/removing active tiles.

* Adds API for FixVacuum.

* Adds API for UpdateAdjacent.

* Adds API for IsTileAirBlocked.

* Re-organize hotspot code

* Adds API for IsTileSpace.

* RemoveGasCommand uses AtmosphereSystem

* AddGasCommand uses AtmosphereSystem.

* SetTemperatureCommand uses AtmosphereSystem.

* Adds API for IsSimulatedGrid.

* GasLeak uses AtmosphereSystem.

* Makes Spark method in GasLeak ALSO use AtmosphereSystem.

* GasPassiveVentSystem uses AtmosphereSystem.

* GasMinerSystem uses AtmosphereSystem.

* GasOutletInjectorSystem uses AtmosphereSystem.

* GasVentPumpSystem uses AtmosphereSystem.

* GasDualPortVentPumpSystem uses AtmosphereSystem.

* GasVolumePumpSystem uses AtmosphereSystem.

* GasAnalyzerComponent uses AtmosphereSystem.

* Add API for GetAdjacentTileMixtures.

* GasVentScrubberSystem uses AtmosphereSystem.

* AirtightComponent uses AtmosphereSystem.

* GasLeaks's TryFindRandomTile uses AtmosphereSystem.

* Adds API for GetAdjacentTiles.

* FirelockComponent's IsHoldingFire uses AtmosphereSystem.

* Adds API for GetAllTileMixtures.

* DeleteGasCommand uses AtmosphereSystem.

* FixGridAtmos uses AtmosphereSystem.

* FillGasCommand uses AtmosphereSystem.

* SetAtmosTemperatureCommand uses AtmosphereSystem.
2021-07-19 12:07:37 +02:00

1001 lines
40 KiB
C#

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<IGridAtmosphereComponent>();
}
/// <summary>
/// Unlike GetGridAtmosphere, this doesn't return space grid when not found.
/// </summary>
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
/// <summary>
/// Returns whether a grid has a simulated atmosphere.
/// </summary>
/// <param name="coordinates">Coordinates to be checked.</param>
/// <returns>Whether the grid has a simulated atmosphere.</returns>
public bool IsSimulatedGrid(MapCoordinates coordinates)
{
if (TryGetGridAndTile(coordinates, out var tuple))
return IsSimulatedGrid(tuple.Value.Grid);
return false;
}
/// <summary>
/// Returns whether a grid has a simulated atmosphere.
/// </summary>
/// <param name="coordinates">Coordinates to be checked.</param>
/// <returns>Whether the grid has a simulated atmosphere.</returns>
public bool IsSimulatedGrid(EntityCoordinates coordinates)
{
if (TryGetGridAndTile(coordinates, out var tuple))
return IsSimulatedGrid(tuple.Value.Grid);
return false;
}
/// <summary>
/// Returns whether a grid has a simulated atmosphere.
/// </summary>
/// <param name="grid">Grid to be checked.</param>
/// <returns>Whether the grid has a simulated atmosphere.</returns>
public bool IsSimulatedGrid(GridId grid)
{
if (!_mapManager.TryGetGrid(grid, out var mapGrid))
return false;
if (ComponentManager.HasComponent<GridAtmosphereComponent>(mapGrid.GridEntityId))
return true;
return false;
}
#endregion
#region Grid Get All Mixtures
/// <summary>
/// Gets all tile mixtures within a grid atmosphere, optionally invalidating them all.
/// </summary>
/// <param name="coordinates">Coordinates where to get the grid to get all tile mixtures from.</param>
/// <param name="invalidate">Whether to invalidate all tiles.</param>
/// <returns>All tile mixtures in a grid.</returns>
public IEnumerable<GasMixture> GetAllTileMixtures(MapCoordinates coordinates, bool invalidate = false)
{
if (TryGetGridAndTile(coordinates, out var tuple))
return GetAllTileMixtures(tuple.Value.Grid, invalidate);
return Enumerable.Empty<GasMixture>();
}
/// <summary>
/// Gets all tile mixtures within a grid atmosphere, optionally invalidating them all.
/// </summary>
/// <param name="coordinates">Coordinates where to get the grid to get all tile mixtures from.</param>
/// <param name="invalidate">Whether to invalidate all tiles.</param>
/// <returns>All tile mixtures in a grid.</returns>
public IEnumerable<GasMixture> GetAllTileMixtures(EntityCoordinates coordinates, bool invalidate = false)
{
if (TryGetGridAndTile(coordinates, out var tuple))
return GetAllTileMixtures(tuple.Value.Grid, invalidate);
return Enumerable.Empty<GasMixture>();
}
/// <summary>
/// Gets all tile mixtures within a grid atmosphere, optionally invalidating them all.
/// </summary>
/// <param name="grid">Grid where to get all tile mixtures from.</param>
/// <param name="invalidate">Whether to invalidate all tiles.</param>
/// <returns>All tile mixtures in a grid.</returns>
public IEnumerable<GasMixture> 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
/// <summary>
/// Invalidates a tile at a certain position.
/// </summary>
/// <param name="coordinates"></param>
public void InvalidateTile(MapCoordinates coordinates)
{
if(TryGetGridAndTile(coordinates, out var tuple))
InvalidateTile(tuple.Value.Grid, tuple.Value.Tile);
}
/// <summary>
/// Invalidates a tile at a certain position.
/// </summary>
/// <param name="coordinates"></param>
public void InvalidateTile(EntityCoordinates coordinates)
{
if(TryGetGridAndTile(coordinates, out var tuple))
InvalidateTile(tuple.Value.Grid, tuple.Value.Tile);
}
/// <summary>
/// Invalidates a tile at a certain position.
/// </summary>
/// <param name="grid">Grid where to invalidate the tile.</param>
/// <param name="position">The tile's indices.</param>
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
/// <summary>
/// Makes a tile become active and start processing.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
public void AddActiveTile(MapCoordinates coordinates)
{
if(TryGetGridAndTile(coordinates, out var tuple))
AddActiveTile(tuple.Value.Grid, tuple.Value.Tile);
}
/// <summary>
/// Makes a tile become active and start processing.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
public void AddActiveTile(EntityCoordinates coordinates)
{
if(TryGetGridAndTile(coordinates, out var tuple))
AddActiveTile(tuple.Value.Grid, tuple.Value.Tile);
}
/// <summary>
/// Makes a tile become active and start processing.
/// </summary>
/// <param name="grid">Grid where to get the tile.</param>
/// <param name="tile">Indices of the tile to be activated.</param>
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
/// <summary>
/// Makes a tile become inactive and stop processing.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
/// <param name="disposeExcitedGroup">Whether to dispose of the tile's <see cref="ExcitedGroup"/></param>
public void RemoveActiveTile(MapCoordinates coordinates, bool disposeExcitedGroup = false)
{
if(TryGetGridAndTile(coordinates, out var tuple))
RemoveActiveTile(tuple.Value.Grid, tuple.Value.Tile, disposeExcitedGroup);
}
/// <summary>
/// Makes a tile become inactive and stop processing.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
/// <param name="disposeExcitedGroup">Whether to dispose of the tile's <see cref="ExcitedGroup"/></param>
public void RemoveActiveTile(EntityCoordinates coordinates, bool disposeExcitedGroup = false)
{
if(TryGetGridAndTile(coordinates, out var tuple))
RemoveActiveTile(tuple.Value.Grid, tuple.Value.Tile, disposeExcitedGroup);
}
/// <summary>
/// Makes a tile become inactive and stop processing.
/// </summary>
/// <param name="grid">Grid where to get the tile.</param>
/// <param name="tile">Indices of the tile to be activated.</param>
/// <param name="disposeExcitedGroup">Whether to dispose of the tile's <see cref="ExcitedGroup"/></param>
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
/// <summary>
/// Returns a reference to the gas mixture on a tile, or null.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
/// <param name="invalidate">Whether to invalidate the tile.</param>
/// <returns>The tile mixture, or null</returns>
public GasMixture? GetTileMixture(MapCoordinates coordinates, bool invalidate = false)
{
return TryGetGridAndTile(coordinates, out var tuple)
? GetTileMixture(tuple.Value.Grid, tuple.Value.Tile, invalidate) : null;
}
/// <summary>
/// Returns a reference to the gas mixture on a tile, or null.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
/// <param name="invalidate">Whether to invalidate the tile.</param>
/// <returns>The tile mixture, or null</returns>
public GasMixture? GetTileMixture(EntityCoordinates coordinates, bool invalidate = false)
{
return TryGetGridAndTile(coordinates, out var tuple)
? GetTileMixture(tuple.Value.Grid, tuple.Value.Tile, invalidate) : null;
}
/// <summary>
/// Returns a reference to the gas mixture on a tile, or null.
/// </summary>
/// <param name="grid">Grid where to get the tile air.</param>
/// <param name="position">Indices of the tile.</param>
/// <param name="invalidate">Whether to invalidate the tile.</param>
/// <returns>The tile mixture, or null</returns>
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
/// <summary>
/// Causes a gas mixture reaction on a specific tile.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
/// <returns>Reaction results.</returns>
public ReactionResult React(MapCoordinates coordinates)
{
if (TryGetGridAndTile(coordinates, out var tuple))
return React(tuple.Value.Grid, tuple.Value.Tile);
return ReactionResult.NoReaction;
}
/// <summary>
/// Causes a gas mixture reaction on a specific tile.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
/// <returns>Reaction results.</returns>
public ReactionResult React(EntityCoordinates coordinates)
{
if (TryGetGridAndTile(coordinates, out var tuple))
return React(tuple.Value.Grid, tuple.Value.Tile);
return ReactionResult.NoReaction;
}
/// <summary>
/// Causes a gas mixture reaction on a specific tile.
/// </summary>
/// <param name="grid">Grid where to get the tile.</param>
/// <param name="tile">Indices of the tile.</param>
/// <returns>Reaction results.</returns>
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
/// <summary>
/// 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.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
/// <param name="direction">Directions to check.</param>
/// <returns>Whether the tile is blocked in the directions specified.</returns>
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;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
/// <param name="direction">Directions to check.</param>
/// <returns>Whether the tile is blocked in the directions specified.</returns>
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;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="grid">Grid where to get the tile.</param>
/// <param name="tile">Indices of the tile.</param>
/// <param name="direction">Directions to check.</param>
/// <returns>Whether the tile is blocked in the directions specified.</returns>
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
/// <summary>
/// Returns whether the specified tile is a space tile or not.
/// </summary>
/// <param name="coordinates">Coordinates where to check the tile.</param>
/// <returns>Whether the tile is space or not.</returns>
public bool IsTileSpace(MapCoordinates coordinates)
{
if (TryGetGridAndTile(coordinates, out var tuple))
return IsTileSpace(tuple.Value.Grid, tuple.Value.Tile);
return true;
}
/// <summary>
/// Returns whether the specified tile is a space tile or not.
/// </summary>
/// <param name="coordinates">Coordinates where to check the tile.</param>
/// <returns>Whether the tile is space or not.</returns>
public bool IsTileSpace(EntityCoordinates coordinates)
{
if (TryGetGridAndTile(coordinates, out var tuple))
return IsTileSpace(tuple.Value.Grid, tuple.Value.Tile);
return true;
}
/// <summary>
/// Returns whether the specified tile is a space tile or not.
/// </summary>
/// <param name="grid">Grid where to check the tile.</param>
/// <param name="tile">Indices of the tile.</param>
/// <returns>Whether the tile is space or not.</returns>
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
/// <summary>
/// Gets all the positions adjacent to a tile. Can include air-blocked directions.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
/// <param name="includeBlocked">Whether to include tiles in directions the tile is air-blocked in.</param>
/// <returns>The positions adjacent to the tile.</returns>
public IEnumerable<Vector2i> GetAdjacentTiles(MapCoordinates coordinates, bool includeBlocked = false)
{
if (TryGetGridAndTile(coordinates, out var tuple))
return GetAdjacentTiles(tuple.Value.Grid, tuple.Value.Tile, includeBlocked);
return Enumerable.Empty<Vector2i>();
}
/// <summary>
/// Gets all the positions adjacent to a tile. Can include air-blocked directions.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
/// <param name="includeBlocked">Whether to include tiles in directions the tile is air-blocked in.</param>
/// <returns>The positions adjacent to the tile.</returns>
public IEnumerable<Vector2i> GetAdjacentTiles(EntityCoordinates coordinates, bool includeBlocked = false)
{
if (TryGetGridAndTile(coordinates, out var tuple))
return GetAdjacentTiles(tuple.Value.Grid, tuple.Value.Tile, includeBlocked);
return Enumerable.Empty<Vector2i>();
}
/// <summary>
/// Gets all the positions adjacent to a tile. Can include air-blocked directions.
/// </summary>
/// <param name="grid">Grid where to get the tiles.</param>
/// <param name="tile">Indices of the tile.</param>
/// <param name="includeBlocked">Whether to include tiles in directions the tile is air-blocked in.</param>
/// <returns>The positions adjacent to the tile.</returns>
public IEnumerable<Vector2i> 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
/// <summary>
/// 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.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
/// <param name="includeBlocked">Whether to include tiles in directions the tile is air-blocked in.</param>
/// <param name="invalidate">Whether to invalidate all adjacent tiles.</param>
/// <returns>All adjacent tile gas mixtures to the tile in question</returns>
public IEnumerable<GasMixture> 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<GasMixture>();
}
/// <summary>
/// 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.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
/// <param name="includeBlocked">Whether to include tiles in directions the tile is air-blocked in.</param>
/// <param name="invalidate">Whether to invalidate all adjacent tiles.</param>
/// <returns>All adjacent tile gas mixtures to the tile in question</returns>
public IEnumerable<GasMixture> 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<GasMixture>();
}
/// <summary>
/// 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.
/// </summary>
/// <param name="grid">Grid where to get the tile.</param>
/// <param name="tile">Indices of the tile.</param>
/// <param name="includeBlocked">Whether to include tiles in directions the tile is air-blocked in.</param>
/// <param name="invalidate">Whether to invalidate all adjacent tiles.</param>
/// <returns>All adjacent tile gas mixtures to the tile in question</returns>
public IEnumerable<GasMixture> 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
/// <summary>
/// Immediately updates a tile's blocked air directions.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
public void UpdateAdjacent(MapCoordinates coordinates)
{
if(TryGetGridAndTile(coordinates, out var tuple))
UpdateAdjacent(tuple.Value.Grid, tuple.Value.Tile);
}
/// <summary>
/// Immediately updates a tile's blocked air directions.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
public void UpdateAdjacent(EntityCoordinates coordinates)
{
if(TryGetGridAndTile(coordinates, out var tuple))
UpdateAdjacent(tuple.Value.Grid, tuple.Value.Tile);
}
/// <summary>
/// Immediately updates a tile's blocked air directions.
/// </summary>
/// <param name="grid">Grid where to get the tile.</param>
/// <param name="tile">Indices of the tile.</param>
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
/// <summary>
/// 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.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
/// <param name="exposedTemperature">Temperature to expose to the tile.</param>
/// <param name="exposedVolume">Volume of the exposed temperature.</param>
/// <param name="soh">If true, the existing hotspot values will be set to the exposed values, but only if they're smaller.</param>
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);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
/// <param name="exposedTemperature">Temperature to expose to the tile.</param>
/// <param name="exposedVolume">Volume of the exposed temperature.</param>
/// <param name="soh">If true, the existing hotspot values will be set to the exposed values, but only if they're smaller.</param>
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);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="grid">Grid where to get the tile.</param>
/// <param name="tile">Indices of the tile.</param>
/// <param name="exposedTemperature">Temperature to expose to the tile.</param>
/// <param name="exposedVolume">Volume of the exposed temperature.</param>
/// <param name="soh">If true, the existing hotspot values will be set to the exposed values, but only if they're smaller.</param>
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
/// <summary>
/// Extinguishes a hotspot (fire) on a certain tile, if any. Also invalidates the tile.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
public void HotspotExtinguish(MapCoordinates coordinates)
{
if(TryGetGridAndTile(coordinates, out var tuple))
HotspotExtinguish(tuple.Value.Grid, tuple.Value.Tile);
}
/// <summary>
/// Extinguishes a hotspot (fire) on a certain tile, if any. Also invalidates the tile.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
public void HotspotExtinguish(EntityCoordinates coordinates)
{
if(TryGetGridAndTile(coordinates, out var tuple))
HotspotExtinguish(tuple.Value.Grid, tuple.Value.Tile);
}
/// <summary>
/// Extinguishes a hotspot (fire) on a certain tile, if any. Also invalidates the tile.
/// </summary>
/// <param name="grid">Grid where to get the tile.</param>
/// <param name="tile">Indices of the tile.</param>
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
/// <summary>
/// Returns whether there's an active hotspot (fire) on a certain tile.
/// </summary>
/// <param name="coordinates">Position where to get the tile.</param>
/// <returns>Whether the hotspot is active or not.</returns>
public bool IsHotspotActive(MapCoordinates coordinates)
{
if (TryGetGridAndTile(coordinates, out var tuple))
return IsHotspotActive(tuple.Value.Grid, tuple.Value.Tile);
return false;
}
/// <summary>
/// Returns whether there's an active hotspot (fire) on a certain tile.
/// </summary>
/// <param name="coordinates">Position where to get the tile.</param>
/// <returns>Whether the hotspot is active or not.</returns>
public bool IsHotspotActive(EntityCoordinates coordinates)
{
if (TryGetGridAndTile(coordinates, out var tuple))
return IsHotspotActive(tuple.Value.Grid, tuple.Value.Tile);
return false;
}
/// <summary>
/// Returns whether there's an active hotspot (fire) on a certain tile.
/// </summary>
/// <param name="grid">Grid where to get the tile</param>
/// <param name="tile">Indices for the tile</param>
/// <returns>Whether the hotspot is active or not.</returns>
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
/// <summary>
/// Checks whether a tile's gas mixture is probably safe.
/// This only checks temperature and pressure, not gas composition.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
/// <returns>Whether the tile's gas mixture is probably safe.</returns>
public bool IsTileMixtureProbablySafe(MapCoordinates coordinates)
{
return IsMixtureProbablySafe(GetTileMixture(coordinates));
}
/// <summary>
/// Checks whether a tile's gas mixture is probably safe.
/// This only checks temperature and pressure, not gas composition.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
/// <returns>Whether the tile's gas mixture is probably safe.</returns>
public bool IsTileMixtureProbablySafe(EntityCoordinates coordinates)
{
return IsMixtureProbablySafe(GetTileMixture(coordinates));
}
/// <summary>
/// Checks whether a tile's gas mixture is probably safe.
/// This only checks temperature and pressure, not gas composition.
/// </summary>
/// <param name="grid">Grid where to get the tile.</param>
/// <param name="tile">Indices of the tile.</param>
/// <returns>Whether the tile's gas mixture is probably safe.</returns>
public bool IsTileMixtureProbablySafe(GridId grid, Vector2i tile)
{
return IsMixtureProbablySafe(GetTileMixture(grid, tile));
}
/// <summary>
/// Checks whether a gas mixture is probably safe.
/// This only checks temperature and pressure, not gas composition.
/// </summary>
/// <param name="air">Mixture to be checked.</param>
/// <returns>Whether the mixture is probably safe.</returns>
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
/// <summary>
/// Attempts to fix a sudden vacuum by creating gas based on adjacent tiles.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
public void FixVacuum(MapCoordinates coordinates)
{
if(TryGetGridAndTile(coordinates, out var tuple))
FixVacuum(tuple.Value.Grid, tuple.Value.Tile);
}
/// <summary>
/// Attempts to fix a sudden vacuum by creating gas based on adjacent tiles.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
public void FixVacuum(EntityCoordinates coordinates)
{
if(TryGetGridAndTile(coordinates, out var tuple))
FixVacuum(tuple.Value.Grid, tuple.Value.Tile);
}
/// <summary>
/// Attempts to fix a sudden vacuum by creating gas based on adjacent tiles.
/// </summary>
/// <param name="grid">Grid where to get the tile.</param>
/// <param name="tile">Indices of the tile.</param>
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
}
}