2021-07-19 12:07:37 +02:00
using System ;
using System.Collections.Generic ;
using System.Diagnostics.CodeAnalysis ;
using System.Linq ;
2021-07-23 11:09:01 +02:00
using System.Runtime.CompilerServices ;
2021-07-19 12:07:37 +02:00
using Content.Server.Atmos.Components ;
2021-07-23 11:09:01 +02:00
using Content.Server.Atmos.Piping.Components ;
2021-07-19 12:07:37 +02:00
using Content.Server.Atmos.Reactions ;
2021-07-23 11:09:01 +02:00
using Content.Server.NodeContainer.NodeGroups ;
2021-07-19 12:07:37 +02:00
using Content.Shared.Atmos ;
2021-07-23 11:09:01 +02:00
using Content.Shared.Maps ;
using Robust.Shared.GameObjects ;
// ReSharper disable once RedundantUsingDirective
using Robust.Shared.IoC ;
using Robust.Shared.Log ;
2021-07-19 12:07:37 +02:00
using Robust.Shared.Map ;
using Robust.Shared.Maths ;
2021-07-23 11:09:01 +02:00
using Robust.Shared.Utility ;
using Dependency = Robust . Shared . IoC . DependencyAttribute ;
2021-07-19 12:07:37 +02:00
namespace Content.Server.Atmos.EntitySystems
{
public partial class AtmosphereSystem
{
2021-07-23 11:09:01 +02:00
[Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default ! ;
2021-07-26 12:58:17 +02:00
[Dependency] private readonly GasTileOverlaySystem _gasTileOverlaySystem = default ! ;
2021-07-19 12:07:37 +02:00
2021-07-23 11:09:01 +02:00
private void InitializeGrid ( )
{
SubscribeLocalEvent < GridAtmosphereComponent , ComponentInit > ( OnGridAtmosphereInit ) ;
2021-07-19 12:07:37 +02:00
}
2021-07-23 11:09:01 +02:00
private void OnGridAtmosphereInit ( EntityUid uid , GridAtmosphereComponent gridAtmosphere , ComponentInit args )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
base . Initialize ( ) ;
2021-07-19 12:07:37 +02:00
2021-07-23 11:09:01 +02:00
gridAtmosphere . Tiles . Clear ( ) ;
2021-07-19 12:07:37 +02:00
2021-12-16 12:10:51 +01:00
if ( ! TryComp ( uid , out IMapGridComponent ? mapGrid ) )
2021-07-23 11:09:01 +02:00
return ;
2021-07-19 12:07:37 +02:00
2021-07-23 11:09:01 +02:00
if ( gridAtmosphere . TilesUniqueMixes ! = null )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
foreach ( var ( indices , mix ) in gridAtmosphere . TilesUniqueMixes )
{
try
{
gridAtmosphere . Tiles . Add ( indices , new TileAtmosphere ( mapGrid . GridIndex , indices , ( GasMixture ) gridAtmosphere . UniqueMixes ! [ mix ] . Clone ( ) ) ) ;
}
catch ( ArgumentOutOfRangeException )
{
Logger . Error ( $"Error during atmos serialization! Tile at {indices} points to an unique mix ({mix}) out of range!" ) ;
throw ;
}
2021-07-19 12:07:37 +02:00
2021-07-23 11:09:01 +02:00
InvalidateTile ( gridAtmosphere , indices ) ;
}
2021-07-19 12:07:37 +02:00
}
2021-07-23 11:09:01 +02:00
GridRepopulateTiles ( mapGrid . Grid , gridAtmosphere ) ;
2021-07-19 12:07:37 +02:00
}
#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 ( 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 ;
2021-12-16 12:10:51 +01:00
if ( HasComp < GridAtmosphereComponent > ( mapGrid . GridEntityId ) )
2021-07-19 12:07:37 +02:00
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>
2021-07-23 11:09:01 +02:00
public IEnumerable < GasMixture > GetAllTileMixtures ( EntityCoordinates coordinates , bool invalidate = false )
2021-07-19 12:07:37 +02:00
{
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>
2021-07-23 11:09:01 +02:00
/// <param name="grid">Grid where to get all tile mixtures from.</param>
2021-07-19 12:07:37 +02:00
/// <param name="invalidate">Whether to invalidate all tiles.</param>
/// <returns>All tile mixtures in a grid.</returns>
2021-07-23 11:09:01 +02:00
public IEnumerable < GasMixture > GetAllTileMixtures ( GridId grid , bool invalidate = false )
2021-07-19 12:07:37 +02:00
{
2021-08-02 13:59:41 +02:00
// Return an array with a single space gas mixture for invalid grids.
if ( ! grid . IsValid ( ) )
return new [ ] { GasMixture . SpaceGas } ;
2021-07-23 11:09:01 +02:00
if ( ! _mapManager . TryGetGrid ( grid , out var mapGrid ) )
return Enumerable . Empty < GasMixture > ( ) ;
2021-12-16 12:10:51 +01:00
if ( TryComp ( mapGrid . GridEntityId , out GridAtmosphereComponent ? gridAtmosphere ) )
2021-07-23 11:09:01 +02:00
{
return GetAllTileMixtures ( gridAtmosphere , invalidate ) ;
}
2021-07-19 12:07:37 +02:00
return Enumerable . Empty < GasMixture > ( ) ;
}
/// <summary>
/// Gets all tile mixtures within a grid atmosphere, optionally invalidating them all.
/// </summary>
2021-07-23 11:09:01 +02:00
/// <param name="gridAtmosphere">Grid Atmosphere to get all mixtures from.</param>
/// <param name="invalidate">Whether to invalidate all mixtures.</param>
/// <returns>All the tile mixtures in a grid.</returns>
public IEnumerable < GasMixture > GetAllTileMixtures ( GridAtmosphereComponent gridAtmosphere , bool invalidate = false )
{
foreach ( var ( indices , tile ) in gridAtmosphere . Tiles )
{
if ( tile . Air = = null )
continue ;
if ( invalidate )
InvalidateTile ( gridAtmosphere , indices ) ;
yield return tile . Air ;
}
}
#endregion
#region Grid Cell Volume
/// <summary>
/// Gets the volume in liters for a number of tiles, on a specific grid.
/// </summary>
/// <param name="grid">The grid in question.</param>
/// <param name="tiles">The amount of tiles.</param>
/// <returns>The volume in liters that the tiles occupy.</returns>
public float GetVolumeForTiles ( GridId grid , int tiles = 1 )
2021-07-19 12:07:37 +02:00
{
if ( ! _mapManager . TryGetGrid ( grid , out var mapGrid ) )
2021-07-23 11:09:01 +02:00
return Atmospherics . CellVolume * tiles ;
2021-07-19 12:07:37 +02:00
2021-07-23 11:09:01 +02:00
return GetVolumeForTiles ( mapGrid , tiles ) ;
}
/// <summary>
/// Gets the volume in liters for a number of tiles, on a specific grid.
/// </summary>
/// <param name="mapGrid">The grid in question.</param>
/// <param name="tiles">The amount of tiles.</param>
/// <returns>The volume in liters that the tiles occupy.</returns>
public float GetVolumeForTiles ( IMapGrid mapGrid , int tiles = 1 )
{
return Atmospherics . CellVolume * mapGrid . TileSize * tiles ;
}
#endregion
#region Grid Get Obstructing
/// <summary>
/// Gets all obstructing AirtightComponent instances in a specific tile.
/// </summary>
/// <param name="mapGrid">The grid where to get the tile.</param>
/// <param name="tile">The indices of the tile.</param>
/// <returns></returns>
public virtual IEnumerable < AirtightComponent > GetObstructingComponents ( IMapGrid mapGrid , Vector2i tile )
{
foreach ( var uid in mapGrid . GetAnchoredEntities ( tile ) )
2021-07-19 12:07:37 +02:00
{
2021-12-16 12:10:51 +01:00
if ( TryComp < AirtightComponent > ( uid , out var ac ) )
2021-07-23 11:09:01 +02:00
yield return ac ;
}
}
private AtmosDirection GetBlockedDirections ( IMapGrid mapGrid , Vector2i indices )
{
var value = AtmosDirection . Invalid ;
foreach ( var airtightComponent in GetObstructingComponents ( mapGrid , indices ) )
{
if ( airtightComponent . AirBlocked )
value | = airtightComponent . AirBlockedDirection ;
}
return value ;
}
#endregion
#region Grid Repopulate
2021-07-19 12:07:37 +02:00
/// <summary>
2021-07-23 11:09:01 +02:00
/// Repopulates all tiles on a grid atmosphere.
2021-07-19 12:07:37 +02:00
/// </summary>
2021-07-23 11:09:01 +02:00
/// <param name="mapGrid">The grid where to get all valid tiles from.</param>
/// <param name="gridAtmosphere">The grid atmosphere where the tiles will be repopulated.</param>
public void GridRepopulateTiles ( IMapGrid mapGrid , GridAtmosphereComponent gridAtmosphere )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
var volume = GetVolumeForTiles ( mapGrid , 1 ) ;
foreach ( var tile in mapGrid . GetAllTiles ( ) )
{
if ( ! gridAtmosphere . Tiles . ContainsKey ( tile . GridIndices ) )
gridAtmosphere . Tiles [ tile . GridIndices ] = new TileAtmosphere ( tile . GridIndex , tile . GridIndices , new GasMixture ( volume ) { Temperature = Atmospherics . T20C } ) ;
InvalidateTile ( gridAtmosphere , tile . GridIndices ) ;
}
foreach ( var ( position , tile ) in gridAtmosphere . Tiles . ToArray ( ) )
{
UpdateAdjacent ( mapGrid , gridAtmosphere , tile ) ;
InvalidateVisuals ( mapGrid . Index , position ) ;
}
2021-07-19 12:07:37 +02:00
}
2021-07-23 11:09:01 +02:00
#endregion
#region Tile Pry
/// <summary>
/// Pries a tile in a grid.
/// </summary>
/// <param name="mapGrid">The grid in question.</param>
/// <param name="tile">The indices of the tile.</param>
2021-07-23 13:07:48 +02:00
private void PryTile ( IMapGrid mapGrid , Vector2i tile )
2021-07-23 11:09:01 +02:00
{
if ( ! mapGrid . TryGetTileRef ( tile , out var tileRef ) )
return ;
2021-11-24 04:15:49 +11:00
tileRef . PryTile ( _mapManager , _tileDefinitionManager , EntityManager , _robustRandom ) ;
2021-07-23 11:09:01 +02:00
}
#endregion
#region Tile Invalidate
2021-07-19 12:07:37 +02:00
/// <summary>
/// Invalidates a tile at a certain position.
/// </summary>
2021-07-23 11:09:01 +02:00
/// <param name="coordinates">Coordinates of the tile.</param>
2021-07-19 12:07:37 +02:00
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>
2021-07-23 11:09:01 +02:00
/// <param name="tile">The indices of the tile.</param>
public void InvalidateTile ( GridId grid , Vector2i tile )
2021-07-19 12:07:37 +02:00
{
if ( ! _mapManager . TryGetGrid ( grid , out var mapGrid ) )
return ;
2021-12-16 12:10:51 +01:00
if ( TryComp ( mapGrid . GridEntityId , out GridAtmosphereComponent ? gridAtmosphere ) )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
InvalidateTile ( gridAtmosphere , tile ) ;
2021-07-19 12:07:37 +02:00
return ;
}
}
2021-07-23 11:09:01 +02:00
/// <summary>
/// Invalidates a tile at a certain position.
/// </summary>
/// <param name="gridAtmosphere">Grid Atmosphere where to invalidate the tile.</param>
/// <param name="tile">The tile's indices.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void InvalidateTile ( GridAtmosphereComponent gridAtmosphere , Vector2i tile )
{
gridAtmosphere . InvalidatedCoords . Add ( tile ) ;
}
2021-07-19 12:07:37 +02:00
#endregion
2021-07-23 11:09:01 +02:00
#region Tile Invalidate Visuals
public void InvalidateVisuals ( EntityCoordinates coordinates )
{
if ( TryGetGridAndTile ( coordinates , out var tuple ) )
InvalidateVisuals ( tuple . Value . Grid , tuple . Value . Tile ) ;
}
2021-12-16 12:10:51 +01:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2021-07-23 11:09:01 +02:00
public void InvalidateVisuals ( GridId grid , Vector2i tile )
{
_gasTileOverlaySystem . Invalidate ( grid , tile ) ;
}
#endregion
#region Tile Atmosphere Get
2021-07-19 12:07:37 +02:00
/// <summary>
2021-07-23 11:09:01 +02:00
/// Gets the tile atmosphere in a position, or null.
2021-07-19 12:07:37 +02:00
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
2021-07-23 11:09:01 +02:00
/// <remarks>Do NOT use this outside of atmos internals.</remarks>
/// <returns>The Tile Atmosphere in the position, or null if not on a grid.</returns>
public TileAtmosphere ? GetTileAtmosphere ( EntityCoordinates coordinates )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
if ( TryGetGridAndTile ( coordinates , out var tuple ) )
return GetTileAtmosphere ( tuple . Value . Grid , tuple . Value . Tile ) ;
return null ;
}
/// <summary>
/// Gets the tile atmosphere in a position, or null.
/// </summary>
/// <param name="grid">Grid where to get the tile.</param>
/// <param name="tile">Indices of the tile.</param>
/// <remarks>Do NOT use this outside of atmos internals.</remarks>
/// <returns>The Tile Atmosphere in the position, or null.</returns>
public TileAtmosphere ? GetTileAtmosphere ( GridId grid , Vector2i tile )
{
if ( ! _mapManager . TryGetGrid ( grid , out var mapGrid ) )
return null ;
2021-12-16 12:10:51 +01:00
if ( TryComp ( mapGrid . GridEntityId , out GridAtmosphereComponent ? gridAtmosphere ) )
2021-07-23 11:09:01 +02:00
{
return GetTileAtmosphere ( gridAtmosphere , tile ) ;
}
return null ;
2021-07-19 12:07:37 +02:00
}
2021-07-23 11:09:01 +02:00
/// <summary>
/// Gets the tile atmosphere in a position, or null.
/// </summary>
/// <param name="gridAtmosphere">Grid atmosphere where to get the tile.</param>
/// <param name="tile">Indices of the tile.</param>
/// <remarks>Do NOT use this outside of atmos internals.</remarks>
/// <returns>The Tile Atmosphere in the position, or null.</returns>
public TileAtmosphere ? GetTileAtmosphere ( GridAtmosphereComponent gridAtmosphere , Vector2i tile )
{
if ( gridAtmosphere . Tiles . TryGetValue ( tile , out var tileAtmosphere ) )
return tileAtmosphere ;
return null ;
}
/// <summary>
/// Gets the tile atmosphere in a position and if not possible returns a space tile or null.
/// </summary>
/// <param name="coordinates">Coordinates of the tile.</param>
/// <remarks>Do NOT use this outside of atmos internals.</remarks>
/// <returns>The tile atmosphere of a specific position in a grid, a space tile atmosphere if the tile is space or null if not on a grid.</returns>
public TileAtmosphere ? GetTileAtmosphereOrCreateSpace ( EntityCoordinates coordinates )
{
if ( TryGetGridAndTile ( coordinates , out var tuple ) )
return GetTileAtmosphereOrCreateSpace ( tuple . Value . Grid , tuple . Value . Tile ) ;
return null ;
}
/// <summary>
/// Gets the tile atmosphere in a position and if not possible returns a space tile or null.
/// </summary>
/// <param name="grid">Grid where to get the tile.</param>
/// <param name="tile">Indices of the tile.</param>
/// <remarks>Do NOT use this outside of atmos internals.</remarks>
/// <returns>The tile atmosphere of a specific position in a grid, a space tile atmosphere if the tile is space or null if the grid doesn't exist.</returns>
public TileAtmosphere ? GetTileAtmosphereOrCreateSpace ( GridId grid , Vector2i tile )
{
if ( ! _mapManager . TryGetGrid ( grid , out var mapGrid ) )
return null ;
2021-12-16 12:10:51 +01:00
if ( TryComp ( mapGrid . GridEntityId , out GridAtmosphereComponent ? gridAtmosphere ) )
2021-07-23 11:09:01 +02:00
{
return GetTileAtmosphereOrCreateSpace ( mapGrid , gridAtmosphere , tile ) ;
}
return null ;
}
/// <summary>
/// Gets the tile atmosphere in a position and if not possible returns a space tile or null.
/// </summary>
/// <param name="mapGrid">Grid where to get the tile.</param>
/// <param name="gridAtmosphere">Grid Atmosphere where to get the tile.</param>
/// <param name="tile">Indices of the tile.</param>
/// <remarks>Do NOT use this outside of atmos internals.</remarks>
/// <returns>The tile atmosphere of a specific position in a grid or a space tile atmosphere if the tile is space.</returns>
public TileAtmosphere GetTileAtmosphereOrCreateSpace ( IMapGrid mapGrid , GridAtmosphereComponent gridAtmosphere , Vector2i tile )
{
var tileAtmosphere = GetTileAtmosphere ( gridAtmosphere , tile ) ;
2021-10-07 16:51:36 +02:00
// Please note, you might run into a race condition when using this or GetTileAtmosphere.
// The race condition occurs when a tile goes from being space to not-space, and then something
// attempts to get the tile atmosphere for it before it has been revalidated by atmos.
// The tile atmosphere will get revalidated on the next atmos tick, however.
2021-07-23 11:09:01 +02:00
2021-10-07 16:51:36 +02:00
return tileAtmosphere ? ? new TileAtmosphere ( mapGrid . Index , tile , new GasMixture ( Atmospherics . CellVolume ) { Temperature = Atmospherics . TCMB } , true ) ;
2021-07-23 11:09:01 +02:00
}
#endregion
#region Tile Active Add
2021-07-19 12:07:37 +02:00
/// <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 ;
2021-12-16 12:10:51 +01:00
if ( TryComp ( mapGrid . GridEntityId , out GridAtmosphereComponent ? gridAtmosphere ) )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
AddActiveTile ( gridAtmosphere , tile ) ;
2021-07-19 12:07:37 +02:00
return ;
}
}
2021-07-23 11:09:01 +02:00
/// <summary>
/// Makes a tile become active and start processing.
/// </summary>
/// <param name="gridAtmosphere">Grid Atmosphere where to get the tile.</param>
/// <param name="tile">Indices of the tile to be activated.</param>
public void AddActiveTile ( GridAtmosphereComponent gridAtmosphere , Vector2i tile )
{
if ( ! gridAtmosphere . Tiles . TryGetValue ( tile , out var tileAtmosphere ) )
return ;
2021-07-19 12:07:37 +02:00
2021-07-23 11:09:01 +02:00
AddActiveTile ( gridAtmosphere , tileAtmosphere ) ;
}
2021-07-19 12:07:37 +02:00
/// <summary>
2021-07-23 11:09:01 +02:00
/// Makes a tile become active and start processing. Does NOT check if the tile belongs to the grid atmos.
2021-07-19 12:07:37 +02:00
/// </summary>
2021-07-23 11:09:01 +02:00
/// <param name="gridAtmosphere">Grid Atmosphere where to get the tile.</param>
/// <param name="tile">Tile Atmosphere to be activated.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void AddActiveTile ( GridAtmosphereComponent gridAtmosphere , TileAtmosphere tile )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
if ( tile . Air = = null )
return ;
tile . Excited = true ;
gridAtmosphere . ActiveTiles . Add ( tile ) ;
2021-07-19 12:07:37 +02:00
}
2021-07-23 11:09:01 +02:00
#endregion
#region Tile Active Remove
2021-07-19 12:07:37 +02:00
/// <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>
2021-07-23 11:09:01 +02:00
public void RemoveActiveTile ( EntityCoordinates coordinates , bool disposeExcitedGroup = true )
2021-07-19 12:07:37 +02:00
{
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>
2021-07-23 11:09:01 +02:00
/// <param name="tile">Indices of the tile to be deactivated.</param>
2021-07-19 12:07:37 +02:00
/// <param name="disposeExcitedGroup">Whether to dispose of the tile's <see cref="ExcitedGroup"/></param>
2021-07-23 11:09:01 +02:00
public void RemoveActiveTile ( GridId grid , Vector2i tile , bool disposeExcitedGroup = true )
2021-07-19 12:07:37 +02:00
{
if ( ! _mapManager . TryGetGrid ( grid , out var mapGrid ) )
return ;
2021-12-16 12:10:51 +01:00
if ( TryComp ( mapGrid . GridEntityId , out GridAtmosphereComponent ? gridAtmosphere ) )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
RemoveActiveTile ( gridAtmosphere , tile ) ;
2021-07-19 12:07:37 +02:00
return ;
}
}
2021-07-23 11:09:01 +02:00
/// <summary>
/// Makes a tile become inactive and stop processing.
/// </summary>
/// <param name="gridAtmosphere">Grid Atmosphere where to get the tile.</param>
/// <param name="tile">Indices of the tile to be deactivated.</param>
/// <param name="disposeExcitedGroup">Whether to dispose of the tile's <see cref="ExcitedGroup"/></param>
public void RemoveActiveTile ( GridAtmosphereComponent gridAtmosphere , Vector2i tile , bool disposeExcitedGroup = true )
{
if ( ! gridAtmosphere . Tiles . TryGetValue ( tile , out var tileAtmosphere ) )
return ;
2021-07-19 12:07:37 +02:00
2021-07-23 11:09:01 +02:00
RemoveActiveTile ( gridAtmosphere , tileAtmosphere , disposeExcitedGroup ) ;
}
2021-07-19 12:07:37 +02:00
/// <summary>
2021-07-23 11:09:01 +02:00
/// Makes a tile become inactive and stop processing.
2021-07-19 12:07:37 +02:00
/// </summary>
2021-07-23 11:09:01 +02:00
/// <param name="gridAtmosphere">Grid Atmosphere where to get the tile.</param>
/// <param name="tile">Tile Atmosphere to be deactivated.</param>
/// <param name="disposeExcitedGroup">Whether to dispose of the tile's <see cref="ExcitedGroup"/></param>
private void RemoveActiveTile ( GridAtmosphereComponent gridAtmosphere , TileAtmosphere tile , bool disposeExcitedGroup = true )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
tile . Excited = false ;
gridAtmosphere . ActiveTiles . Remove ( tile ) ;
if ( tile . ExcitedGroup = = null )
return ;
if ( disposeExcitedGroup )
ExcitedGroupDispose ( gridAtmosphere , tile . ExcitedGroup ) ;
else
ExcitedGroupRemoveTile ( tile . ExcitedGroup , tile ) ;
2021-07-19 12:07:37 +02:00
}
2021-07-23 11:09:01 +02:00
#endregion
#region Tile Mixture
2021-07-19 12:07:37 +02:00
/// <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 )
2021-08-04 09:48:49 +02:00
? GetTileMixture ( tuple . Value . Grid , tuple . Value . Tile , invalidate ) : GasMixture . SpaceGas ;
2021-07-19 12:07:37 +02:00
}
/// <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>
2021-07-23 11:09:01 +02:00
/// <param name="tile">Indices of the tile.</param>
2021-07-19 12:07:37 +02:00
/// <param name="invalidate">Whether to invalidate the tile.</param>
/// <returns>The tile mixture, or null</returns>
2021-07-23 11:09:01 +02:00
public GasMixture ? GetTileMixture ( GridId grid , Vector2i tile , bool invalidate = false )
2021-07-19 12:07:37 +02:00
{
2021-08-02 13:59:41 +02:00
// Always return space gas mixtures for invalid grids (grid 0)
if ( ! grid . IsValid ( ) )
return GasMixture . SpaceGas ;
2021-07-19 12:07:37 +02:00
if ( ! _mapManager . TryGetGrid ( grid , out var mapGrid ) )
return null ;
2021-12-16 12:10:51 +01:00
if ( TryComp ( mapGrid . GridEntityId , out GridAtmosphereComponent ? gridAtmosphere ) )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
return GetTileMixture ( gridAtmosphere , tile , invalidate ) ;
2021-07-19 12:07:37 +02:00
}
2021-12-16 12:10:51 +01:00
if ( TryComp ( mapGrid . GridEntityId , out SpaceAtmosphereComponent ? _ ) )
2021-07-19 12:07:37 +02:00
{
// Always return a new space gas mixture in this case.
return GasMixture . SpaceGas ;
}
return null ;
}
2021-07-23 11:09:01 +02:00
/// <summary>
/// Returns a reference to the gas mixture on a tile, or null.
/// </summary>
/// <param name="gridAtmosphere">Grid Atmosphere where to get the tile air.</param>
/// <param name="tile">Indices of the tile.</param>
/// <param name="invalidate">Whether to invalidate the tile.</param>
/// <returns>The tile mixture, or null</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public GasMixture ? GetTileMixture ( GridAtmosphereComponent gridAtmosphere , Vector2i tile , bool invalidate = false )
{
if ( ! gridAtmosphere . Tiles . TryGetValue ( tile , out var tileAtmosphere ) )
return null ;
// Invalidate the tile if needed.
if ( invalidate )
InvalidateTile ( gridAtmosphere , tile ) ;
// Return actual tile air or null.
return tileAtmosphere . Air ;
}
2021-07-19 12:07:37 +02:00
#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>
2021-07-23 11:09:01 +02:00
public ReactionResult React ( EntityCoordinates coordinates )
2021-07-19 12:07:37 +02:00
{
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>
2021-07-23 11:09:01 +02:00
/// <param name="grid">Grid where to get the tile.</param>
/// <param name="tile">Indices of the tile.</param>
2021-07-19 12:07:37 +02:00
/// <returns>Reaction results.</returns>
2021-07-23 11:09:01 +02:00
public ReactionResult React ( GridId grid , Vector2i tile )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
if ( ! _mapManager . TryGetGrid ( grid , out var mapGrid ) )
return ReactionResult . NoReaction ;
2021-12-16 12:10:51 +01:00
if ( TryComp ( mapGrid . GridEntityId , out GridAtmosphereComponent ? gridAtmosphere ) )
2021-07-23 11:09:01 +02:00
{
return React ( gridAtmosphere , tile ) ;
}
2021-07-19 12:07:37 +02:00
return ReactionResult . NoReaction ;
}
/// <summary>
/// Causes a gas mixture reaction on a specific tile.
/// </summary>
2021-07-23 11:09:01 +02:00
/// <param name="gridAtmosphere">Grid Atmosphere where to get the tile.</param>
2021-07-19 12:07:37 +02:00
/// <param name="tile">Indices of the tile.</param>
/// <returns>Reaction results.</returns>
2021-07-23 11:09:01 +02:00
public ReactionResult React ( GridAtmosphereComponent gridAtmosphere , Vector2i tile )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
if ( ! gridAtmosphere . Tiles . TryGetValue ( tile , out var tileAtmosphere ) | | tileAtmosphere . Air = = null )
return ReactionResult . NoReaction ;
2021-07-19 12:07:37 +02:00
2021-07-23 11:09:01 +02:00
InvalidateTile ( gridAtmosphere , tile ) ;
return React ( tileAtmosphere . Air , tileAtmosphere ) ;
2021-07-19 12:07:37 +02:00
}
#endregion
2021-07-23 11:09:01 +02:00
#region Tile Air - blocked
2021-07-19 12:07:37 +02:00
/// <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>
2021-07-23 11:09:01 +02:00
public bool IsTileAirBlocked ( EntityCoordinates coordinates , AtmosDirection direction = AtmosDirection . All )
2021-07-19 12:07:37 +02:00
{
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>
2021-07-23 11:09:01 +02:00
/// <param name="grid">Grid where to get the tile.</param>
/// <param name="tile">Indices of the tile.</param>
2021-07-19 12:07:37 +02:00
/// <param name="direction">Directions to check.</param>
/// <returns>Whether the tile is blocked in the directions specified.</returns>
2021-07-23 11:09:01 +02:00
public bool IsTileAirBlocked ( GridId grid , Vector2i tile , AtmosDirection direction = AtmosDirection . All )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
if ( ! _mapManager . TryGetGrid ( grid , out var mapGrid ) )
return false ;
2021-07-19 12:07:37 +02:00
2021-07-23 11:09:01 +02:00
return IsTileAirBlocked ( mapGrid , tile , direction ) ;
2021-07-19 12:07:37 +02:00
}
/// <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>
2021-07-23 11:09:01 +02:00
/// <param name="mapGrid">Grid where to get the tile.</param>
2021-07-19 12:07:37 +02:00
/// <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>
2021-07-23 11:09:01 +02:00
public bool IsTileAirBlocked ( IMapGrid mapGrid , Vector2i tile , AtmosDirection direction = AtmosDirection . All )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
var directions = AtmosDirection . Invalid ;
2021-07-19 12:07:37 +02:00
2021-07-23 11:09:01 +02:00
foreach ( var obstructingComponent in GetObstructingComponents ( mapGrid , tile ) )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
if ( ! obstructingComponent . AirBlocked )
continue ;
// We set the directions that are air-blocked so far,
// as you could have a full obstruction with only 4 directional air blockers.
directions | = obstructingComponent . AirBlockedDirection ;
if ( directions . IsFlagSet ( direction ) )
return true ;
2021-07-19 12:07:37 +02:00
}
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 ( 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 )
{
2021-07-23 11:09:01 +02:00
return ! _mapManager . TryGetGrid ( grid , out var mapGrid ) | | IsTileSpace ( mapGrid , tile ) ;
}
public bool IsTileSpace ( IMapGrid mapGrid , Vector2i tile )
{
if ( ! mapGrid . TryGetTileRef ( tile , out var tileRef ) )
2021-07-19 12:07:37 +02:00
return true ;
2021-07-23 11:09:01 +02:00
return ( ( ContentTileDefinition ) _tileDefinitionManager [ tileRef . Tile . TypeId ] ) . IsSpace ;
2021-07-19 12:07:37 +02:00
}
#endregion
2021-11-30 12:00:13 +01:00
#region Tile Get Heat Capacity
/// <summary>
/// Get a tile's heat capacity, based on the tile type, tile contents and tile gas mixture.
/// </summary>
public float GetTileHeatCapacity ( EntityCoordinates coordinates )
{
if ( TryGetGridAndTile ( coordinates , out var tuple ) )
return GetTileHeatCapacity ( tuple . Value . Grid , tuple . Value . Tile ) ;
return Atmospherics . MinimumHeatCapacity ;
}
/// <summary>
/// Get a tile's heat capacity, based on the tile type, tile contents and tile gas mixture.
/// </summary>
public float GetTileHeatCapacity ( GridId grid , Vector2i tile )
{
// Always return space gas mixtures for invalid grids (grid 0)
if ( ! grid . IsValid ( ) )
return Atmospherics . MinimumHeatCapacity ;
if ( ! _mapManager . TryGetGrid ( grid , out var mapGrid ) )
return Atmospherics . MinimumHeatCapacity ;
2021-12-16 12:10:51 +01:00
if ( TryComp ( mapGrid . GridEntityId , out GridAtmosphereComponent ? gridAtmosphere ) )
2021-11-30 12:00:13 +01:00
{
return GetTileHeatCapacity ( gridAtmosphere , tile ) ;
}
2021-12-16 12:10:51 +01:00
if ( TryComp ( mapGrid . GridEntityId , out SpaceAtmosphereComponent ? _ ) )
2021-11-30 12:00:13 +01:00
{
return Atmospherics . SpaceHeatCapacity ;
}
return Atmospherics . MinimumHeatCapacity ;
}
/// <summary>
/// Get a tile's heat capacity, based on the tile type, tile contents and tile gas mixture.
/// </summary>
public float GetTileHeatCapacity ( GridAtmosphereComponent gridAtmosphere , Vector2i tile )
{
if ( ! gridAtmosphere . Tiles . TryGetValue ( tile , out var tileAtmosphere ) )
return Atmospherics . MinimumHeatCapacity ;
return GetTileHeatCapacity ( tileAtmosphere ) ;
}
/// <summary>
/// Get a tile's heat capacity, based on the tile type, tile contents and tile gas mixture.
/// </summary>
public float GetTileHeatCapacity ( TileAtmosphere tile )
{
return tile . HeatCapacity + ( tile . Air = = null ? 0 : GetHeatCapacity ( tile . Air ) ) ;
}
#endregion
2021-07-19 12:07:37 +02:00
#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>
2021-07-23 11:09:01 +02:00
public IEnumerable < Vector2i > GetAdjacentTiles ( EntityCoordinates coordinates , bool includeBlocked = false )
2021-07-19 12:07:37 +02:00
{
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>
2021-07-23 11:09:01 +02:00
/// <param name="grid">Grid where to get the tiles.</param>
/// <param name="tile">Indices of the tile.</param>
2021-07-19 12:07:37 +02:00
/// <param name="includeBlocked">Whether to include tiles in directions the tile is air-blocked in.</param>
/// <returns>The positions adjacent to the tile.</returns>
2021-07-23 11:09:01 +02:00
public IEnumerable < Vector2i > GetAdjacentTiles ( GridId grid , Vector2i tile , bool includeBlocked = false )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
if ( ! _mapManager . TryGetGrid ( grid , out var mapGrid ) )
return Enumerable . Empty < Vector2i > ( ) ;
2021-12-16 12:10:51 +01:00
if ( TryComp ( mapGrid . GridEntityId , out GridAtmosphereComponent ? gridAtmosphere ) )
2021-07-23 11:09:01 +02:00
{
return GetAdjacentTiles ( gridAtmosphere , tile , includeBlocked ) ;
}
2021-07-19 12:07:37 +02:00
return Enumerable . Empty < Vector2i > ( ) ;
}
/// <summary>
/// Gets all the positions adjacent to a tile. Can include air-blocked directions.
/// </summary>
2021-07-23 11:09:01 +02:00
/// <param name="gridAtmosphere">Grid Atmosphere where to get the tiles.</param>
2021-07-19 12:07:37 +02:00
/// <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>
2021-07-23 11:09:01 +02:00
public IEnumerable < Vector2i > GetAdjacentTiles ( GridAtmosphereComponent gridAtmosphere , Vector2i tile , bool includeBlocked = false )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
if ( ! gridAtmosphere . Tiles . TryGetValue ( tile , out var tileAtmosphere ) )
2021-07-19 12:07:37 +02:00
yield break ;
2021-07-23 11:09:01 +02:00
for ( var i = 0 ; i < tileAtmosphere . AdjacentTiles . Length ; i + + )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
var adjacentTile = tileAtmosphere . AdjacentTiles [ i ] ;
// TileAtmosphere has nullable disabled, so just in case...
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
if ( adjacentTile ? . Air = = null )
continue ;
2021-07-19 12:07:37 +02:00
2021-07-23 11:09:01 +02:00
if ( ! includeBlocked )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
var direction = ( AtmosDirection ) ( 1 < < i ) ;
if ( tileAtmosphere . BlockedAirflow . IsFlagSet ( direction ) )
2021-07-19 12:07:37 +02:00
continue ;
}
2021-07-23 11:09:01 +02:00
yield return adjacentTile . GridIndices ;
2021-07-19 12:07:37 +02:00
}
}
#endregion
#region Adjacent Get Mixture
/// <summary>
/// Gets all tile gas mixtures adjacent to a specific tile, and optionally invalidates them.
2021-07-23 11:09:01 +02:00
/// Does not return the tile in question, only the adjacent ones.
2021-07-19 12:07:37 +02:00
/// </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>
2021-07-23 11:09:01 +02:00
public IEnumerable < GasMixture > GetAdjacentTileMixtures ( EntityCoordinates coordinates , bool includeBlocked = false , bool invalidate = false )
2021-07-19 12:07:37 +02:00
{
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>
2021-07-23 11:09:01 +02:00
/// <param name="grid">Grid where to get the tile.</param>
/// <param name="tile">Indices of the tile.</param>
2021-07-19 12:07:37 +02:00
/// <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>
2021-07-23 11:09:01 +02:00
public IEnumerable < GasMixture > GetAdjacentTileMixtures ( GridId grid , Vector2i tile , bool includeBlocked = false , bool invalidate = false )
2021-07-19 12:07:37 +02:00
{
2021-08-02 13:59:41 +02:00
// For invalid grids, return an array with a single space gas mixture in it.
if ( ! grid . IsValid ( ) )
return new [ ] { GasMixture . SpaceGas } ;
2021-07-23 11:09:01 +02:00
if ( ! _mapManager . TryGetGrid ( grid , out var mapGrid ) )
return Enumerable . Empty < GasMixture > ( ) ;
2021-12-16 12:10:51 +01:00
if ( TryComp ( mapGrid . GridEntityId , out GridAtmosphereComponent ? gridAtmosphere ) )
2021-07-23 11:09:01 +02:00
{
return GetAdjacentTileMixtures ( gridAtmosphere , tile , includeBlocked , invalidate ) ;
}
2021-07-19 12:07:37 +02:00
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>
2021-07-23 11:09:01 +02:00
/// <param name="gridAtmosphere">Grid Atmosphere where to get the tile.</param>
2021-07-19 12:07:37 +02:00
/// <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>
2021-07-23 11:09:01 +02:00
public IEnumerable < GasMixture > GetAdjacentTileMixtures ( GridAtmosphereComponent gridAtmosphere , Vector2i tile , bool includeBlocked = false , bool invalidate = false )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
if ( ! gridAtmosphere . Tiles . TryGetValue ( tile , out var tileAtmosphere ) )
2021-07-25 09:04:58 +02:00
return Enumerable . Empty < GasMixture > ( ) ;
2021-07-19 12:07:37 +02:00
2021-07-25 09:04:58 +02:00
return GetAdjacentTileMixtures ( gridAtmosphere , tileAtmosphere , includeBlocked , invalidate ) ;
}
/// <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="gridAtmosphere">Grid Atmosphere where the tile is.</param>
/// <param name="tile">Tile Atmosphere in question.</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>
private IEnumerable < GasMixture > GetAdjacentTileMixtures ( GridAtmosphereComponent gridAtmosphere , TileAtmosphere tile , bool includeBlocked = false , bool invalidate = false )
{
for ( var i = 0 ; i < tile . AdjacentTiles . Length ; i + + )
2021-07-19 12:07:37 +02:00
{
2021-07-25 09:04:58 +02:00
var adjacentTile = tile . AdjacentTiles [ i ] ;
2021-07-19 12:07:37 +02:00
2021-07-23 11:09:01 +02:00
// TileAtmosphere has nullable disabled, so just in case...
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
if ( adjacentTile ? . Air = = null )
continue ;
2021-07-19 12:07:37 +02:00
2021-07-23 11:09:01 +02:00
if ( ! includeBlocked )
{
var direction = ( AtmosDirection ) ( 1 < < i ) ;
2021-07-25 09:04:58 +02:00
if ( tile . BlockedAirflow . IsFlagSet ( direction ) )
2021-07-19 12:07:37 +02:00
continue ;
2021-07-23 11:09:01 +02:00
}
2021-07-19 12:07:37 +02:00
2021-07-23 11:09:01 +02:00
if ( invalidate )
InvalidateTile ( gridAtmosphere , adjacentTile . GridIndices ) ;
2021-07-19 12:07:37 +02:00
2021-07-23 11:09:01 +02:00
yield return adjacentTile . Air ;
2021-07-19 12:07:37 +02:00
}
}
#endregion
#region Adjacent Update
/// <summary>
/// Immediately updates a tile's blocked air directions.
/// </summary>
/// <param name="coordinates">Coordinates where to get the tile.</param>
2021-07-23 11:09:01 +02:00
public void UpdateAdjacent ( EntityCoordinates coordinates )
2021-07-19 12:07:37 +02:00
{
if ( TryGetGridAndTile ( coordinates , out var tuple ) )
UpdateAdjacent ( tuple . Value . Grid , tuple . Value . Tile ) ;
}
/// <summary>
/// Immediately updates a tile's blocked air directions.
/// </summary>
2021-07-23 11:09:01 +02:00
/// <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 ;
2021-12-16 12:10:51 +01:00
if ( TryComp ( mapGrid . GridEntityId , out GridAtmosphereComponent ? gridAtmosphere ) )
2021-07-23 11:09:01 +02:00
{
UpdateAdjacent ( mapGrid , gridAtmosphere , tile ) ;
return ;
}
}
/// <summary>
/// Immediately updates a tile's blocked air directions.
/// </summary>
/// <param name="mapGrid">Grid where to get the tile.</param>
/// <param name="gridAtmosphere">Grid Atmosphere where to get the tile.</param>
/// <param name="tile">Indices of the tile.</param>
public void UpdateAdjacent ( IMapGrid mapGrid , GridAtmosphereComponent gridAtmosphere , Vector2i tile )
{
if ( ! gridAtmosphere . Tiles . TryGetValue ( tile , out var tileAtmosphere ) )
return ;
UpdateAdjacent ( mapGrid , gridAtmosphere , tileAtmosphere ) ;
}
/// <summary>
/// Immediately updates a tile's blocked air directions.
/// </summary>
/// <param name="mapGrid">Grid where to get the tile.</param>
/// <param name="gridAtmosphere">Grid Atmosphere of the tile.</param>
/// <param name="tileAtmosphere">Tile Atmosphere to be updated.</param>
private void UpdateAdjacent ( IMapGrid mapGrid , GridAtmosphereComponent gridAtmosphere , TileAtmosphere tileAtmosphere )
{
tileAtmosphere . AdjacentBits = AtmosDirection . Invalid ;
2021-11-11 16:15:14 +01:00
tileAtmosphere . BlockedAirflow = GetBlockedDirections ( mapGrid , tileAtmosphere . GridIndices ) ;
2021-07-23 11:09:01 +02:00
for ( var i = 0 ; i < Atmospherics . Directions ; i + + )
{
var direction = ( AtmosDirection ) ( 1 < < i ) ;
2021-10-06 15:02:50 +02:00
var otherIndices = tileAtmosphere . GridIndices . Offset ( direction ) ;
2021-07-23 11:09:01 +02:00
var adjacent = GetTileAtmosphereOrCreateSpace ( mapGrid , gridAtmosphere , otherIndices ) ;
tileAtmosphere . AdjacentTiles [ direction . ToIndex ( ) ] = adjacent ;
UpdateAdjacent ( mapGrid , gridAtmosphere , adjacent , direction . GetOpposite ( ) ) ;
if ( ! tileAtmosphere . BlockedAirflow . IsFlagSet ( direction )
& & ! IsTileAirBlocked ( mapGrid , adjacent . GridIndices , direction . GetOpposite ( ) ) )
{
tileAtmosphere . AdjacentBits | = direction ;
}
}
2021-11-11 16:15:14 +01:00
if ( ! tileAtmosphere . AdjacentBits . IsFlagSet ( tileAtmosphere . MonstermosInfo . CurrentTransferDirection ) )
tileAtmosphere . MonstermosInfo . CurrentTransferDirection = AtmosDirection . Invalid ;
2021-07-23 11:09:01 +02:00
}
/// <summary>
/// Immediately updates a tile's single blocked air direction.
/// </summary>
2021-07-19 12:07:37 +02:00
/// <param name="coordinates">Coordinates where to get the tile.</param>
2021-07-23 11:09:01 +02:00
/// <param name="direction">Direction to be updated.</param>
public void UpdateAdjacent ( EntityCoordinates coordinates , AtmosDirection direction )
2021-07-19 12:07:37 +02:00
{
if ( TryGetGridAndTile ( coordinates , out var tuple ) )
2021-07-23 11:09:01 +02:00
UpdateAdjacent ( tuple . Value . Grid , tuple . Value . Tile , direction ) ;
2021-07-19 12:07:37 +02:00
}
/// <summary>
2021-07-23 11:09:01 +02:00
/// Immediately updates a tile's single blocked air direction.
2021-07-19 12:07:37 +02:00
/// </summary>
/// <param name="grid">Grid where to get the tile.</param>
/// <param name="tile">Indices of the tile.</param>
2021-07-23 11:09:01 +02:00
/// <param name="direction">Direction to be updated.</param>
public void UpdateAdjacent ( GridId grid , Vector2i tile , AtmosDirection direction )
2021-07-19 12:07:37 +02:00
{
if ( ! _mapManager . TryGetGrid ( grid , out var mapGrid ) )
return ;
2021-12-16 12:10:51 +01:00
if ( TryComp ( mapGrid . GridEntityId , out GridAtmosphereComponent ? gridAtmosphere ) )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
UpdateAdjacent ( mapGrid , gridAtmosphere , tile , direction ) ;
2021-07-19 12:07:37 +02:00
return ;
}
}
2021-07-23 11:09:01 +02:00
/// <summary>
/// Immediately updates a tile's single blocked air direction.
/// </summary>
/// <param name="mapGrid">Grid where to get the tile.</param>
/// <param name="gridAtmosphere">Grid Atmosphere where to get the tile.</param>
/// <param name="tile">Indices of the tile.</param>
/// <param name="direction">Direction to be updated.</param>
public void UpdateAdjacent ( IMapGrid mapGrid , GridAtmosphereComponent gridAtmosphere , Vector2i tile , AtmosDirection direction )
{
if ( ! gridAtmosphere . Tiles . TryGetValue ( tile , out var tileAtmosphere ) )
return ;
2021-07-19 12:07:37 +02:00
2021-07-23 11:09:01 +02:00
UpdateAdjacent ( mapGrid , gridAtmosphere , tileAtmosphere , direction ) ;
}
2021-07-19 12:07:37 +02:00
/// <summary>
2021-07-23 11:09:01 +02:00
/// Immediately updates a tile's single blocked air direction.
2021-07-19 12:07:37 +02:00
/// </summary>
2021-07-23 11:09:01 +02:00
/// <param name="mapGrid">Grid where to get the tile.</param>
/// <param name="gridAtmosphere">Grid where to get the tile.</param>
/// <param name="tile">Tile Atmosphere to be updated.</param>
/// <param name="direction">Direction to be updated.</param>
private void UpdateAdjacent ( IMapGrid mapGrid , GridAtmosphereComponent gridAtmosphere , TileAtmosphere tile , AtmosDirection direction )
2021-07-19 12:07:37 +02:00
{
2021-10-06 15:02:50 +02:00
tile . AdjacentTiles [ direction . ToIndex ( ) ] = GetTileAtmosphereOrCreateSpace ( mapGrid , gridAtmosphere , tile . GridIndices . Offset ( direction ) ) ;
2021-07-23 11:09:01 +02:00
2021-10-06 15:02:50 +02:00
if ( ! tile . BlockedAirflow . IsFlagSet ( direction ) & & ! IsTileAirBlocked ( mapGrid , tile . GridIndices . Offset ( direction ) , direction . GetOpposite ( ) ) )
2021-07-23 11:09:01 +02:00
{
tile . AdjacentBits | = direction ;
}
else
{
tile . AdjacentBits & = ~ direction ;
}
2021-11-11 16:15:14 +01:00
if ( ! tile . AdjacentBits . IsFlagSet ( tile . MonstermosInfo . CurrentTransferDirection ) )
tile . MonstermosInfo . CurrentTransferDirection = AtmosDirection . Invalid ;
2021-07-19 12:07:37 +02:00
}
2021-07-23 11:09:01 +02:00
#endregion
#region Hotspot Expose
2021-07-19 12:07:37 +02:00
/// <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 ;
2021-12-16 12:10:51 +01:00
if ( TryComp ( mapGrid . GridEntityId , out GridAtmosphereComponent ? gridAtmosphere ) )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
var tileAtmosphere = GetTileAtmosphere ( gridAtmosphere , tile ) ;
2021-07-20 18:03:49 +02:00
if ( tileAtmosphere = = null )
return ;
HotspotExpose ( gridAtmosphere , tileAtmosphere , exposedTemperature , exposedVolume , soh ) ;
2021-07-23 11:09:01 +02:00
InvalidateTile ( gridAtmosphere , tile ) ;
2021-07-19 12:07:37 +02:00
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 ( 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 ;
2021-12-16 12:10:51 +01:00
if ( TryComp ( mapGrid . GridEntityId , out GridAtmosphereComponent ? gridAtmosphere ) )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
HotspotExtinguish ( gridAtmosphere , tile ) ;
2021-07-19 12:07:37 +02:00
return ;
}
}
2021-07-23 11:09:01 +02:00
/// <summary>
/// Extinguishes a hotspot (fire) on a certain tile, if any. Also invalidates the tile.
/// </summary>
/// <param name="gridAtmosphere">Grid Atmosphere where to get the tile.</param>
/// <param name="tile">Indices of the tile.</param>
public void HotspotExtinguish ( GridAtmosphereComponent gridAtmosphere , Vector2i tile )
{
if ( ! gridAtmosphere . Tiles . TryGetValue ( tile , out var tileAtmosphere ) )
return ;
tileAtmosphere . Hotspot = new Hotspot ( ) ;
InvalidateTile ( gridAtmosphere , tile ) ;
}
2021-07-19 12:07:37 +02:00
#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>
2021-07-23 11:09:01 +02:00
public bool IsHotspotActive ( EntityCoordinates coordinates )
2021-07-19 12:07:37 +02:00
{
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>
2021-07-23 11:09:01 +02:00
/// <param name="grid">Grid where to get the tile</param>
/// <param name="tile">Indices for the tile</param>
2021-07-19 12:07:37 +02:00
/// <returns>Whether the hotspot is active or not.</returns>
2021-07-23 11:09:01 +02:00
public bool IsHotspotActive ( GridId grid , Vector2i tile )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
if ( ! _mapManager . TryGetGrid ( grid , out var mapGrid ) )
return false ;
2021-12-16 12:10:51 +01:00
if ( TryComp ( mapGrid . GridEntityId , out GridAtmosphereComponent ? gridAtmosphere ) )
2021-07-23 11:09:01 +02:00
{
return IsHotspotActive ( gridAtmosphere , tile ) ;
}
2021-07-19 12:07:37 +02:00
return false ;
}
/// <summary>
/// Returns whether there's an active hotspot (fire) on a certain tile.
/// </summary>
2021-07-23 11:09:01 +02:00
/// <param name="gridAtmosphere">Grid Atmosphere where to get the tile</param>
2021-07-19 12:07:37 +02:00
/// <param name="tile">Indices for the tile</param>
/// <returns>Whether the hotspot is active or not.</returns>
2021-07-23 11:09:01 +02:00
public bool IsHotspotActive ( GridAtmosphereComponent gridAtmosphere , Vector2i tile )
{
if ( ! gridAtmosphere . Tiles . TryGetValue ( tile , out var tileAtmosphere ) )
return false ;
return tileAtmosphere . Hotspot . Valid ;
}
#endregion
#region PipeNet Add
public void AddPipeNet ( PipeNet pipeNet )
{
if ( ! _mapManager . TryGetGrid ( pipeNet . Grid , out var mapGrid ) )
return ;
2021-12-16 12:10:51 +01:00
if ( TryComp ( mapGrid . GridEntityId , out GridAtmosphereComponent ? gridAtmosphere ) )
2021-07-23 11:09:01 +02:00
{
gridAtmosphere . PipeNets . Add ( pipeNet ) ;
}
}
#endregion
#region PipeNet Remove
public void RemovePipeNet ( PipeNet pipeNet )
{
if ( ! _mapManager . TryGetGrid ( pipeNet . Grid , out var mapGrid ) )
return ;
2021-12-16 12:10:51 +01:00
if ( TryComp ( mapGrid . GridEntityId , out GridAtmosphereComponent ? gridAtmosphere ) )
2021-07-23 11:09:01 +02:00
{
gridAtmosphere . PipeNets . Remove ( pipeNet ) ;
}
}
#endregion
#region AtmosDevice Add
public bool AddAtmosDevice ( AtmosDeviceComponent atmosDevice )
2021-07-19 12:07:37 +02:00
{
2021-12-16 12:10:51 +01:00
var grid = Comp < TransformComponent > ( atmosDevice . Owner ) . GridID ;
2021-07-23 11:09:01 +02:00
2021-07-19 12:07:37 +02:00
if ( ! _mapManager . TryGetGrid ( grid , out var mapGrid ) )
return false ;
2021-12-16 12:10:51 +01:00
if ( TryComp ( mapGrid . GridEntityId , out GridAtmosphereComponent ? gridAtmosphere ) )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
atmosDevice . JoinedGrid = grid ;
gridAtmosphere . AtmosDevices . Add ( atmosDevice ) ;
return true ;
2021-07-19 12:07:37 +02:00
}
return false ;
}
#endregion
2021-07-23 11:09:01 +02:00
#region AtmosDevice Remove
2021-07-19 12:07:37 +02:00
2021-07-23 11:09:01 +02:00
public bool RemoveAtmosDevice ( AtmosDeviceComponent atmosDevice )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
if ( atmosDevice . JoinedGrid = = null )
return false ;
var grid = atmosDevice . JoinedGrid . Value ;
if ( ! _mapManager . TryGetGrid ( grid , out var mapGrid ) )
return false ;
2021-12-16 12:10:51 +01:00
if ( TryComp ( mapGrid . GridEntityId , out GridAtmosphereComponent ? gridAtmosphere )
2021-08-02 13:59:41 +02:00
& & gridAtmosphere . AtmosDevices . Contains ( atmosDevice ) )
2021-07-23 11:09:01 +02:00
{
atmosDevice . JoinedGrid = null ;
gridAtmosphere . AtmosDevices . Remove ( atmosDevice ) ;
return true ;
}
return false ;
2021-07-19 12:07:37 +02:00
}
2021-07-23 11:09:01 +02:00
#endregion
#region Mixture Safety
2021-07-19 12:07:37 +02:00
/// <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 ( 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 ;
2021-12-16 12:10:51 +01:00
if ( TryComp ( mapGrid . GridEntityId , out GridAtmosphereComponent ? gridAtmosphere ) )
2021-07-19 12:07:37 +02:00
{
2021-07-23 11:09:01 +02:00
FixVacuum ( gridAtmosphere , tile ) ;
return ;
}
}
public void FixVacuum ( GridAtmosphereComponent gridAtmosphere , Vector2i tile )
{
if ( ! gridAtmosphere . Tiles . TryGetValue ( tile , out var tileAtmosphere ) )
return ;
2021-07-25 09:04:58 +02:00
var adjacent = GetAdjacentTileMixtures ( gridAtmosphere , tileAtmosphere , false , true ) . ToArray ( ) ;
2021-07-23 11:09:01 +02:00
tileAtmosphere . Air = new GasMixture ( GetVolumeForTiles ( tileAtmosphere . GridIndex , 1 ) )
{ Temperature = Atmospherics . T20C } ;
2021-07-19 12:07:37 +02:00
2021-07-23 11:09:01 +02:00
// Return early, let's not cause any funny NaNs.
if ( adjacent . Length = = 0 )
2021-07-19 12:07:37 +02:00
return ;
2021-07-23 11:09:01 +02:00
var ratio = 1f / adjacent . Length ;
var totalTemperature = 0f ;
foreach ( var adj in adjacent )
{
totalTemperature + = adj . Temperature ;
// Remove a bit of gas from the adjacent ratio...
var mix = adj . RemoveRatio ( ratio ) ;
// And merge it to the new tile air.
Merge ( tileAtmosphere . Air , mix ) ;
// Return removed gas to its original mixture.
Merge ( adj , mix ) ;
2021-07-19 12:07:37 +02:00
}
2021-07-23 11:09:01 +02:00
// New temperature is the arithmetic mean of the sum of the adjacent temperatures...
tileAtmosphere . Air . Temperature = totalTemperature / adjacent . Length ;
}
public bool NeedsVacuumFixing ( IMapGrid mapGrid , Vector2i indices )
{
var value = false ;
foreach ( var airtightComponent in GetObstructingComponents ( mapGrid , indices ) )
{
value | = airtightComponent . FixVacuum ;
}
return value ;
2021-07-19 12:07:37 +02:00
}
#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 ;
}
2021-07-23 11:09:01 +02:00
public bool TryGetMapGrid ( GridAtmosphereComponent gridAtmosphere , [ NotNullWhen ( true ) ] out IMapGrid ? mapGrid )
{
2021-12-16 12:10:51 +01:00
if ( TryComp ( gridAtmosphere . Owner , out IMapGridComponent ? mapGridComponent ) )
2021-07-23 11:09:01 +02:00
{
mapGrid = mapGridComponent . Grid ;
return true ;
}
mapGrid = null ;
return false ;
}
2021-07-19 12:07:37 +02:00
#endregion
}
}