From: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com> Date: Mon, 10 Nov 2025 18:42:13 +0000 (-0800) Subject: Document Atmospherics API (#41382) X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=26d95b7944b63aa03001c52c432b9419347229ef;p=space-station-14.git Document Atmospherics API (#41382) * api docs * rem using dir. linq in atmospherics not allowed. * address review --- diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs index 29f091f340..96a5c69457 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs @@ -1,5 +1,4 @@ using System.Diagnostics; -using System.Linq; using Content.Server.Atmos.Components; using Content.Server.Atmos.Piping.Components; using Content.Server.NodeContainer.NodeGroups; @@ -14,6 +13,22 @@ namespace Content.Server.Atmos.EntitySystems; public partial class AtmosphereSystem { + /* + General API for interacting with AtmosphereSystem. + + If you feel like you're stepping on eggshells because you can't access things in AtmosphereSystem, + consider adding a method here instead of making your own way to work around it. + */ + + /// + /// Gets the that an entity is contained within. + /// + /// The entity to get the mixture for. + /// If true, will ignore mixtures that the entity is contained in + /// (ex. lockers and cryopods) and just get the tile mixture. + /// If true, will mark the tile as active for atmosphere processing. + /// A if one could be found, null otherwise. + [PublicAPI] public GasMixture? GetContainingMixture(Entity ent, bool ignoreExposed = false, bool excite = false) { if (!Resolve(ent, ref ent.Comp)) @@ -22,6 +37,17 @@ public partial class AtmosphereSystem return GetContainingMixture(ent, ent.Comp.GridUid, ent.Comp.MapUid, ignoreExposed, excite); } + /// + /// Gets the that an entity is contained within. + /// + /// The entity to get the mixture for. + /// The grid that the entity may be on. + /// The map that the entity may be on. + /// If true, will ignore mixtures that the entity is contained in + /// (ex. lockers and cryopods) and just get the tile mixture. + /// If true, will mark the tile as active for atmosphere processing. + /// A if one could be found, null otherwise. + [PublicAPI] public GasMixture? GetContainingMixture( Entity ent, Entity? grid, @@ -49,16 +75,38 @@ public partial class AtmosphereSystem return GetTileMixture(grid, map, position, excite); } - public bool HasAtmosphere(EntityUid gridUid) => _atmosQuery.HasComponent(gridUid); + /// + /// Checks if a grid has an atmosphere. + /// + /// The grid to check. + /// True if the grid has an atmosphere, false otherwise. + [PublicAPI] + public bool HasAtmosphere(EntityUid gridUid) + { + return _atmosQuery.HasComponent(gridUid); + } + /// + /// Sets whether a grid is simulated by Atmospherics. + /// + /// The grid to set. + /// Whether the grid should be simulated. + /// >True if the grid's simulated state was changed, false otherwise. + [PublicAPI] public bool SetSimulatedGrid(EntityUid gridUid, bool simulated) { + // TODO ATMOS this event literally has no subscribers. Did this just get silently refactored out? var ev = new SetSimulatedGridMethodEvent(gridUid, simulated); RaiseLocalEvent(gridUid, ref ev); return ev.Handled; } + /// + /// Checks whether a grid is simulated by Atmospherics. + /// + /// The grid to check. + /// >True if the grid is simulated, false otherwise. public bool IsSimulatedGrid(EntityUid gridUid) { var ev = new IsSimulatedGridMethodEvent(gridUid); @@ -67,24 +115,53 @@ public partial class AtmosphereSystem return ev.Simulated; } + /// + /// Gets all s on a grid. + /// + /// The grid to get mixtures for. + /// Whether to mark all tiles as active for atmosphere processing. + /// An enumerable of all gas mixtures on the grid. + [PublicAPI] public IEnumerable GetAllMixtures(EntityUid gridUid, bool excite = false) { var ev = new GetAllMixturesMethodEvent(gridUid, excite); RaiseLocalEvent(gridUid, ref ev); - if(!ev.Handled) - return Enumerable.Empty(); + if (!ev.Handled) + return []; DebugTools.AssertNotNull(ev.Mixtures); return ev.Mixtures!; } + /// + /// Invalidates a tile on a grid, marking it for revalidation. + /// + /// Frequently used tile data like are determined once and cached. + /// If this tile's state changes, ex. being added or removed, then this position in the map needs to + /// be updated. + /// + /// Tiles that need to be updated are marked as invalid and revalidated before all other + /// processing stages. + /// + /// The grid entity. + /// The tile to invalidate. + [PublicAPI] public void InvalidateTile(Entity entity, Vector2i tile) { if (_atmosQuery.Resolve(entity.Owner, ref entity.Comp, false)) entity.Comp.InvalidatedCoords.Add(tile); } + /// + /// Gets the gas mixtures for a list of tiles on a grid or map. + /// + /// The grid to get mixtures from. + /// The map to get mixtures from. + /// The list of tiles to get mixtures for. + /// Whether to mark the tiles as active for atmosphere processing. + /// >An array of gas mixtures corresponding to the input tiles. + [PublicAPI] public GasMixture?[]? GetTileMixtures( Entity? grid, Entity? map, @@ -95,7 +172,7 @@ public partial class AtmosphereSystem var handled = false; // If we've been passed a grid, try to let it handle it. - if (grid is {} gridEnt && Resolve(gridEnt, ref gridEnt.Comp1)) + if (grid is { } gridEnt && _atmosQuery.Resolve(gridEnt, ref gridEnt.Comp1)) { if (excite) Resolve(gridEnt, ref gridEnt.Comp2); @@ -128,7 +205,7 @@ public partial class AtmosphereSystem // We either don't have a grid, or the event wasn't handled. // Let the map handle it instead, and also broadcast the event. - if (map is {} mapEnt && _mapAtmosQuery.Resolve(mapEnt, ref mapEnt.Comp)) + if (map is { } mapEnt && _mapAtmosQuery.Resolve(mapEnt, ref mapEnt.Comp)) { mixtures ??= new GasMixture?[tiles.Count]; for (var i = 0; i < tiles.Count; i++) @@ -145,10 +222,21 @@ public partial class AtmosphereSystem { mixtures[i] ??= GasMixture.SpaceGas; } + return mixtures; } - public GasMixture? GetTileMixture (Entity entity, bool excite = false) + /// + /// Gets the gas mixture for a specific tile that an entity is on. + /// + /// The entity to get the tile mixture for. + /// Whether to mark the tile as active for atmosphere processing. + /// A if one could be found, null otherwise. + /// This does not return the that the entity + /// may be contained in, ex. if the entity is currently in a locker/crate with its own + /// . + [PublicAPI] + public GasMixture? GetTileMixture(Entity entity, bool excite = false) { if (!Resolve(entity.Owner, ref entity.Comp)) return null; @@ -157,6 +245,15 @@ public partial class AtmosphereSystem return GetTileMixture(entity.Comp.GridUid, entity.Comp.MapUid, indices, excite); } + /// + /// Gets the gas mixture for a specific tile on a grid or map. + /// + /// The grid to get the mixture from. + /// The map to get the mixture from. + /// The tile to get the mixture from. + /// Whether to mark the tile as active for atmosphere processing. + /// >A if one could be found, null otherwise. + [PublicAPI] public GasMixture? GetTileMixture( Entity? grid, Entity? map, @@ -164,8 +261,8 @@ public partial class AtmosphereSystem bool excite = false) { // If we've been passed a grid, try to let it handle it. - if (grid is {} gridEnt - && Resolve(gridEnt, ref gridEnt.Comp1, false) + if (grid is { } gridEnt + && _atmosQuery.Resolve(gridEnt, ref gridEnt.Comp1, false) && gridEnt.Comp1.Tiles.TryGetValue(gridTile, out var tile)) { if (excite) @@ -177,13 +274,20 @@ public partial class AtmosphereSystem return tile.Air; } - if (map is {} mapEnt && _mapAtmosQuery.Resolve(mapEnt, ref mapEnt.Comp, false)) + if (map is { } mapEnt && _mapAtmosQuery.Resolve(mapEnt, ref mapEnt.Comp, false)) return mapEnt.Comp.Mixture; // Default to a space mixture... This is a space game, after all! return GasMixture.SpaceGas; } + /// + /// Triggers a tile's to react. + /// + /// The grid to react the tile on. + /// The tile to react. + /// The result of the reaction. + [PublicAPI] public ReactionResult ReactTile(EntityUid gridId, Vector2i tile) { var ev = new ReactTileMethodEvent(gridId, tile); @@ -194,24 +298,49 @@ public partial class AtmosphereSystem return ev.Result; } - public bool IsTileAirBlocked(EntityUid gridUid, Vector2i tile, AtmosDirection directions = AtmosDirection.All, MapGridComponent? mapGridComp = null) + /// + /// Checks if a tile on a grid is air-blocked in the specified directions. + /// + /// The grid to check. + /// The tile on the grid to check. + /// The directions to check for air-blockage. + /// Optional map grid component associated with the grid. + /// True if the tile is air-blocked in the specified directions, false otherwise. + [PublicAPI] + public bool IsTileAirBlocked(EntityUid gridUid, + Vector2i tile, + AtmosDirection directions = AtmosDirection.All, + MapGridComponent? mapGridComp = null) { if (!Resolve(gridUid, ref mapGridComp, false)) return false; + // TODO ATMOS: This reconstructs the data instead of getting the cached version. Might want to include a method to get the cached version later. var data = GetAirtightData(gridUid, mapGridComp, tile); return data.BlockedDirections.IsFlagSet(directions); } + /// + /// Checks if a tile on a grid or map is space as defined by a tile's definition of space. + /// Some tiles can hold back space and others cannot - for example, plating can hold + /// back space, whereas scaffolding cannot, exposing the map atmosphere beneath. + /// + /// This does not check if the on the tile is space, + /// it only checks the current tile's ability to hold back space. + /// The grid to check. + /// The map to check. + /// The tile to check. + /// True if the tile is space, false otherwise. + [PublicAPI] public bool IsTileSpace(Entity? grid, Entity? map, Vector2i tile) { - if (grid is {} gridEnt && _atmosQuery.Resolve(gridEnt, ref gridEnt.Comp, false) - && gridEnt.Comp.Tiles.TryGetValue(tile, out var tileAtmos)) + if (grid is { } gridEnt && _atmosQuery.Resolve(gridEnt, ref gridEnt.Comp, false) + && gridEnt.Comp.Tiles.TryGetValue(tile, out var tileAtmos)) { return tileAtmos.Space; } - if (map is {} mapEnt && _mapAtmosQuery.Resolve(mapEnt, ref mapEnt.Comp, false)) + if (map is { } mapEnt && _mapAtmosQuery.Resolve(mapEnt, ref mapEnt.Comp, false)) return mapEnt.Comp.Space; // If nothing handled the event, it'll default to true. @@ -219,28 +348,77 @@ public partial class AtmosphereSystem return true; } + /// + /// Checks if the gas mixture on a tile is "probably safe". + /// Probably safe is defined as having at least air alarm-grade safe pressure and temperature. + /// (more than 260K, less than 360K, and between safe low and high pressure as defined in + /// and ) + /// + /// The grid to check. + /// The map to check. + /// The tile to check. + /// True if the tile's mixture is probably safe, false otherwise. + [PublicAPI] public bool IsTileMixtureProbablySafe(Entity? grid, Entity map, Vector2i tile) { return IsMixtureProbablySafe(GetTileMixture(grid, map, tile)); } + /// + /// Gets the heat capacity of the gas mixture on a tile. + /// + /// The grid to check. + /// The map to check. + /// The tile on the grid/map to check. + /// >The heat capacity of the tile's mixture, or the heat capacity of space if a mixture could not be found. + [PublicAPI] public float GetTileHeatCapacity(Entity? grid, Entity map, Vector2i tile) { return GetHeatCapacity(GetTileMixture(grid, map, tile) ?? GasMixture.SpaceGas); } + /// + /// Gets an enumerator for the adjacent tile mixtures of a tile on a grid. + /// + /// The grid to get adjacent tile mixtures from. + /// The tile to get adjacent mixtures for. + /// Whether to include blocked adjacent tiles. + /// Whether to mark the adjacent tiles as active for atmosphere processing. + /// An enumerator for the adjacent tile mixtures. + [PublicAPI] public TileMixtureEnumerator GetAdjacentTileMixtures(Entity grid, Vector2i tile, bool includeBlocked = false, bool excite = false) { + // TODO ATMOS includeBlocked and excite parameters are unhandled currently. if (!_atmosQuery.Resolve(grid, ref grid.Comp, false)) return TileMixtureEnumerator.Empty; return !grid.Comp.Tiles.TryGetValue(tile, out var atmosTile) ? TileMixtureEnumerator.Empty - : new(atmosTile.AdjacentTiles); + : new TileMixtureEnumerator(atmosTile.AdjacentTiles); } - public void HotspotExpose(Entity grid, Vector2i tile, float exposedTemperature, float exposedVolume, - EntityUid? sparkSourceUid = null, bool soh = false) + /// + /// Exposes a tile to a hotspot of given temperature and volume, igniting it if conditions are met. + /// + /// The grid to expose the tile on. + /// The tile to expose. + /// The temperature of the hotspot to expose. + /// You can think of this as exposing a temperature of a flame. + /// The volume of the hotspot to expose. + /// You can think of this as how big the flame is initially. + /// Bigger flames will ramp a fire faster. + /// Whether to "boost" a fire that's currently on the tile already. + /// Does nothing if the tile isn't already a hotspot. + /// This clamps the temperature and volume of the hotspot to the maximum + /// of the provided parameters and whatever's on the tile. + /// Entity that started the exposure for admin logging. + [PublicAPI] + public void HotspotExpose(Entity grid, + Vector2i tile, + float exposedTemperature, + float exposedVolume, + EntityUid? sparkSourceUid = null, + bool soh = false) { if (!_atmosQuery.Resolve(grid, ref grid.Comp, false)) return; @@ -249,8 +427,26 @@ public partial class AtmosphereSystem HotspotExpose(grid.Comp, atmosTile, exposedTemperature, exposedVolume, soh, sparkSourceUid); } - public void HotspotExpose(TileAtmosphere tile, float exposedTemperature, float exposedVolume, - EntityUid? sparkSourceUid = null, bool soh = false) + /// + /// Exposes a tile to a hotspot of given temperature and volume, igniting it if conditions are met. + /// + /// The to expose. + /// The temperature of the hotspot to expose. + /// You can think of this as exposing a temperature of a flame. + /// The volume of the hotspot to expose. + /// You can think of this as how big the flame is initially. + /// Bigger flames will ramp a fire faster. + /// Whether to "boost" a fire that's currently on the tile already. + /// Does nothing if the tile isn't already a hotspot. + /// This clamps the temperature and volume of the hotspot to the maximum + /// of the provided parameters and whatever's on the tile. + /// Entity that started the exposure for admin logging. + [PublicAPI] + public void HotspotExpose(TileAtmosphere tile, + float exposedTemperature, + float exposedVolume, + EntityUid? sparkSourceUid = null, + bool soh = false) { if (!_atmosQuery.TryGetComponent(tile.GridIndex, out var atmos)) return; @@ -259,12 +455,25 @@ public partial class AtmosphereSystem HotspotExpose(atmos, tile, exposedTemperature, exposedVolume, soh, sparkSourceUid); } + /// + /// Extinguishes a hotspot on a tile. + /// + /// The grid to extinguish the hotspot on. + /// The tile on the grid to extinguish the hotspot on. + [PublicAPI] public void HotspotExtinguish(EntityUid gridUid, Vector2i tile) { var ev = new HotspotExtinguishMethodEvent(gridUid, tile); RaiseLocalEvent(gridUid, ref ev); } + /// + /// Checks if a hotspot is active on a tile. + /// + /// The grid to check. + /// The tile on the grid to check. + /// True if a hotspot is active on the tile, false otherwise. + [PublicAPI] public bool IsHotspotActive(EntityUid gridUid, Vector2i tile) { var ev = new IsHotspotActiveMethodEvent(gridUid, tile); @@ -274,11 +483,25 @@ public partial class AtmosphereSystem return ev.Result; } + /// + /// Adds a to a grid. + /// + /// The grid to add the pipe net to. + /// The pipe net to add. + /// True if the pipe net was added, false otherwise. + [PublicAPI] public bool AddPipeNet(Entity grid, PipeNet pipeNet) { return _atmosQuery.Resolve(grid, ref grid.Comp, false) && grid.Comp.PipeNets.Add(pipeNet); } + /// + /// Removes a from a grid. + /// + /// The grid to remove the pipe net from. + /// The pipe net to remove. + /// True if the pipe net was removed, false otherwise. + [PublicAPI] public bool RemovePipeNet(Entity grid, PipeNet pipeNet) { // Technically this event can be fired even on grids that don't @@ -292,6 +515,13 @@ public partial class AtmosphereSystem return _atmosQuery.Resolve(grid, ref grid.Comp, false) && grid.Comp.PipeNets.Remove(pipeNet); } + /// + /// Adds an entity with an to a grid's list of atmos devices. + /// + /// The grid to add the device to. + /// The device to add. + /// True if the device was added, false otherwise. + [PublicAPI] public bool AddAtmosDevice(Entity grid, Entity device) { DebugTools.Assert(device.Comp.JoinedGrid == null); @@ -307,6 +537,12 @@ public partial class AtmosphereSystem return true; } + /// + /// Removes an entity with an from a grid's list of atmos devices. + /// + /// The grid to remove the device from. + /// The device to remove. + /// True if the device was removed, false otherwise. public bool RemoveAtmosDevice(Entity grid, Entity device) { DebugTools.Assert(device.Comp.JoinedGrid == grid); @@ -418,23 +654,44 @@ public partial class AtmosphereSystem return contains; } - [ByRefEvent] private record struct SetSimulatedGridMethodEvent - (EntityUid Grid, bool Simulated, bool Handled = false); - - [ByRefEvent] private record struct IsSimulatedGridMethodEvent - (EntityUid Grid, bool Simulated = false, bool Handled = false); - - [ByRefEvent] private record struct GetAllMixturesMethodEvent - (EntityUid Grid, bool Excite = false, IEnumerable? Mixtures = null, bool Handled = false); - - [ByRefEvent] private record struct ReactTileMethodEvent - (EntityUid GridId, Vector2i Tile, ReactionResult Result = default, bool Handled = false); - - [ByRefEvent] private record struct HotspotExtinguishMethodEvent - (EntityUid Grid, Vector2i Tile, bool Handled = false); - - [ByRefEvent] private record struct IsHotspotActiveMethodEvent - (EntityUid Grid, Vector2i Tile, bool Result = false, bool Handled = false); + [ByRefEvent] + private record struct SetSimulatedGridMethodEvent( + EntityUid Grid, + bool Simulated, + bool Handled = false); + + [ByRefEvent] + private record struct IsSimulatedGridMethodEvent( + EntityUid Grid, + bool Simulated = false, + bool Handled = false); + + [ByRefEvent] + private record struct GetAllMixturesMethodEvent( + EntityUid Grid, + bool Excite = false, + IEnumerable? Mixtures = null, + bool Handled = false); + + [ByRefEvent] + private record struct ReactTileMethodEvent( + EntityUid GridId, + Vector2i Tile, + ReactionResult Result = default, + bool Handled = false); + + [ByRefEvent] + private record struct HotspotExtinguishMethodEvent( + EntityUid Grid, + Vector2i Tile, + bool Handled = false); + + [ByRefEvent] + private record struct IsHotspotActiveMethodEvent( + EntityUid Grid, + Vector2i Tile, + bool Result = false, + bool Handled = false); }