2021-07-19 12:07:37 +02:00
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 ;
// ReSharper disable once RedundantUsingDirective
2021-07-19 12:07:37 +02:00
using Robust.Shared.Map ;
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
{
2022-02-16 00:23:23 -07:00
public sealed partial class AtmosphereSystem
2021-07-19 12:07:37 +02:00
{
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 ) ;
2022-04-24 13:54:25 +10:00
SubscribeLocalEvent < GridAtmosphereComponent , GridSplitEvent > ( OnGridSplit ) ;
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
{
2022-06-11 18:54:41 -07:00
gridAtmosphere . Tiles . Add ( indices , new TileAtmosphere ( mapGrid . Owner , indices , ( GasMixture ) gridAtmosphere . UniqueMixes ! [ mix ] . Clone ( ) ) ) ;
2021-07-23 11:09:01 +02:00
}
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
}
2022-04-24 13:54:25 +10:00
private void OnGridSplit ( EntityUid uid , GridAtmosphereComponent originalGridAtmos , ref GridSplitEvent args )
{
foreach ( var newGrid in args . NewGrids )
{
// Make extra sure this is a valid grid.
if ( ! _mapManager . TryGetGrid ( newGrid , out var mapGrid ) )
continue ;
var entity = mapGrid . GridEntityId ;
// If the new split grid has an atmosphere already somehow, use that. Otherwise, add a new one.
if ( ! TryComp ( entity , out GridAtmosphereComponent ? newGridAtmos ) )
newGridAtmos = AddComp < GridAtmosphereComponent > ( entity ) ;
// We assume the tiles on the new grid have the same coordinates as they did on the old grid...
var enumerator = mapGrid . GetAllTilesEnumerator ( ) ;
while ( enumerator . MoveNext ( out var tile ) )
{
var indices = tile . Value . GridIndices ;
// This split event happens *before* the spaced tiles have been invalidated, therefore we can still
// access their gas data. On the next atmos update tick, these tiles will be spaced. Poof!
if ( ! originalGridAtmos . Tiles . TryGetValue ( indices , out var tileAtmosphere ) )
continue ;
// The new grid atmosphere has been initialized, meaning it has all the needed TileAtmospheres...
if ( ! newGridAtmos . Tiles . TryGetValue ( indices , out var newTileAtmosphere ) )
// Let's be honest, this is really not gonna happen, but just in case...!
continue ;
// Copy a bunch of data over... Not great, maybe put this in TileAtmosphere?
newTileAtmosphere . Air = tileAtmosphere . Air ? . Clone ( ) ? ? null ;
newTileAtmosphere . Hotspot = tileAtmosphere . Hotspot ;
newTileAtmosphere . HeatCapacity = tileAtmosphere . HeatCapacity ;
newTileAtmosphere . Temperature = tileAtmosphere . Temperature ;
newTileAtmosphere . PressureDifference = tileAtmosphere . PressureDifference ;
newTileAtmosphere . PressureDirection = tileAtmosphere . PressureDirection ;
// TODO ATMOS: Somehow force GasTileOverlaySystem to perform an update *right now, right here.*
// The reason why is that right now, gas will flicker until the next GasTileOverlay update.
// That looks bad, of course. We want to avoid that! Anyway that's a bit more complicated so out of scope.
// Invalidate the tile, it's redundant but redundancy is good! Also HashSet so really, no duplicates.
InvalidateTile ( originalGridAtmos , indices ) ;
InvalidateTile ( newGridAtmos , indices ) ;
}
}
}
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>
2022-06-20 12:14:35 +12:00
public bool IsSimulatedGrid ( EntityUid ? grid )
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 ( 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>
2022-06-11 18:54:41 -07:00
public IEnumerable < GasMixture > GetAllTileMixtures ( EntityUid 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>
2022-06-11 18:54:41 -07:00
public float GetVolumeForTiles ( EntityUid 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>
2022-02-16 00:23:23 -07:00
public IEnumerable < AirtightComponent > GetObstructingComponents ( IMapGrid mapGrid , Vector2i tile )
2021-07-23 11:09:01 +02:00
{
2022-03-27 17:49:26 +11:00
var airQuery = GetEntityQuery < AirtightComponent > ( ) ;
var enumerator = mapGrid . GetAnchoredEntitiesEnumerator ( tile ) ;
while ( enumerator . MoveNext ( out var uid ) )
2021-07-19 12:07:37 +02:00
{
2022-03-27 17:49:26 +11:00
if ( ! airQuery . TryGetComponent ( uid . Value , out var airtight ) ) continue ;
yield return airtight ;
2021-07-23 11:09:01 +02:00
}
}
2022-03-27 17:49:26 +11:00
public AtmosObstructionEnumerator GetObstructingComponentsEnumerator ( IMapGrid mapGrid , Vector2i tile )
{
var ancEnumerator = mapGrid . GetAnchoredEntitiesEnumerator ( tile ) ;
var airQuery = GetEntityQuery < AirtightComponent > ( ) ;
var enumerator = new AtmosObstructionEnumerator ( ancEnumerator , airQuery ) ;
return enumerator ;
}
2021-07-23 11:09:01 +02:00
private AtmosDirection GetBlockedDirections ( IMapGrid mapGrid , Vector2i indices )
{
var value = AtmosDirection . Invalid ;
2022-04-24 13:54:25 +10:00
var enumerator = GetObstructingComponentsEnumerator ( mapGrid , indices ) ;
2021-07-23 11:09:01 +02:00
2022-04-24 13:54:25 +10:00
while ( enumerator . MoveNext ( out var airtightComponent ) )
2021-07-23 11:09:01 +02:00
{
2022-04-24 13:54:25 +10:00
if ( airtightComponent . AirBlocked )
2021-07-23 11:09:01 +02:00
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 ) )
2022-06-11 18:54:41 -07:00
gridAtmosphere . Tiles [ tile . GridIndices ] = new TileAtmosphere ( tile . GridUid , tile . GridIndices , new GasMixture ( volume ) { Temperature = Atmospherics . T20C } ) ;
2021-07-23 11:09:01 +02:00
InvalidateTile ( gridAtmosphere , tile . GridIndices ) ;
}
foreach ( var ( position , tile ) in gridAtmosphere . Tiles . ToArray ( ) )
{
UpdateAdjacent ( mapGrid , gridAtmosphere , tile ) ;
2022-06-11 18:54:41 -07:00
InvalidateVisuals ( mapGrid . GridEntityId , position ) ;
2021-07-23 11:09:01 +02:00
}
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>
2022-06-11 18:54:41 -07:00
public void InvalidateTile ( EntityUid 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)]
2022-06-11 18:54:41 -07:00
public void InvalidateVisuals ( EntityUid grid , Vector2i tile )
2021-07-23 11:09:01 +02:00
{
_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>
2022-06-11 18:54:41 -07:00
public TileAtmosphere ? GetTileAtmosphere ( EntityUid grid , Vector2i tile )
2021-07-23 11:09:01 +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-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>
2022-06-11 18:54:41 -07:00
public TileAtmosphere ? GetTileAtmosphereOrCreateSpace ( EntityUid grid , Vector2i tile )
2021-07-23 11:09:01 +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-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
2022-06-11 18:54:41 -07:00
return tileAtmosphere ? ? new TileAtmosphere ( mapGrid . GridEntityId , 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>
2022-06-11 18:54:41 -07:00
public void AddActiveTile ( EntityUid 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
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>
2022-06-11 18:54:41 -07:00
public void RemoveActiveTile ( EntityUid 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>
2022-06-11 18:54:41 -07:00
public GasMixture ? GetTileMixture ( EntityUid 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>
2022-06-11 18:54:41 -07:00
public ReactionResult React ( EntityUid 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>
2022-06-11 18:54:41 -07:00
public bool IsTileAirBlocked ( EntityUid 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
2022-03-27 17:49:26 +11:00
var enumerator = GetObstructingComponentsEnumerator ( mapGrid , tile ) ;
while ( enumerator . MoveNext ( out var obstructingComponent ) )
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>
2022-06-11 18:54:41 -07:00
public bool IsTileSpace ( EntityUid grid , Vector2i tile )
2021-07-19 12:07:37 +02:00
{
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>
2022-06-11 18:54:41 -07:00
public float GetTileHeatCapacity ( EntityUid grid , Vector2i tile )
2021-11-30 12:00:13 +01:00
{
// 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>
2022-06-11 18:54:41 -07:00
public IEnumerable < Vector2i > GetAdjacentTiles ( EntityUid 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 ) )
2022-04-08 19:52:44 -07:00
return GetAdjacentTileMixtures ( tuple . Value . Grid , tuple . Value . 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="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>
2022-06-11 18:54:41 -07:00
public IEnumerable < GasMixture > GetAdjacentTileMixtures ( EntityUid 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>
2022-06-11 18:54:41 -07:00
public void UpdateAdjacent ( EntityUid grid , Vector2i tile )
2021-07-23 11:09:01 +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-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>
2022-06-11 18:54:41 -07:00
public void UpdateAdjacent ( EntityUid 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>
2022-06-11 18:54:41 -07:00
public void HotspotExpose ( EntityUid grid , Vector2i tile , float exposedTemperature , float exposedVolume , bool soh = false )
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
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>
2022-06-11 18:54:41 -07:00
public void HotspotExtinguish ( EntityUid 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
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>
2022-06-11 18:54:41 -07:00
public bool IsHotspotActive ( EntityUid 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
{
2022-06-20 12:14:35 +12:00
var grid = Comp < TransformComponent > ( atmosDevice . Owner ) . GridUid ;
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>
2022-06-11 18:54:41 -07:00
public bool IsTileMixtureProbablySafe ( EntityUid grid , Vector2i tile )
2021-07-19 12:07:37 +02:00
{
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>
2022-06-11 18:54:41 -07:00
public void FixVacuum ( EntityUid 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
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
2022-02-20 17:43:20 +11:00
private TileRef ? GetTile ( TileAtmosphere tile )
{
return tile . GridIndices . GetTileRef ( tile . GridIndex , _mapManager ) ;
}
2022-06-11 18:54:41 -07:00
public bool TryGetGridAndTile ( MapCoordinates coordinates , [ NotNullWhen ( true ) ] out ( EntityUid Grid , Vector2i Tile ) ? tuple )
2021-07-19 12:07:37 +02:00
{
if ( ! _mapManager . TryFindGridAt ( coordinates , out var grid ) )
{
tuple = null ;
return false ;
}
2022-06-11 18:54:41 -07:00
tuple = ( grid . GridEntityId , grid . TileIndicesFor ( coordinates ) ) ;
2021-07-19 12:07:37 +02:00
return true ;
}
2022-06-11 18:54:41 -07:00
public bool TryGetGridAndTile ( EntityCoordinates coordinates , [ NotNullWhen ( true ) ] out ( EntityUid Grid , Vector2i Tile ) ? tuple )
2021-07-19 12:07:37 +02:00
{
if ( ! coordinates . IsValid ( EntityManager ) )
{
tuple = null ;
return false ;
}
2022-06-20 12:14:35 +12:00
var gridId = coordinates . GetGridUid ( EntityManager ) ;
2021-07-19 12:07:37 +02:00
if ( ! _mapManager . TryGetGrid ( gridId , out var grid ) )
{
tuple = null ;
return false ;
}
2022-06-20 12:14:35 +12:00
tuple = ( gridId . Value , grid . TileIndicesFor ( coordinates ) ) ;
2021-07-19 12:07:37 +02:00
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
}
}