diff --git a/Content.Server/Atmos/Components/GridAtmosphereComponent.cs b/Content.Server/Atmos/Components/GridAtmosphereComponent.cs index 816fc09f4a..53670f8d05 100644 --- a/Content.Server/Atmos/Components/GridAtmosphereComponent.cs +++ b/Content.Server/Atmos/Components/GridAtmosphereComponent.cs @@ -1,24 +1,13 @@ -// ReSharper disable once RedundantUsingDirective using System; using System.Collections; using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; using Content.Server.Atmos.EntitySystems; using Content.Server.Atmos.Piping.Components; -using Content.Server.CPUJob.JobQueues.Queues; using Content.Server.NodeContainer.NodeGroups; -using Content.Shared.Atmos; -using Content.Shared.Maps; -using Robust.Server.GameObjects; using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Log; -using Robust.Shared.Map; using Robust.Shared.Maths; using Robust.Shared.Serialization; using Robust.Shared.Serialization.Manager.Attributes; -using Robust.Shared.Timing; using Robust.Shared.ViewVariables; using Dependency = Robust.Shared.IoC.DependencyAttribute; @@ -31,33 +20,21 @@ namespace Content.Server.Atmos.Components [RegisterComponent, Serializable] public class GridAtmosphereComponent : Component, IGridAtmosphereComponent, ISerializationHooks { - [Dependency] private IMapManager _mapManager = default!; - [Dependency] private ITileDefinitionManager _tileDefinitionManager = default!; - [Dependency] private IServerEntityManager _serverEntityManager = default!; - [Dependency] private IGameTiming _gameTiming = default!; - - internal GasTileOverlaySystem GasTileOverlaySystem { get; private set; } = default!; - public AtmosphereSystem AtmosphereSystem { get; private set; } = default!; - public override string Name => "GridAtmosphere"; - - public bool ProcessingPaused { get; set; } = false; - public float Timer { get; set; } - private GridId _gridId; - - [ComponentDependency] private IMapGridComponent? _mapGridComponent; - public virtual bool Simulated => true; + [ViewVariables] + public bool RevalidatePaused { get; set; } = false; + + [ViewVariables] + public bool ProcessingPaused { get; set; } = false; + + [ViewVariables] + public float Timer { get; set; } = 0f; + [ViewVariables] public int UpdateCounter { get; set; } = 0; - [ViewVariables] - public readonly HashSet ExcitedGroups = new(1000); - - [ViewVariables] - public int ExcitedGroupCount => ExcitedGroups.Count; - [DataField("uniqueMixes")] public List? UniqueMixes; @@ -73,6 +50,12 @@ namespace Content.Server.Atmos.Components [ViewVariables] public int ActiveTilesCount => ActiveTiles.Count; + [ViewVariables] + public readonly HashSet ExcitedGroups = new(1000); + + [ViewVariables] + public int ExcitedGroupCount => ExcitedGroups.Count; + [ViewVariables] public readonly HashSet HotspotTiles = new(1000); @@ -85,9 +68,6 @@ namespace Content.Server.Atmos.Components [ViewVariables] public int SuperconductivityTilesCount => SuperconductivityTiles.Count; - [ViewVariables] - public readonly HashSet InvalidatedCoords = new(1000); - [ViewVariables] public HashSet HighPressureDelta = new(1000); @@ -112,22 +92,21 @@ namespace Content.Server.Atmos.Components [ViewVariables] public Queue CurrentRunAtmosDevices = new(); + [ViewVariables] + public readonly HashSet InvalidatedCoords = new(1000); + + [ViewVariables] + public Queue CurrentRunInvalidatedCoordinates = new(); + + [ViewVariables] + public int InvalidatedCoordsCount => InvalidatedCoords.Count; + + [ViewVariables] + public long EqualizationQueueCycleControl { get; set; } + [ViewVariables] public AtmosphereProcessingState State { get; set; } = AtmosphereProcessingState.TileEqualize; - public GridAtmosphereComponent() - { - ProcessingPaused = false; - } - - /// - public virtual void PryTile(Vector2i indices) - { - if (IsSpace(indices) || IsAirBlocked(indices)) return; - - indices.PryTile(_gridId, _mapManager, _tileDefinitionManager, _serverEntityManager); - } - void ISerializationHooks.BeforeSerialization() { var uniqueMixes = new List(); @@ -156,403 +135,5 @@ namespace Content.Server.Atmos.Components UniqueMixes = uniqueMixes; TilesUniqueMixes = tiles; } - - protected override void Initialize() - { - base.Initialize(); - - Tiles.Clear(); - - if (TilesUniqueMixes != null && Owner.TryGetComponent(out IMapGridComponent? mapGrid)) - { - foreach (var (indices, mix) in TilesUniqueMixes) - { - try - { - Tiles.Add(indices, new TileAtmosphere(this, mapGrid.GridIndex, indices, (GasMixture) UniqueMixes![mix].Clone())); - } - catch (ArgumentOutOfRangeException) - { - Logger.Error($"Error during atmos serialization! Tile at {indices} points to an unique mix ({mix}) out of range!"); - throw; - } - - Invalidate(indices); - } - } - - GasTileOverlaySystem = EntitySystem.Get(); - AtmosphereSystem = EntitySystem.Get(); - - RepopulateTiles(); - } - - protected override void OnAdd() - { - base.OnAdd(); - - if (Owner.TryGetComponent(out IMapGridComponent? mapGrid)) - _gridId = mapGrid.GridIndex; - } - - public virtual void RepopulateTiles() - { - if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return; - - foreach (var tile in mapGrid.Grid.GetAllTiles()) - { - if(!Tiles.ContainsKey(tile.GridIndices)) - Tiles.Add(tile.GridIndices, new TileAtmosphere(this, tile.GridIndex, tile.GridIndices, new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.T20C})); - - Invalidate(tile.GridIndices); - } - - foreach (var (_, tile) in Tiles.ToArray()) - { - tile.UpdateAdjacent(); - tile.UpdateVisuals(); - } - } - - /// - public virtual void Invalidate(Vector2i indices) - { - InvalidatedCoords.Add(indices); - } - - public virtual void Revalidate() - { - foreach (var indices in InvalidatedCoords) - { - var tile = GetTile(indices); - - if (tile == null) - { - tile = new TileAtmosphere(this, _gridId, indices, new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.T20C}); - Tiles[indices] = tile; - } - - var isAirBlocked = IsAirBlocked(indices); - - if (IsSpace(indices) && !isAirBlocked) - { - tile.Air = new GasMixture(GetVolumeForCells(1)); - tile.Air.MarkImmutable(); - Tiles[indices] = tile; - - } else if (isAirBlocked) - { - var nullAir = false; - - foreach (var airtight in GetObstructingComponents(indices)) - { - if (airtight.NoAirWhenFullyAirBlocked) - { - nullAir = true; - break; - } - } - - if(nullAir) - tile.Air = null; - } - else - { - if (tile.Air == null && NeedsVacuumFixing(indices)) - { - FixVacuum(tile.GridIndices); - } - - // Tile used to be space, but isn't anymore. - if (tile.Air?.Immutable ?? false) - { - tile.Air = null; - } - - tile.Air ??= new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.T20C}; - } - - // By removing the active tile, we effectively remove its excited group, if any. - RemoveActiveTile(tile); - - // Then we activate the tile again. - AddActiveTile(tile); - - tile.BlockedAirflow = GetBlockedDirections(indices); - - // TODO ATMOS: Query all the contents of this tile (like walls) and calculate the correct thermal conductivity - tile.ThermalConductivity = tile.Tile?.Tile.GetContentTileDefinition().ThermalConductivity ?? 0.5f; - tile.UpdateAdjacent(); - GasTileOverlaySystem.Invalidate(_gridId, indices); - - for (var i = 0; i < Atmospherics.Directions; i++) - { - var direction = (AtmosDirection) (1 << i); - var otherIndices = indices.Offset(direction.ToDirection()); - var otherTile = GetTile(otherIndices); - if (otherTile != null) AddActiveTile(otherTile); - } - } - - InvalidatedCoords.Clear(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void UpdateAdjacentBits(Vector2i indices) - { - GetTile(indices)?.UpdateAdjacent(); - } - - /// - public virtual void FixVacuum(Vector2i indices) - { - var tile = GetTile(indices); - if (tile?.GridIndex != _gridId) return; - // includeAirBlocked is false, therefore all tiles in this have Air != null. - var adjacent = GetAdjacentTiles(indices); - tile.Air = new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.T20C}; - Tiles[indices] = tile; - - var ratio = 1f / adjacent.Count; - - foreach (var (_, adj) in adjacent) - { - var mix = adj.Air!.RemoveRatio(ratio); - AtmosphereSystem.Merge(tile.Air, mix); - AtmosphereSystem.Merge(adj.Air, mix); - } - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public virtual void AddActiveTile(TileAtmosphere tile) - { - if (tile?.GridIndex != _gridId || tile.Air == null) return; - tile.Excited = true; - ActiveTiles.Add(tile); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public virtual void RemoveActiveTile(TileAtmosphere tile, bool disposeGroup = true) - { - ActiveTiles.Remove(tile); - tile.Excited = false; - if(disposeGroup) - tile.ExcitedGroup?.Dispose(); - else - tile.ExcitedGroup?.RemoveTile(tile); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public virtual void AddHotspotTile(TileAtmosphere tile) - { - if (tile?.GridIndex != _gridId || tile?.Air == null) return; - HotspotTiles.Add(tile); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public virtual void RemoveHotspotTile(TileAtmosphere tile) - { - HotspotTiles.Remove(tile); - } - - public virtual void AddSuperconductivityTile(TileAtmosphere tile) - { - if (tile?.GridIndex != _gridId || !AtmosphereSystem.Superconduction) return; - SuperconductivityTiles.Add(tile); - } - - public virtual void RemoveSuperconductivityTile(TileAtmosphere tile) - { - SuperconductivityTiles.Remove(tile); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public virtual void AddHighPressureDelta(TileAtmosphere tile) - { - if (tile.GridIndex != _gridId) return; - HighPressureDelta.Add(tile); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public virtual bool HasHighPressureDelta(TileAtmosphere tile) - { - return HighPressureDelta.Contains(tile); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public virtual void AddExcitedGroup(ExcitedGroup excitedGroup) - { - ExcitedGroups.Add(excitedGroup); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public virtual void RemoveExcitedGroup(ExcitedGroup excitedGroup) - { - ExcitedGroups.Remove(excitedGroup); - } - - public virtual void AddPipeNet(IPipeNet pipeNet) - { - PipeNets.Add(pipeNet); - } - - public virtual void RemovePipeNet(IPipeNet pipeNet) - { - PipeNets.Remove(pipeNet); - } - - public virtual void AddAtmosDevice(AtmosDeviceComponent atmosDevice) - { - AtmosDevices.Add(atmosDevice); - } - - public virtual void RemoveAtmosDevice(AtmosDeviceComponent atmosDevice) - { - AtmosDevices.Remove(atmosDevice); - } - - /// - public virtual TileAtmosphere? GetTile(EntityCoordinates coordinates, bool createSpace = true) - { - return GetTile(coordinates.ToVector2i(_serverEntityManager, _mapManager), createSpace); - } - - /// - public virtual TileAtmosphere? GetTile(Vector2i indices, bool createSpace = true) - { - if (Tiles.TryGetValue(indices, out var tile)) return tile; - - // We don't have that tile! - if (IsSpace(indices) && createSpace) - { - return new TileAtmosphere(this, _gridId, indices, new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.TCMB}, true); - } - - return null; - } - - /// - public bool IsAirBlocked(Vector2i indices, AtmosDirection direction = AtmosDirection.All) - { - var directions = AtmosDirection.Invalid; - - foreach (var obstructingComponent in GetObstructingComponents(indices)) - { - 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; - } - - return false; - } - - /// - public virtual bool IsSpace(Vector2i indices) - { - if (_mapGridComponent == null) return default; - - return _mapGridComponent.Grid.GetTileRef(indices).IsSpace(); - } - - public Dictionary GetAdjacentTiles(EntityCoordinates coordinates, bool includeAirBlocked = false) - { - return GetAdjacentTiles(coordinates.ToVector2i(_serverEntityManager, _mapManager), includeAirBlocked); - } - - public Dictionary GetAdjacentTiles(Vector2i indices, bool includeAirBlocked = false) - { - var sides = new Dictionary(); - for (var i = 0; i < Atmospherics.Directions; i++) - { - var direction = (AtmosDirection) (1 << i); - var side = indices.Offset(direction.ToDirection()); - var tile = GetTile(side); - if (tile != null && (tile.Air != null || includeAirBlocked)) - sides[direction] = tile; - } - - return sides; - } - - public long EqualizationQueueCycleControl { get; set; } - - /// - public float GetVolumeForCells(int cellCount) - { - if (_mapGridComponent == null) return default; - - return _mapGridComponent.Grid.TileSize * cellCount * Atmospherics.CellVolume; - } - - protected virtual IEnumerable GetObstructingComponents(Vector2i indices) - { - var gridLookup = EntitySystem.Get(); - - foreach (var v in gridLookup.GetEntitiesIntersecting(_gridId, indices)) - { - if (v.TryGetComponent(out var ac)) - yield return ac; - } - } - - private bool NeedsVacuumFixing(Vector2i indices) - { - var value = false; - - foreach (var airtightComponent in GetObstructingComponents(indices)) - { - value |= airtightComponent.FixVacuum; - } - - return value; - } - - private AtmosDirection GetBlockedDirections(Vector2i indices) - { - var value = AtmosDirection.Invalid; - - foreach (var airtightComponent in GetObstructingComponents(indices)) - { - if(airtightComponent.AirBlocked) - value |= airtightComponent.AirBlockedDirection; - } - - return value; - } - - public void Dispose() - { - - } - - public IEnumerator GetEnumerator() - { - return Tiles.Values.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - public virtual void BurnTile(Vector2i gridIndices) - { - // TODO ATMOS - } } } diff --git a/Content.Server/Atmos/Components/IGridAtmosphereComponent.cs b/Content.Server/Atmos/Components/IGridAtmosphereComponent.cs index 877e5e86a5..11b953b2fa 100644 --- a/Content.Server/Atmos/Components/IGridAtmosphereComponent.cs +++ b/Content.Server/Atmos/Components/IGridAtmosphereComponent.cs @@ -1,181 +1,12 @@ -using System.Collections.Generic; -using Content.Server.Atmos.Piping.Components; -using Content.Server.NodeContainer.NodeGroups; -using Content.Shared.Atmos; -using Robust.Shared.GameObjects; -using Robust.Shared.Map; -using Robust.Shared.Maths; +using Robust.Shared.GameObjects; namespace Content.Server.Atmos.Components { - public interface IGridAtmosphereComponent : IComponent, IEnumerable + public interface IGridAtmosphereComponent : IComponent { /// /// Whether this atmosphere is simulated or not. /// bool Simulated { get; } - - /// - /// Number of times has been called. - /// - int UpdateCounter { get; } - - /// - /// Control variable for equalization. - /// - long EqualizationQueueCycleControl { get; set; } - - /// - /// Attemps to pry a tile. - /// - /// - void PryTile(Vector2i indices); - - /// - /// Burns a tile. - /// - /// - void BurnTile(Vector2i gridIndices); - - /// - /// Invalidates a coordinate to be revalidated again. - /// Use this after changing a tile's gas contents, or when the tile becomes space, etc. - /// - /// - void Invalidate(Vector2i indices); - - /// - /// Attempts to fix a sudden vacuum by creating gas. - /// - void FixVacuum(Vector2i indices); - - /// - /// Revalidates indices immediately. - /// - /// - void UpdateAdjacentBits(Vector2i indices); - - /// - /// Adds an active tile so it becomes processed every update until it becomes inactive. - /// Also makes the tile excited. - /// - /// - void AddActiveTile(TileAtmosphere tile); - - /// - /// Removes an active tile and disposes of its . - /// Use with caution. - /// - /// - void RemoveActiveTile(TileAtmosphere tile, bool disposeGroup = true); - - /// - /// Marks a tile as having a hotspot so it can be processed. - /// - /// - void AddHotspotTile(TileAtmosphere tile); - - /// - /// Removes a tile from the hotspot processing list. - /// - /// - void RemoveHotspotTile(TileAtmosphere tile); - - /// - /// Marks a tile as superconductive so it can be processed. - /// - /// - void AddSuperconductivityTile(TileAtmosphere tile); - - /// - /// Removes a tile from the superconductivity processing list. - /// - /// - void RemoveSuperconductivityTile(TileAtmosphere tile); - - /// - /// Marks a tile has having high pressure differences that need to be equalized. - /// - /// - void AddHighPressureDelta(TileAtmosphere tile); - - /// - /// Returns whether the tile in question is marked as having high pressure differences or not. - /// - /// - /// - bool HasHighPressureDelta(TileAtmosphere tile); - - /// - /// Adds a excited group to be processed. - /// - /// - void AddExcitedGroup(ExcitedGroup excitedGroup); - - /// - /// Removes an excited group. - /// - /// - void RemoveExcitedGroup(ExcitedGroup excitedGroup); - - /// - /// Returns a tile. - /// - /// - /// - /// - TileAtmosphere? GetTile(Vector2i indices, bool createSpace = true); - - /// - /// Returns a tile. - /// - /// - /// - /// - TileAtmosphere? GetTile(EntityCoordinates coordinates, bool createSpace = true); - - /// - /// Returns if the tile in question is air-blocked. - /// This could be due to a wall, an airlock, etc. - /// - /// - /// - /// - /// - bool IsAirBlocked(Vector2i indices, AtmosDirection direction); - - /// - /// Returns if the tile in question is space. - /// - /// - /// - bool IsSpace(Vector2i indices); - - /// - /// Returns the volume in liters for a number of cells/tiles. - /// - /// - /// - float GetVolumeForCells(int cellCount); - - void RepopulateTiles(); - - /// - /// Returns a dictionary of adjacent TileAtmospheres. - /// - Dictionary GetAdjacentTiles(EntityCoordinates coordinates, bool includeAirBlocked = false); - - /// - /// Returns a dictionary of adjacent TileAtmospheres. - /// - Dictionary GetAdjacentTiles(Vector2i indices, bool includeAirBlocked = false); - - void AddPipeNet(IPipeNet pipeNet); - - void RemovePipeNet(IPipeNet pipeNet); - - void AddAtmosDevice(AtmosDeviceComponent atmosDevice); - - void RemoveAtmosDevice(AtmosDeviceComponent atmosDevice); } } diff --git a/Content.Server/Atmos/Components/SpaceGridAtmosphereComponent.cs b/Content.Server/Atmos/Components/SpaceGridAtmosphereComponent.cs index c87caa0886..6fa75f774d 100644 --- a/Content.Server/Atmos/Components/SpaceGridAtmosphereComponent.cs +++ b/Content.Server/Atmos/Components/SpaceGridAtmosphereComponent.cs @@ -12,22 +12,5 @@ namespace Content.Server.Atmos.Components public class SpaceGridAtmosphereComponent : UnsimulatedGridAtmosphereComponent { public override string Name => "SpaceGridAtmosphere"; - - public override void RepopulateTiles() { } - - public override bool IsSpace(Vector2i indices) - { - return true; - } - - public override TileAtmosphere GetTile(Vector2i indices, bool createSpace = true) - { - return new(this, GridId.Invalid, indices, new GasMixture(Atmospherics.CellVolume), true); - } - - protected override IEnumerable GetObstructingComponents(Vector2i indices) - { - return Enumerable.Empty(); - } } } diff --git a/Content.Server/Atmos/Components/UnsimulatedGridAtmosphereComponent.cs b/Content.Server/Atmos/Components/UnsimulatedGridAtmosphereComponent.cs index 8aded0a2dd..806164e6c1 100644 --- a/Content.Server/Atmos/Components/UnsimulatedGridAtmosphereComponent.cs +++ b/Content.Server/Atmos/Components/UnsimulatedGridAtmosphereComponent.cs @@ -16,55 +16,5 @@ namespace Content.Server.Atmos.Components public override string Name => "UnsimulatedGridAtmosphere"; public override bool Simulated => false; - - public override void PryTile(Vector2i indices) { } - - public override void RepopulateTiles() - { - if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return; - - foreach (var tile in mapGrid.Grid.GetAllTiles()) - { - if(!Tiles.ContainsKey(tile.GridIndices)) - Tiles.Add(tile.GridIndices, new TileAtmosphere(this, tile.GridIndex, tile.GridIndices, new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.T20C})); - } - } - - public override void Invalidate(Vector2i indices) { } - - public override void Revalidate() { } - - public override void FixVacuum(Vector2i indices) { } - - public override void AddActiveTile(TileAtmosphere? tile) { } - - public override void RemoveActiveTile(TileAtmosphere? tile, bool disposeGroup = true) { } - - public override void AddHotspotTile(TileAtmosphere? tile) { } - - public override void RemoveHotspotTile(TileAtmosphere? tile) { } - - public override void AddSuperconductivityTile(TileAtmosphere? tile) { } - - public override void RemoveSuperconductivityTile(TileAtmosphere? tile) { } - - public override void AddHighPressureDelta(TileAtmosphere? tile) { } - - public override bool HasHighPressureDelta(TileAtmosphere tile) - { - return false; - } - - public override void AddExcitedGroup(ExcitedGroup excitedGroup) { } - - public override void RemoveExcitedGroup(ExcitedGroup excitedGroup) { } - - public override void AddPipeNet(IPipeNet pipeNet) { } - - public override void RemovePipeNet(IPipeNet pipeNet) { } - - public override void AddAtmosDevice(AtmosDeviceComponent atmosDevice) { } - - public override void RemoveAtmosDevice(AtmosDeviceComponent atmosDevice) { } } } diff --git a/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs b/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs index f9d0288fc8..87a9bc0952 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs @@ -127,6 +127,7 @@ namespace Content.Server.Atmos.EntitySystems AccumulatedFrameTime -= _updateCooldown; var currentTick = _gameTiming.CurTick; + var atmosphereSystem = Get(); // Now we'll go through each player, then through each chunk in range of that player checking if the player is still in range // If they are, check if they need the new data to send (i.e. if there's an overlay for the gas). @@ -156,7 +157,7 @@ namespace Content.Server.Atmos.EntitySystems for (var x = 0; x < LocalViewRange; x++) { var Vector2i = new Vector2i(baseTile.X + x, baseTile.Y + y); - debugOverlayContent[index++] = ConvertTileToData(gam.GetTile(Vector2i)); + debugOverlayContent[index++] = ConvertTileToData(atmosphereSystem.GetTileAtmosphereOrCreateSpace(grid, gam, Vector2i)); } } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs index 50576c5221..3ab492f850 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs @@ -1,9 +1,13 @@ using Content.Shared.CCVar; +using Robust.Shared.Configuration; +using Robust.Shared.IoC; namespace Content.Server.Atmos.EntitySystems { public partial class AtmosphereSystem { + [Dependency] private readonly IConfigurationManager _cfg = default!; + public bool SpaceWind { get; private set; } public string? SpaceWindSound { get; private set; } public bool MonstermosEqualization { get; private set; } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.ExcitedGroup.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.ExcitedGroup.cs new file mode 100644 index 0000000000..8f18d63e4f --- /dev/null +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.ExcitedGroup.cs @@ -0,0 +1,137 @@ +using Content.Server.Atmos.Components; +using Content.Shared.Atmos; +using Robust.Shared.Utility; + +namespace Content.Server.Atmos.EntitySystems +{ + public partial class AtmosphereSystem + { + private void ExcitedGroupAddTile(ExcitedGroup excitedGroup, TileAtmosphere tile) + { + DebugTools.Assert(!excitedGroup.Disposed, "Excited group is disposed!"); + DebugTools.Assert(tile.ExcitedGroup == null, "Tried to add a tile to an excited group when it's already in another one!"); + excitedGroup.Tiles.Add(tile); + tile.ExcitedGroup = excitedGroup; + ExcitedGroupResetCooldowns(excitedGroup); + } + + private void ExcitedGroupRemoveTile(ExcitedGroup excitedGroup, TileAtmosphere tile) + { + DebugTools.Assert(!excitedGroup.Disposed, "Excited group is disposed!"); + DebugTools.Assert(tile.ExcitedGroup == excitedGroup, "Tried to remove a tile from an excited group it's not present in!"); + tile.ExcitedGroup = null; + excitedGroup.Tiles.Remove(tile); + } + + private void ExcitedGroupMerge(GridAtmosphereComponent gridAtmosphere, ExcitedGroup ourGroup, ExcitedGroup otherGroup) + { + DebugTools.Assert(!ourGroup.Disposed, "Excited group is disposed!"); + DebugTools.Assert(!otherGroup.Disposed, "Excited group is disposed!"); + DebugTools.Assert(gridAtmosphere.ExcitedGroups.Contains(ourGroup), "Grid Atmosphere does not contain Excited Group!"); + DebugTools.Assert(gridAtmosphere.ExcitedGroups.Contains(otherGroup), "Grid Atmosphere does not contain Excited Group!"); + var ourSize = ourGroup.Tiles.Count; + var otherSize = otherGroup.Tiles.Count; + + ExcitedGroup winner; + ExcitedGroup loser; + + if (ourSize > otherSize) + { + winner = ourGroup; + loser = otherGroup; + } + else + { + winner = otherGroup; + loser = ourGroup; + } + + foreach (var tile in loser.Tiles) + { + tile.ExcitedGroup = winner; + winner.Tiles.Add(tile); + } + + loser.Tiles.Clear(); + ExcitedGroupDispose(gridAtmosphere, loser); + ExcitedGroupResetCooldowns(winner); + } + + private void ExcitedGroupResetCooldowns(ExcitedGroup excitedGroup) + { + DebugTools.Assert(!excitedGroup.Disposed, "Excited group is disposed!"); + excitedGroup.BreakdownCooldown = 0; + excitedGroup.DismantleCooldown = 0; + } + + private void ExcitedGroupSelfBreakdown(GridAtmosphereComponent gridAtmosphere, ExcitedGroup excitedGroup, bool spaceIsAllConsuming = false) + { + DebugTools.Assert(!excitedGroup.Disposed, "Excited group is disposed!"); + DebugTools.Assert(gridAtmosphere.ExcitedGroups.Contains(excitedGroup), "Grid Atmosphere does not contain Excited Group!"); + var combined = new GasMixture(Atmospherics.CellVolume); + + var tileSize = excitedGroup.Tiles.Count; + + if (excitedGroup.Disposed) return; + + if (tileSize == 0) + { + ExcitedGroupDispose(gridAtmosphere, excitedGroup); + return; + } + + foreach (var tile in excitedGroup.Tiles) + { + if (tile?.Air == null) + continue; + + Merge(combined, tile.Air); + + if (!spaceIsAllConsuming || !tile.Air.Immutable) + continue; + + combined.Clear(); + break; + } + + combined.Multiply(1 / (float)tileSize); + + foreach (var tile in excitedGroup.Tiles) + { + if (tile?.Air == null) continue; + tile.Air.CopyFromMutable(combined); + InvalidateVisuals(tile.GridIndex, tile.GridIndices); + } + + excitedGroup.BreakdownCooldown = 0; + } + + private void ExcitedGroupDismantle(GridAtmosphereComponent gridAtmosphere, ExcitedGroup excitedGroup, bool unexcite = true) + { + foreach (var tile in excitedGroup.Tiles) + { + tile.ExcitedGroup = null; + + if (!unexcite) + continue; + + RemoveActiveTile(gridAtmosphere, tile); + } + + excitedGroup.Tiles.Clear(); + } + + private void ExcitedGroupDispose(GridAtmosphereComponent gridAtmosphere, ExcitedGroup excitedGroup) + { + if (excitedGroup.Disposed) + return; + + DebugTools.Assert(gridAtmosphere.ExcitedGroups.Contains(excitedGroup), "Grid Atmosphere does not contain Excited Group!"); + + excitedGroup.Disposed = true; + + gridAtmosphere.ExcitedGroups.Remove(excitedGroup); + ExcitedGroupDismantle(gridAtmosphere, excitedGroup, false); + } + } +} diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs index f2422b458b..bcf7989db8 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs @@ -4,12 +4,16 @@ using System.Linq; using Content.Server.Atmos.Reactions; using Content.Server.Interfaces; using Content.Shared.Atmos; +using Robust.Shared.IoC; using Robust.Shared.Maths; +using Robust.Shared.Prototypes; namespace Content.Server.Atmos.EntitySystems { public partial class AtmosphereSystem { + [Dependency] private readonly IPrototypeManager _protoMan = default!; + private GasReactionPrototype[] _gasReactions = Array.Empty(); private float[] _gasSpecificHeats = new float[Atmospherics.TotalNumberOfGases]; @@ -51,16 +55,23 @@ namespace Content.Server.Atmos.EntitySystems return mixture.Temperature * GetHeatCapacity(mixture); } + public float GetThermalEnergy(GasMixture mixture, float cachedHeatCapacity) + { + return mixture.Temperature * cachedHeatCapacity; + } + public void Merge(GasMixture receiver, GasMixture giver) { if (receiver.Immutable) return; if (MathF.Abs(receiver.Temperature - giver.Temperature) > Atmospherics.MinimumTemperatureDeltaToConsider) { - var combinedHeatCapacity = GetHeatCapacity(receiver) + GetHeatCapacity(giver); + var receiverHeatCapacity = GetHeatCapacity(receiver); + var giverHeatCapacity = GetHeatCapacity(giver); + var combinedHeatCapacity = receiverHeatCapacity + giverHeatCapacity; if (combinedHeatCapacity > 0f) { - receiver.Temperature = (GetThermalEnergy(giver) + GetThermalEnergy(receiver)) / combinedHeatCapacity; + receiver.Temperature = (GetThermalEnergy(giver, giverHeatCapacity) + GetThermalEnergy(receiver, receiverHeatCapacity)) / combinedHeatCapacity; } } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Grid.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Grid.cs index b159597378..5806ef1332 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Grid.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Grid.cs @@ -2,93 +2,69 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Runtime.CompilerServices; using Content.Server.Atmos.Components; +using Content.Server.Atmos.Piping.Components; using Content.Server.Atmos.Reactions; +using Content.Server.NodeContainer.NodeGroups; using Content.Shared.Atmos; +using Content.Shared.Maps; +using Robust.Shared.GameObjects; +// ReSharper disable once RedundantUsingDirective +using Robust.Shared.IoC; +using Robust.Shared.Log; using Robust.Shared.Map; using Robust.Shared.Maths; +using Robust.Shared.Utility; +using Dependency = Robust.Shared.IoC.DependencyAttribute; namespace Content.Server.Atmos.EntitySystems { public partial class AtmosphereSystem { - #region Get GridAtmosphere + [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!; - public IGridAtmosphereComponent? GetGridAtmosphere(GridId gridId) + private GasTileOverlaySystem _gasTileOverlaySystem = default!; + + private void InitializeGrid() { - if (!gridId.IsValid()) - return null; + _gasTileOverlaySystem = Get(); - if (!_mapManager.TryGetGrid(gridId, out var grid)) - return null; - - return ComponentManager.TryGetComponent(grid.GridEntityId, out IGridAtmosphereComponent? gridAtmosphere) - ? gridAtmosphere : null; + SubscribeLocalEvent(OnGridAtmosphereInit); } - public IGridAtmosphereComponent GetGridAtmosphere(EntityCoordinates coordinates) + private void OnGridAtmosphereInit(EntityUid uid, GridAtmosphereComponent gridAtmosphere, ComponentInit args) { - return GetGridAtmosphere(coordinates.ToMap(EntityManager)); - } + base.Initialize(); - public IGridAtmosphereComponent GetGridAtmosphere(MapCoordinates coordinates) - { - if (coordinates.MapId == MapId.Nullspace) - { - throw new ArgumentException($"Coordinates cannot be in nullspace!", nameof(coordinates)); - } + gridAtmosphere.Tiles.Clear(); - if (_mapManager.TryFindGridAt(coordinates, out var grid)) + if (!ComponentManager.TryGetComponent(uid, out IMapGridComponent? mapGrid)) + return; + + if (gridAtmosphere.TilesUniqueMixes != null) { - if (ComponentManager.TryGetComponent(grid.GridEntityId, out IGridAtmosphereComponent? atmos)) + foreach (var (indices, mix) in gridAtmosphere.TilesUniqueMixes) { - return atmos; + 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; + } + + InvalidateTile(gridAtmosphere, indices); } } - return _mapManager.GetMapEntity(coordinates.MapId).GetComponent(); + GridRepopulateTiles(mapGrid.Grid, gridAtmosphere); } - /// - /// Unlike GetGridAtmosphere, this doesn't return space grid when not found. - /// - public bool TryGetSimulatedGridAtmosphere(MapCoordinates coordinates, [NotNullWhen(true)] out IGridAtmosphereComponent? atmosphere) - { - if (coordinates.MapId == MapId.Nullspace) - { - atmosphere = null; - return false; - } - - if (_mapManager.TryFindGridAt(coordinates, out var mapGrid) - && ComponentManager.TryGetComponent(mapGrid.GridEntityId, out IGridAtmosphereComponent? atmosGrid) - && atmosGrid.Simulated) - { - atmosphere = atmosGrid; - return true; - } - - atmosphere = null; - return false; - } - - #endregion - #region Grid Is Simulated - /// - /// Returns whether a grid has a simulated atmosphere. - /// - /// Coordinates to be checked. - /// Whether the grid has a simulated atmosphere. - public bool IsSimulatedGrid(MapCoordinates coordinates) - { - if (TryGetGridAndTile(coordinates, out var tuple)) - return IsSimulatedGrid(tuple.Value.Grid); - - return false; - } - /// /// Returns whether a grid has a simulated atmosphere. /// @@ -122,20 +98,6 @@ namespace Content.Server.Atmos.EntitySystems #region Grid Get All Mixtures - /// - /// Gets all tile mixtures within a grid atmosphere, optionally invalidating them all. - /// - /// Coordinates where to get the grid to get all tile mixtures from. - /// Whether to invalidate all tiles. - /// All tile mixtures in a grid. - public IEnumerable GetAllTileMixtures(MapCoordinates coordinates, bool invalidate = false) - { - if (TryGetGridAndTile(coordinates, out var tuple)) - return GetAllTileMixtures(tuple.Value.Grid, invalidate); - - return Enumerable.Empty(); - } - /// /// Gets all tile mixtures within a grid atmosphere, optionally invalidating them all. /// @@ -159,41 +121,272 @@ namespace Content.Server.Atmos.EntitySystems public IEnumerable GetAllTileMixtures(GridId grid, bool invalidate = false) { if (!_mapManager.TryGetGrid(grid, out var mapGrid)) - yield break; + return Enumerable.Empty(); if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) { - foreach (var tile in gridAtmosphere) - { - if (tile?.Air == null) - continue; + return GetAllTileMixtures(gridAtmosphere, invalidate); + } - if(invalidate) - gridAtmosphere.Invalidate(tile.GridIndices); + return Enumerable.Empty(); + } - yield return tile.Air; - } + /// + /// Gets all tile mixtures within a grid atmosphere, optionally invalidating them all. + /// + /// Grid Atmosphere to get all mixtures from. + /// Whether to invalidate all mixtures. + /// All the tile mixtures in a grid. + public IEnumerable 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 Invalidate + #region Grid Cell Volume /// - /// Invalidates a tile at a certain position. + /// Gets the volume in liters for a number of tiles, on a specific grid. /// - /// - public void InvalidateTile(MapCoordinates coordinates) + /// The grid in question. + /// The amount of tiles. + /// The volume in liters that the tiles occupy. + public float GetVolumeForTiles(GridId grid, int tiles = 1) { - if(TryGetGridAndTile(coordinates, out var tuple)) - InvalidateTile(tuple.Value.Grid, tuple.Value.Tile); + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) + return Atmospherics.CellVolume * tiles; + + return GetVolumeForTiles(mapGrid, tiles); + } + /// + /// Gets the volume in liters for a number of tiles, on a specific grid. + /// + /// The grid in question. + /// The amount of tiles. + /// The volume in liters that the tiles occupy. + public float GetVolumeForTiles(IMapGrid mapGrid, int tiles = 1) + { + return Atmospherics.CellVolume * mapGrid.TileSize * tiles; + + } + + #endregion + + #region Grid Get Obstructing + + /// + /// Gets all obstructing AirtightComponent instances in a specific tile. + /// + /// The grid where to get the tile. + /// The indices of the tile. + /// + public virtual IEnumerable GetObstructingComponents(IMapGrid mapGrid, Vector2i tile) + { + foreach (var uid in mapGrid.GetAnchoredEntities(tile)) + { + if (ComponentManager.TryGetComponent(uid, out var ac)) + 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 Revalidate + + /// + /// Revalidates all invalid coordinates in a grid atmosphere. + /// + /// The grid in question. + /// The grid atmosphere in question. + /// Whether the process succeeded or got paused due to time constrains. + private bool GridRevalidate(IMapGrid mapGrid, GridAtmosphereComponent gridAtmosphere) + { + var volume = GetVolumeForTiles(mapGrid, 1); + + if (!gridAtmosphere.RevalidatePaused) + gridAtmosphere.CurrentRunInvalidatedCoordinates = new Queue(gridAtmosphere.InvalidatedCoords); + + gridAtmosphere.InvalidatedCoords.Clear(); + + var number = 0; + while (gridAtmosphere.CurrentRunInvalidatedCoordinates.TryDequeue(out var indices)) + { + var tile = GetTileAtmosphere(gridAtmosphere, indices); + + if (tile == null) + { + tile = new TileAtmosphere(mapGrid.Index, indices, new GasMixture(volume){Temperature = Atmospherics.T20C}); + gridAtmosphere.Tiles[indices] = tile; + } + + var isAirBlocked = IsTileAirBlocked(mapGrid, indices); + + if (IsTileSpace(mapGrid, indices) && !isAirBlocked) + { + tile.Air = new GasMixture(volume); + tile.Air.MarkImmutable(); + gridAtmosphere.Tiles[indices] = tile; + + } else if (isAirBlocked) + { + var nullAir = false; + + foreach (var airtight in GetObstructingComponents(mapGrid, indices)) + { + if (!airtight.NoAirWhenFullyAirBlocked) + continue; + + nullAir = true; + break; + } + + if (nullAir) + { + tile.Air = null; + tile.Hotspot = new Hotspot(); + } + } + else + { + if (tile.Air == null && NeedsVacuumFixing(mapGrid, indices)) + { + FixVacuum(gridAtmosphere, tile.GridIndices); + } + + // Tile used to be space, but isn't anymore. + if (tile.Air?.Immutable ?? false) + { + tile.Air = null; + } + + tile.Air ??= new GasMixture(volume){Temperature = Atmospherics.T20C}; + } + + // By removing the active tile, we effectively remove its excited group, if any. + RemoveActiveTile(gridAtmosphere, tile); + + // Then we activate the tile again. + AddActiveTile(gridAtmosphere, tile); + + tile.BlockedAirflow = GetBlockedDirections(mapGrid, indices); + + // TODO ATMOS: Query all the contents of this tile (like walls) and calculate the correct thermal conductivity + tile.ThermalConductivity = tile.Tile?.Tile.GetContentTileDefinition().ThermalConductivity ?? 0.5f; + UpdateAdjacent(mapGrid, gridAtmosphere, tile); + InvalidateVisuals(mapGrid.Index, indices); + + for (var i = 0; i < Atmospherics.Directions; i++) + { + var direction = (AtmosDirection) (1 << i); + var otherIndices = indices.Offset(direction.ToDirection()); + var otherTile = GetTileAtmosphereOrCreateSpace(mapGrid, gridAtmosphere, otherIndices); + if (otherTile != null) + AddActiveTile(gridAtmosphere, otherTile); + } + + if (number++ < InvalidCoordinatesLagCheckIterations) continue; + number = 0; + // Process the rest next time. + if (_simulationStopwatch.Elapsed.TotalMilliseconds >= AtmosMaxProcessTime) + { + return false; + } + } + + return true; + } + + #endregion + + #region Grid Repopulate + + /// + /// Repopulates all tiles on a grid atmosphere. + /// + /// The grid where to get all valid tiles from. + /// The grid atmosphere where the tiles will be repopulated. + public void GridRepopulateTiles(IMapGrid mapGrid, GridAtmosphereComponent gridAtmosphere) + { + 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); + } + } + + #endregion + + #region Tile Pry + + /// + /// Pries a tile in a grid. + /// + /// The grid in question. + /// The indices of the tile. + public void PryTile(GridId grid, Vector2i tile) + { + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) + return; + + PryTile(mapGrid, tile); + } + + /// + /// Pries a tile in a grid. + /// + /// The grid in question. + /// The indices of the tile. + public void PryTile(IMapGrid mapGrid, Vector2i tile) + { + if (!mapGrid.TryGetTileRef(tile, out var tileRef)) + return; + + tileRef.PryTile(_mapManager, _tileDefinitionManager, EntityManager); + } + + #endregion + + #region Tile Invalidate + /// /// Invalidates a tile at a certain position. /// - /// + /// Coordinates of the tile. public void InvalidateTile(EntityCoordinates coordinates) { if(TryGetGridAndTile(coordinates, out var tuple)) @@ -204,33 +397,156 @@ namespace Content.Server.Atmos.EntitySystems /// Invalidates a tile at a certain position. /// /// Grid where to invalidate the tile. - /// The tile's indices. - public void InvalidateTile(GridId grid, Vector2i position) + /// The indices of the tile. + public void InvalidateTile(GridId grid, Vector2i tile) { if (!_mapManager.TryGetGrid(grid, out var mapGrid)) return; if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) { - gridAtmosphere.Invalidate(position); + InvalidateTile(gridAtmosphere, tile); return; } } + /// + /// Invalidates a tile at a certain position. + /// + /// Grid Atmosphere where to invalidate the tile. + /// The tile's indices. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void InvalidateTile(GridAtmosphereComponent gridAtmosphere, Vector2i tile) + { + gridAtmosphere.InvalidatedCoords.Add(tile); + } + + #endregion + + #region Tile Invalidate Visuals + + public void InvalidateVisuals(EntityCoordinates coordinates) + { + if(TryGetGridAndTile(coordinates, out var tuple)) + InvalidateVisuals(tuple.Value.Grid, tuple.Value.Tile); + } + + public void InvalidateVisuals(GridId grid, Vector2i tile) + { + _gasTileOverlaySystem.Invalidate(grid, tile); + } + + #endregion + + #region Tile Atmosphere Get + + /// + /// Gets the tile atmosphere in a position, or null. + /// + /// Coordinates where to get the tile. + /// Do NOT use this outside of atmos internals. + /// The Tile Atmosphere in the position, or null if not on a grid. + public TileAtmosphere? GetTileAtmosphere(EntityCoordinates coordinates) + { + if (TryGetGridAndTile(coordinates, out var tuple)) + return GetTileAtmosphere(tuple.Value.Grid, tuple.Value.Tile); + + return null; + } + + /// + /// Gets the tile atmosphere in a position, or null. + /// + /// Grid where to get the tile. + /// Indices of the tile. + /// Do NOT use this outside of atmos internals. + /// The Tile Atmosphere in the position, or null. + public TileAtmosphere? GetTileAtmosphere(GridId grid, Vector2i tile) + { + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) + return null; + + if(ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) + { + return GetTileAtmosphere(gridAtmosphere, tile); + } + + return null; + } + + /// + /// Gets the tile atmosphere in a position, or null. + /// + /// Grid atmosphere where to get the tile. + /// Indices of the tile. + /// Do NOT use this outside of atmos internals. + /// The Tile Atmosphere in the position, or null. + public TileAtmosphere? GetTileAtmosphere(GridAtmosphereComponent gridAtmosphere, Vector2i tile) + { + if (gridAtmosphere.Tiles.TryGetValue(tile, out var tileAtmosphere)) + return tileAtmosphere; + + return null; + } + + /// + /// Gets the tile atmosphere in a position and if not possible returns a space tile or null. + /// + /// Coordinates of the tile. + /// Do NOT use this outside of atmos internals. + /// 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. + public TileAtmosphere? GetTileAtmosphereOrCreateSpace(EntityCoordinates coordinates) + { + if (TryGetGridAndTile(coordinates, out var tuple)) + return GetTileAtmosphereOrCreateSpace(tuple.Value.Grid, tuple.Value.Tile); + + return null; + } + + /// + /// Gets the tile atmosphere in a position and if not possible returns a space tile or null. + /// + /// Grid where to get the tile. + /// Indices of the tile. + /// Do NOT use this outside of atmos internals. + /// 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. + public TileAtmosphere? GetTileAtmosphereOrCreateSpace(GridId grid, Vector2i tile) + { + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) + return null; + + if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) + { + return GetTileAtmosphereOrCreateSpace(mapGrid, gridAtmosphere, tile); + } + + return null; + } + + /// + /// Gets the tile atmosphere in a position and if not possible returns a space tile or null. + /// + /// Grid where to get the tile. + /// Grid Atmosphere where to get the tile. + /// Indices of the tile. + /// Do NOT use this outside of atmos internals. + /// The tile atmosphere of a specific position in a grid or a space tile atmosphere if the tile is space. + public TileAtmosphere GetTileAtmosphereOrCreateSpace(IMapGrid mapGrid, GridAtmosphereComponent gridAtmosphere, Vector2i tile) + { + var tileAtmosphere = GetTileAtmosphere(gridAtmosphere, tile); + + if (tileAtmosphere != null) + return tileAtmosphere; + + // That tile must be space, or something has gone horribly wrong! + DebugTools.Assert(IsTileSpace(mapGrid, tile)); + return new TileAtmosphere(mapGrid.Index, tile, new GasMixture(Atmospherics.CellVolume) {Temperature = Atmospherics.TCMB}, true); + } + #endregion #region Tile Active Add - /// - /// Makes a tile become active and start processing. - /// - /// Coordinates where to get the tile. - public void AddActiveTile(MapCoordinates coordinates) - { - if(TryGetGridAndTile(coordinates, out var tuple)) - AddActiveTile(tuple.Value.Grid, tuple.Value.Tile); - } - /// /// Makes a tile become active and start processing. /// @@ -253,12 +569,39 @@ namespace Content.Server.Atmos.EntitySystems if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) { - var tileAtmosphere = gridAtmosphere.GetTile(tile)!; - gridAtmosphere.AddActiveTile(tileAtmosphere); + AddActiveTile(gridAtmosphere, tile); return; } } + /// + /// Makes a tile become active and start processing. + /// + /// Grid Atmosphere where to get the tile. + /// Indices of the tile to be activated. + public void AddActiveTile(GridAtmosphereComponent gridAtmosphere, Vector2i tile) + { + if (!gridAtmosphere.Tiles.TryGetValue(tile, out var tileAtmosphere)) + return; + + AddActiveTile(gridAtmosphere, tileAtmosphere); + } + + /// + /// Makes a tile become active and start processing. Does NOT check if the tile belongs to the grid atmos. + /// + /// Grid Atmosphere where to get the tile. + /// Tile Atmosphere to be activated. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void AddActiveTile(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile) + { + if (tile.Air == null) + return; + + tile.Excited = true; + gridAtmosphere.ActiveTiles.Add(tile); + } + #endregion #region Tile Active Remove @@ -268,18 +611,7 @@ namespace Content.Server.Atmos.EntitySystems /// /// Coordinates where to get the tile. /// Whether to dispose of the tile's - public void RemoveActiveTile(MapCoordinates coordinates, bool disposeExcitedGroup = false) - { - if(TryGetGridAndTile(coordinates, out var tuple)) - RemoveActiveTile(tuple.Value.Grid, tuple.Value.Tile, disposeExcitedGroup); - } - - /// - /// Makes a tile become inactive and stop processing. - /// - /// Coordinates where to get the tile. - /// Whether to dispose of the tile's - public void RemoveActiveTile(EntityCoordinates coordinates, bool disposeExcitedGroup = false) + public void RemoveActiveTile(EntityCoordinates coordinates, bool disposeExcitedGroup = true) { if(TryGetGridAndTile(coordinates, out var tuple)) RemoveActiveTile(tuple.Value.Grid, tuple.Value.Tile, disposeExcitedGroup); @@ -289,37 +621,58 @@ namespace Content.Server.Atmos.EntitySystems /// Makes a tile become inactive and stop processing. /// /// Grid where to get the tile. - /// Indices of the tile to be activated. + /// Indices of the tile to be deactivated. /// Whether to dispose of the tile's - public void RemoveActiveTile(GridId grid, Vector2i tile, bool disposeExcitedGroup = false) + public void RemoveActiveTile(GridId grid, Vector2i tile, bool disposeExcitedGroup = true) { if (!_mapManager.TryGetGrid(grid, out var mapGrid)) return; if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) { - var tileAtmosphere = gridAtmosphere.GetTile(tile)!; - gridAtmosphere.RemoveActiveTile(tileAtmosphere, disposeExcitedGroup); + RemoveActiveTile(gridAtmosphere, tile); return; } } + /// + /// Makes a tile become inactive and stop processing. + /// + /// Grid Atmosphere where to get the tile. + /// Indices of the tile to be deactivated. + /// Whether to dispose of the tile's + public void RemoveActiveTile(GridAtmosphereComponent gridAtmosphere, Vector2i tile, bool disposeExcitedGroup = true) + { + if (!gridAtmosphere.Tiles.TryGetValue(tile, out var tileAtmosphere)) + return; + + RemoveActiveTile(gridAtmosphere, tileAtmosphere, disposeExcitedGroup); + } + + /// + /// Makes a tile become inactive and stop processing. + /// + /// Grid Atmosphere where to get the tile. + /// Tile Atmosphere to be deactivated. + /// Whether to dispose of the tile's + private void RemoveActiveTile(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, bool disposeExcitedGroup = true) + { + tile.Excited = false; + gridAtmosphere.ActiveTiles.Remove(tile); + + if (tile.ExcitedGroup == null) + return; + + if (disposeExcitedGroup) + ExcitedGroupDispose(gridAtmosphere, tile.ExcitedGroup); + else + ExcitedGroupRemoveTile(tile.ExcitedGroup, tile); + } + #endregion #region Tile Mixture - /// - /// Returns a reference to the gas mixture on a tile, or null. - /// - /// Coordinates where to get the tile. - /// Whether to invalidate the tile. - /// The tile mixture, or null - public GasMixture? GetTileMixture(MapCoordinates coordinates, bool invalidate = false) - { - return TryGetGridAndTile(coordinates, out var tuple) - ? GetTileMixture(tuple.Value.Grid, tuple.Value.Tile, invalidate) : null; - } - /// /// Returns a reference to the gas mixture on a tile, or null. /// @@ -336,22 +689,17 @@ namespace Content.Server.Atmos.EntitySystems /// Returns a reference to the gas mixture on a tile, or null. /// /// Grid where to get the tile air. - /// Indices of the tile. + /// Indices of the tile. /// Whether to invalidate the tile. /// The tile mixture, or null - public GasMixture? GetTileMixture(GridId grid, Vector2i position, bool invalidate = false) + public GasMixture? GetTileMixture(GridId grid, Vector2i tile, bool invalidate = false) { if (!_mapManager.TryGetGrid(grid, out var mapGrid)) return null; if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) { - // Invalidate the tile if needed. - if(invalidate) - gridAtmosphere.Invalidate(position); - - // Return actual tile air or null. - return gridAtmosphere.GetTile(position)?.Air; + return GetTileMixture(gridAtmosphere, tile, invalidate); } if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out SpaceGridAtmosphereComponent? spaceAtmosphere)) @@ -363,23 +711,31 @@ namespace Content.Server.Atmos.EntitySystems return null; } + /// + /// Returns a reference to the gas mixture on a tile, or null. + /// + /// Grid Atmosphere where to get the tile air. + /// Indices of the tile. + /// Whether to invalidate the tile. + /// The tile mixture, or null + [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; + } + #endregion #region Tile React - /// - /// Causes a gas mixture reaction on a specific tile. - /// - /// Coordinates where to get the tile. - /// Reaction results. - public ReactionResult React(MapCoordinates coordinates) - { - if (TryGetGridAndTile(coordinates, out var tuple)) - return React(tuple.Value.Grid, tuple.Value.Tile); - - return ReactionResult.NoReaction; - } - /// /// Causes a gas mixture reaction on a specific tile. /// @@ -401,31 +757,36 @@ namespace Content.Server.Atmos.EntitySystems /// Reaction results. public ReactionResult React(GridId grid, Vector2i tile) { - var atmosphere = GetGridAtmosphere(grid); - atmosphere?.Invalidate(tile); + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) + return ReactionResult.NoReaction; - var tileAtmosphere = atmosphere?.GetTile(tile); - return tileAtmosphere?.Air == null ? ReactionResult.NoReaction : React(tileAtmosphere.Air, tileAtmosphere); + if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) + { + return React(gridAtmosphere, tile); + } + + return ReactionResult.NoReaction; + } + + /// + /// Causes a gas mixture reaction on a specific tile. + /// + /// Grid Atmosphere where to get the tile. + /// Indices of the tile. + /// Reaction results. + public ReactionResult React(GridAtmosphereComponent gridAtmosphere, Vector2i tile) + { + if (!gridAtmosphere.Tiles.TryGetValue(tile, out var tileAtmosphere) || tileAtmosphere.Air == null) + return ReactionResult.NoReaction; + + InvalidateTile(gridAtmosphere, tile); + + return React(tileAtmosphere.Air, tileAtmosphere); } #endregion - #region Tile Airblocked - - /// - /// Returns if the tile in question is "air-blocked" in a certain direction or not. - /// This could be due to a number of reasons, such as walls, doors, etc. - /// - /// Coordinates where to get the tile. - /// Directions to check. - /// Whether the tile is blocked in the directions specified. - public bool IsTileAirBlocked(MapCoordinates coordinates, AtmosDirection direction = AtmosDirection.All) - { - if (TryGetGridAndTile(coordinates, out var tuple)) - return IsTileAirBlocked(tuple.Value.Grid, tuple.Value.Tile, direction); - - return false; - } + #region Tile Air-blocked /// /// Returns if the tile in question is "air-blocked" in a certain direction or not. @@ -455,9 +816,32 @@ namespace Content.Server.Atmos.EntitySystems if (!_mapManager.TryGetGrid(grid, out var mapGrid)) return false; - if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) + return IsTileAirBlocked(mapGrid, tile, direction); + } + + /// + /// Returns if the tile in question is "air-blocked" in a certain direction or not. + /// This could be due to a number of reasons, such as walls, doors, etc. + /// + /// Grid where to get the tile. + /// Indices of the tile. + /// Directions to check. + /// Whether the tile is blocked in the directions specified. + public bool IsTileAirBlocked(IMapGrid mapGrid, Vector2i tile, AtmosDirection direction = AtmosDirection.All) + { + var directions = AtmosDirection.Invalid; + + foreach (var obstructingComponent in GetObstructingComponents(mapGrid, tile)) { - return gridAtmosphere.IsAirBlocked(tile, direction); + 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; } return false; @@ -467,19 +851,6 @@ namespace Content.Server.Atmos.EntitySystems #region Tile Space - /// - /// Returns whether the specified tile is a space tile or not. - /// - /// Coordinates where to check the tile. - /// Whether the tile is space or not. - public bool IsTileSpace(MapCoordinates coordinates) - { - if (TryGetGridAndTile(coordinates, out var tuple)) - return IsTileSpace(tuple.Value.Grid, tuple.Value.Tile); - - return true; - } - /// /// Returns whether the specified tile is a space tile or not. /// @@ -501,35 +872,21 @@ namespace Content.Server.Atmos.EntitySystems /// Whether the tile is space or not. public bool IsTileSpace(GridId grid, Vector2i tile) { - if (!_mapManager.TryGetGrid(grid, out var mapGrid)) + return !_mapManager.TryGetGrid(grid, out var mapGrid) || IsTileSpace(mapGrid, tile); + } + + public bool IsTileSpace(IMapGrid mapGrid, Vector2i tile) + { + if (!mapGrid.TryGetTileRef(tile, out var tileRef)) return true; - if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) - { - return gridAtmosphere.IsSpace(tile); - } - - return true; + return ((ContentTileDefinition) _tileDefinitionManager[tileRef.Tile.TypeId]).IsSpace; } #endregion #region Adjacent Get Positions - /// - /// Gets all the positions adjacent to a tile. Can include air-blocked directions. - /// - /// Coordinates where to get the tile. - /// Whether to include tiles in directions the tile is air-blocked in. - /// The positions adjacent to the tile. - public IEnumerable GetAdjacentTiles(MapCoordinates coordinates, bool includeBlocked = false) - { - if (TryGetGridAndTile(coordinates, out var tuple)) - return GetAdjacentTiles(tuple.Value.Grid, tuple.Value.Tile, includeBlocked); - - return Enumerable.Empty(); - } - /// /// Gets all the positions adjacent to a tile. Can include air-blocked directions. /// @@ -554,29 +911,44 @@ namespace Content.Server.Atmos.EntitySystems public IEnumerable GetAdjacentTiles(GridId grid, Vector2i tile, bool includeBlocked = false) { if (!_mapManager.TryGetGrid(grid, out var mapGrid)) - yield break; + return Enumerable.Empty(); if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) { - var tileAtmos = gridAtmosphere.GetTile(tile)!; + return GetAdjacentTiles(gridAtmosphere, tile, includeBlocked); + } - for (var i = 0; i < tileAtmos.AdjacentTiles.Length; i++) + return Enumerable.Empty(); + } + + /// + /// Gets all the positions adjacent to a tile. Can include air-blocked directions. + /// + /// Grid Atmosphere where to get the tiles. + /// Indices of the tile. + /// Whether to include tiles in directions the tile is air-blocked in. + /// The positions adjacent to the tile. + public IEnumerable GetAdjacentTiles(GridAtmosphereComponent gridAtmosphere, Vector2i tile, bool includeBlocked = false) + { + if(!gridAtmosphere.Tiles.TryGetValue(tile, out var tileAtmosphere)) + yield break; + + for (var i = 0; i < tileAtmosphere.AdjacentTiles.Length; i++) + { + var adjacentTile = tileAtmosphere.AdjacentTiles[i]; + // TileAtmosphere has nullable disabled, so just in case... + // ReSharper disable once ConditionIsAlwaysTrueOrFalse + if (adjacentTile?.Air == null) + continue; + + if (!includeBlocked) { - var adjacentTile = tileAtmos.AdjacentTiles[i]; - // TileAtmosphere has nullable disabled, so just in case... - // ReSharper disable once ConditionIsAlwaysTrueOrFalse - if (adjacentTile?.Air == null) + var direction = (AtmosDirection) (1 << i); + if (tileAtmosphere.BlockedAirflow.IsFlagSet(direction)) continue; - - if (!includeBlocked) - { - var direction = (AtmosDirection) (1 << i); - if (tileAtmos.BlockedAirflow.IsFlagSet(direction)) - continue; - } - - yield return adjacentTile.GridIndices; } + + yield return adjacentTile.GridIndices; } } @@ -584,22 +956,6 @@ namespace Content.Server.Atmos.EntitySystems #region Adjacent Get Mixture - /// - /// Gets all tile gas mixtures adjacent to a specific tile, and optionally invalidates them. - /// Does not return the tile in question, only the adjacent ones. Can include air-blocked directions. - /// - /// Coordinates where to get the tile. - /// Whether to include tiles in directions the tile is air-blocked in. - /// Whether to invalidate all adjacent tiles. - /// All adjacent tile gas mixtures to the tile in question - public IEnumerable GetAdjacentTileMixtures(MapCoordinates coordinates, bool includeBlocked = false, bool invalidate = false) - { - if (TryGetGridAndTile(coordinates, out var tuple)) - return GetAdjacentTileMixtures(tuple.Value.Grid, tuple.Value.Tile); - - return Enumerable.Empty(); - } - /// /// Gets all tile gas mixtures adjacent to a specific tile, and optionally invalidates them. /// Does not return the tile in question, only the adjacent ones. @@ -628,33 +984,50 @@ namespace Content.Server.Atmos.EntitySystems public IEnumerable GetAdjacentTileMixtures(GridId grid, Vector2i tile, bool includeBlocked = false, bool invalidate = false) { if (!_mapManager.TryGetGrid(grid, out var mapGrid)) - yield break; + return Enumerable.Empty(); if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) { - var tileAtmos = gridAtmosphere.GetTile(tile)!; + return GetAdjacentTileMixtures(gridAtmosphere, tile, includeBlocked, invalidate); + } - for (var i = 0; i < tileAtmos.AdjacentTiles.Length; i++) + return Enumerable.Empty(); + } + + /// + /// Gets all tile gas mixtures adjacent to a specific tile, and optionally invalidates them. + /// Does not return the tile in question, only the adjacent ones. + /// + /// Grid Atmosphere where to get the tile. + /// Indices of the tile. + /// Whether to include tiles in directions the tile is air-blocked in. + /// Whether to invalidate all adjacent tiles. + /// All adjacent tile gas mixtures to the tile in question + public IEnumerable GetAdjacentTileMixtures(GridAtmosphereComponent gridAtmosphere, Vector2i tile, bool includeBlocked = false, bool invalidate = false) + { + if (!gridAtmosphere.Tiles.TryGetValue(tile, out var tileAtmosphere)) + yield break; + + for (var i = 0; i < tileAtmosphere.AdjacentTiles.Length; i++) + { + var adjacentTile = tileAtmosphere.AdjacentTiles[i]; + + // TileAtmosphere has nullable disabled, so just in case... + // ReSharper disable once ConditionIsAlwaysTrueOrFalse + if (adjacentTile?.Air == null) + continue; + + if (!includeBlocked) { - var adjacentTile = tileAtmos.AdjacentTiles[i]; - - // TileAtmosphere has nullable disabled, so just in case... - // ReSharper disable once ConditionIsAlwaysTrueOrFalse - if (adjacentTile?.Air == null) + var direction = (AtmosDirection) (1 << i); + if (tileAtmosphere.BlockedAirflow.IsFlagSet(direction)) continue; - - if (!includeBlocked) - { - var direction = (AtmosDirection) (1 << i); - if (tileAtmos.BlockedAirflow.IsFlagSet(direction)) - continue; - } - - if (invalidate) - gridAtmosphere.Invalidate(adjacentTile.GridIndices); - - yield return adjacentTile.Air; } + + if (invalidate) + InvalidateTile(gridAtmosphere, adjacentTile.GridIndices); + + yield return adjacentTile.Air; } } @@ -662,16 +1035,6 @@ namespace Content.Server.Atmos.EntitySystems #region Adjacent Update - /// - /// Immediately updates a tile's blocked air directions. - /// - /// Coordinates where to get the tile. - public void UpdateAdjacent(MapCoordinates coordinates) - { - if(TryGetGridAndTile(coordinates, out var tuple)) - UpdateAdjacent(tuple.Value.Grid, tuple.Value.Tile); - } - /// /// Immediately updates a tile's blocked air directions. /// @@ -694,29 +1057,123 @@ namespace Content.Server.Atmos.EntitySystems if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) { - gridAtmosphere.UpdateAdjacentBits(tile); + UpdateAdjacent(mapGrid, gridAtmosphere, tile); return; } } + /// + /// Immediately updates a tile's blocked air directions. + /// + /// Grid where to get the tile. + /// Grid Atmosphere where to get the tile. + /// Indices of the tile. + public void UpdateAdjacent(IMapGrid mapGrid, GridAtmosphereComponent gridAtmosphere, Vector2i tile) + { + if (!gridAtmosphere.Tiles.TryGetValue(tile, out var tileAtmosphere)) + return; + + UpdateAdjacent(mapGrid, gridAtmosphere, tileAtmosphere); + } + + /// + /// Immediately updates a tile's blocked air directions. + /// + /// Grid where to get the tile. + /// Grid Atmosphere of the tile. + /// Tile Atmosphere to be updated. + private void UpdateAdjacent(IMapGrid mapGrid, GridAtmosphereComponent gridAtmosphere, TileAtmosphere tileAtmosphere) + { + tileAtmosphere.AdjacentBits = AtmosDirection.Invalid; + + for (var i = 0; i < Atmospherics.Directions; i++) + { + var direction = (AtmosDirection) (1 << i); + + var otherIndices = tileAtmosphere.GridIndices.Offset(direction.ToDirection()); + + 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; + } + } + } + + /// + /// Immediately updates a tile's single blocked air direction. + /// + /// Coordinates where to get the tile. + /// Direction to be updated. + public void UpdateAdjacent(EntityCoordinates coordinates, AtmosDirection direction) + { + if(TryGetGridAndTile(coordinates, out var tuple)) + UpdateAdjacent(tuple.Value.Grid, tuple.Value.Tile, direction); + } + + /// + /// Immediately updates a tile's single blocked air direction. + /// + /// Grid where to get the tile. + /// Indices of the tile. + /// Direction to be updated. + public void UpdateAdjacent(GridId grid, Vector2i tile, AtmosDirection direction) + { + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) + return; + + if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) + { + UpdateAdjacent(mapGrid, gridAtmosphere, tile, direction); + return; + } + } + + /// + /// Immediately updates a tile's single blocked air direction. + /// + /// Grid where to get the tile. + /// Grid Atmosphere where to get the tile. + /// Indices of the tile. + /// Direction to be updated. + public void UpdateAdjacent(IMapGrid mapGrid, GridAtmosphereComponent gridAtmosphere, Vector2i tile, AtmosDirection direction) + { + if (!gridAtmosphere.Tiles.TryGetValue(tile, out var tileAtmosphere)) + return; + + UpdateAdjacent(mapGrid, gridAtmosphere, tileAtmosphere, direction); + } + + /// + /// Immediately updates a tile's single blocked air direction. + /// + /// Grid where to get the tile. + /// Grid where to get the tile. + /// Tile Atmosphere to be updated. + /// Direction to be updated. + private void UpdateAdjacent(IMapGrid mapGrid, GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, AtmosDirection direction) + { + tile.AdjacentTiles[direction.ToIndex()] = GetTileAtmosphereOrCreateSpace(mapGrid, gridAtmosphere, tile.GridIndices.Offset(direction.ToDirection())); + + if (!tile.BlockedAirflow.IsFlagSet(direction) && !IsTileAirBlocked(mapGrid, tile.GridIndices.Offset(direction.ToDirection()), direction.GetOpposite())) + { + tile.AdjacentBits |= direction; + } + else + { + tile.AdjacentBits &= ~direction; + } + } + #endregion #region Hotspot Expose - /// - /// Exposes temperature to a tile, creating a hotspot (fire) if the conditions are ideal. - /// Can also be used to make an existing hotspot hotter/bigger. Also invalidates the tile. - /// - /// Coordinates where to get the tile. - /// Temperature to expose to the tile. - /// Volume of the exposed temperature. - /// If true, the existing hotspot values will be set to the exposed values, but only if they're smaller. - public void HotspotExpose(MapCoordinates coordinates, float exposedTemperature, float exposedVolume, bool soh = false) - { - if(TryGetGridAndTile(coordinates, out var tuple)) - HotspotExpose(tuple.Value.Grid, tuple.Value.Tile, exposedTemperature, exposedVolume, soh); - } - /// /// Exposes temperature to a tile, creating a hotspot (fire) if the conditions are ideal. /// Can also be used to make an existing hotspot hotter/bigger. Also invalidates the tile. @@ -747,13 +1204,13 @@ namespace Content.Server.Atmos.EntitySystems if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) { - var tileAtmosphere = gridAtmosphere.GetTile(tile, false); + var tileAtmosphere = GetTileAtmosphere(gridAtmosphere, tile); if (tileAtmosphere == null) return; HotspotExpose(gridAtmosphere, tileAtmosphere, exposedTemperature, exposedVolume, soh); - gridAtmosphere.Invalidate(tile); + InvalidateTile(gridAtmosphere, tile); return; } } @@ -762,16 +1219,6 @@ namespace Content.Server.Atmos.EntitySystems #region Hotspot Extinguish - /// - /// Extinguishes a hotspot (fire) on a certain tile, if any. Also invalidates the tile. - /// - /// Coordinates where to get the tile. - public void HotspotExtinguish(MapCoordinates coordinates) - { - if(TryGetGridAndTile(coordinates, out var tuple)) - HotspotExtinguish(tuple.Value.Grid, tuple.Value.Tile); - } - /// /// Extinguishes a hotspot (fire) on a certain tile, if any. Also invalidates the tile. /// @@ -794,35 +1241,29 @@ namespace Content.Server.Atmos.EntitySystems if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) { - var tileAtmos = gridAtmosphere.GetTile(tile); - - if (tileAtmos != null) - { - tileAtmos.Hotspot = new Hotspot(); - gridAtmosphere.Invalidate(tile); - } - + HotspotExtinguish(gridAtmosphere, tile); return; } } + /// + /// Extinguishes a hotspot (fire) on a certain tile, if any. Also invalidates the tile. + /// + /// Grid Atmosphere where to get the tile. + /// Indices of the tile. + public void HotspotExtinguish(GridAtmosphereComponent gridAtmosphere, Vector2i tile) + { + if (!gridAtmosphere.Tiles.TryGetValue(tile, out var tileAtmosphere)) + return; + + tileAtmosphere.Hotspot = new Hotspot(); + InvalidateTile(gridAtmosphere, tile); + } + #endregion #region Hotspot Active - /// - /// Returns whether there's an active hotspot (fire) on a certain tile. - /// - /// Position where to get the tile. - /// Whether the hotspot is active or not. - public bool IsHotspotActive(MapCoordinates coordinates) - { - if (TryGetGridAndTile(coordinates, out var tuple)) - return IsHotspotActive(tuple.Value.Grid, tuple.Value.Tile); - - return false; - } - /// /// Returns whether there's an active hotspot (fire) on a certain tile. /// @@ -849,7 +1290,97 @@ namespace Content.Server.Atmos.EntitySystems if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) { - return gridAtmosphere.GetTile(tile, false)?.Hotspot.Valid ?? false; + return IsHotspotActive(gridAtmosphere, tile); + } + + return false; + } + + /// + /// Returns whether there's an active hotspot (fire) on a certain tile. + /// + /// Grid Atmosphere where to get the tile + /// Indices for the tile + /// Whether the hotspot is active or not. + 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; + + if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) + { + gridAtmosphere.PipeNets.Add(pipeNet); + } + } + + #endregion + + #region PipeNet Remove + + public void RemovePipeNet(PipeNet pipeNet) + { + if (!_mapManager.TryGetGrid(pipeNet.Grid, out var mapGrid)) + return; + + if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) + { + gridAtmosphere.PipeNets.Remove(pipeNet); + } + } + + #endregion + + #region AtmosDevice Add + + public bool AddAtmosDevice(AtmosDeviceComponent atmosDevice) + { + var grid = atmosDevice.Owner.Transform.GridID; + + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) + return false; + + if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) + { + atmosDevice.JoinedGrid = grid; + gridAtmosphere.AtmosDevices.Add(atmosDevice); + return true; + } + + return false; + } + + #endregion + + #region AtmosDevice Remove + + public bool RemoveAtmosDevice(AtmosDeviceComponent atmosDevice) + { + if (atmosDevice.JoinedGrid == null) + return false; + + var grid = atmosDevice.JoinedGrid.Value; + + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) + return false; + + if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere) + && gridAtmosphere.AtmosDevices.Contains(atmosDevice)) + { + atmosDevice.JoinedGrid = null; + gridAtmosphere.AtmosDevices.Remove(atmosDevice); + return true; } return false; @@ -859,17 +1390,6 @@ namespace Content.Server.Atmos.EntitySystems #region Mixture Safety - /// - /// Checks whether a tile's gas mixture is probably safe. - /// This only checks temperature and pressure, not gas composition. - /// - /// Coordinates where to get the tile. - /// Whether the tile's gas mixture is probably safe. - public bool IsTileMixtureProbablySafe(MapCoordinates coordinates) - { - return IsMixtureProbablySafe(GetTileMixture(coordinates)); - } - /// /// Checks whether a tile's gas mixture is probably safe. /// This only checks temperature and pressure, not gas composition. @@ -926,16 +1446,6 @@ namespace Content.Server.Atmos.EntitySystems #region Fix Vacuum - /// - /// Attempts to fix a sudden vacuum by creating gas based on adjacent tiles. - /// - /// Coordinates where to get the tile. - public void FixVacuum(MapCoordinates coordinates) - { - if(TryGetGridAndTile(coordinates, out var tuple)) - FixVacuum(tuple.Value.Grid, tuple.Value.Tile); - } - /// /// Attempts to fix a sudden vacuum by creating gas based on adjacent tiles. /// @@ -958,12 +1468,57 @@ namespace Content.Server.Atmos.EntitySystems if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)) { - gridAtmosphere.FixVacuum(tile); - + FixVacuum(gridAtmosphere, tile); return; } } + public void FixVacuum(GridAtmosphereComponent gridAtmosphere, Vector2i tile) + { + if (!gridAtmosphere.Tiles.TryGetValue(tile, out var tileAtmosphere)) + return; + + var adjacent = GetAdjacentTileMixtures(gridAtmosphere, tile, invalidate:true).ToArray(); + tileAtmosphere.Air = new GasMixture(GetVolumeForTiles(tileAtmosphere.GridIndex, 1)) + {Temperature = Atmospherics.T20C}; + + // Return early, let's not cause any funny NaNs. + if (adjacent.Length == 0) + return; + + 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); + } + + // 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; + } + #endregion #region Position Helpers @@ -1000,6 +1555,18 @@ namespace Content.Server.Atmos.EntitySystems return true; } + public bool TryGetMapGrid(GridAtmosphereComponent gridAtmosphere, [NotNullWhen(true)] out IMapGrid? mapGrid) + { + if (gridAtmosphere.Owner.TryGetComponent(out IMapGridComponent? mapGridComponent)) + { + mapGrid = mapGridComponent.Grid; + return true; + } + + mapGrid = null; + return false; + } + #endregion } } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs index b4d0da13c1..badd27b9cc 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs @@ -58,7 +58,7 @@ namespace Content.Server.Atmos.EntitySystems private void ConsiderPressureDifference(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, TileAtmosphere other, float difference) { - gridAtmosphere.AddHighPressureDelta(tile); + gridAtmosphere.HighPressureDelta.Add(tile); if (difference > tile.PressureDifference) { tile.PressureDifference = difference; diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs index 1b0690d579..208c9c2ada 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs @@ -4,8 +4,8 @@ using Content.Server.Atmos.Components; using Content.Server.Atmos.Reactions; using Content.Server.Coordinates.Helpers; using Content.Shared.Atmos; -using Content.Shared.GameTicking; using Content.Shared.Maps; +using Robust.Shared.Map; namespace Content.Server.Atmos.EntitySystems { @@ -15,13 +15,13 @@ namespace Content.Server.Atmos.EntitySystems { if (!tile.Hotspot.Valid) { - gridAtmosphere.RemoveHotspotTile(tile); + gridAtmosphere.HotspotTiles.Remove(tile); return; } if (!tile.Excited) { - gridAtmosphere.AddActiveTile(tile); + AddActiveTile(gridAtmosphere, tile); } if (!tile.Hotspot.SkippedFirstProcess) @@ -30,13 +30,14 @@ namespace Content.Server.Atmos.EntitySystems return; } - tile.ExcitedGroup?.ResetCooldowns(); + if(tile.ExcitedGroup != null) + ExcitedGroupResetCooldowns(tile.ExcitedGroup); if ((tile.Hotspot.Temperature < Atmospherics.FireMinimumTemperatureToExist) || (tile.Hotspot.Volume <= 1f) || tile.Air == null || tile.Air.GetMoles(Gas.Oxygen) < 0.5f || (tile.Air.GetMoles(Gas.Plasma) < 0.5f && tile.Air.GetMoles(Gas.Tritium) < 0.5f)) { tile.Hotspot = new Hotspot(); - tile.UpdateVisuals(); + InvalidateVisuals(tile.GridIndex, tile.GridIndices); return; } @@ -45,13 +46,17 @@ namespace Content.Server.Atmos.EntitySystems if (tile.Hotspot.Bypassing) { tile.Hotspot.State = 3; - gridAtmosphere.BurnTile(tile.GridIndices); + // TODO ATMOS: Burn tile here if (tile.Air.Temperature > Atmospherics.FireMinimumTemperatureToSpread) { var radiatedTemperature = tile.Air.Temperature * Atmospherics.FireSpreadRadiosityScale; foreach (var otherTile in tile.AdjacentTiles) { + // TODO ATMOS: This is sus. Suss this out. + if (otherTile == null) + continue; + if(!otherTile.Hotspot.Valid) HotspotExpose(gridAtmosphere, otherTile, radiatedTemperature, Atmospherics.CellVolume/4); } @@ -108,8 +113,8 @@ namespace Content.Server.Atmos.EntitySystems tile.Hotspot.Start(); - gridAtmosphere.AddActiveTile(tile); - gridAtmosphere.AddHotspotTile(tile); + AddActiveTile(gridAtmosphere, tile); + gridAtmosphere.HotspotTiles.Add(tile); } } @@ -128,11 +133,11 @@ namespace Content.Server.Atmos.EntitySystems { var affected = tile.Air.RemoveRatio(tile.Hotspot.Volume / tile.Air.Volume); affected.Temperature = tile.Hotspot.Temperature; - gridAtmosphere.AtmosphereSystem.React(affected, tile); + React(affected, tile); tile.Hotspot.Temperature = affected.Temperature; tile.Hotspot.Volume = affected.ReactionResults[GasReaction.Fire] * Atmospherics.FireGrowthRate; Merge(tile.Air, affected); - gridAtmosphere.Invalidate(tile.GridIndices); + gridAtmosphere.InvalidatedCoords.Add(tile.GridIndices); } var tileRef = tile.GridIndices.GetTileRef(tile.GridIndex); diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs index a6c7a2ef38..608d1d3c94 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs @@ -12,7 +12,7 @@ namespace Content.Server.Atmos.EntitySystems // Can't process a tile without air if (tile.Air == null) { - gridAtmosphere.RemoveActiveTile(tile); + RemoveActiveTile(gridAtmosphere, tile); return; } @@ -46,7 +46,7 @@ namespace Content.Server.Atmos.EntitySystems { if (tile.ExcitedGroup != enemyTile.ExcitedGroup) { - tile.ExcitedGroup.MergeGroups(enemyTile.ExcitedGroup); + ExcitedGroupMerge(gridAtmosphere, tile.ExcitedGroup, enemyTile.ExcitedGroup); } shouldShareAir = true; @@ -54,7 +54,7 @@ namespace Content.Server.Atmos.EntitySystems { if (!enemyTile.Excited) { - gridAtmosphere.AddActiveTile(enemyTile); + AddActiveTile(gridAtmosphere, enemyTile); } var excitedGroup = tile.ExcitedGroup; @@ -63,14 +63,14 @@ namespace Content.Server.Atmos.EntitySystems if (excitedGroup == null) { excitedGroup = new ExcitedGroup(); - excitedGroup.Initialize(gridAtmosphere); + gridAtmosphere.ExcitedGroups.Add(excitedGroup); } if (tile.ExcitedGroup == null) - excitedGroup.AddTile(tile); + ExcitedGroupAddTile(excitedGroup, tile); if(enemyTile.ExcitedGroup == null) - excitedGroup.AddTile(enemyTile); + ExcitedGroupAddTile(excitedGroup, enemyTile); shouldShareAir = true; } @@ -97,7 +97,8 @@ namespace Content.Server.Atmos.EntitySystems if(tile.Air != null) React(tile.Air, tile); - tile.UpdateVisuals(); + + InvalidateVisuals(tile.GridIndex, tile.GridIndices); var remove = true; @@ -106,7 +107,7 @@ namespace Content.Server.Atmos.EntitySystems remove = false; if(tile.ExcitedGroup == null && remove) - gridAtmosphere.RemoveActiveTile(tile); + RemoveActiveTile(gridAtmosphere, tile); } private void Archive(TileAtmosphere tile, int fireCount) @@ -124,7 +125,7 @@ namespace Content.Server.Atmos.EntitySystems switch (tile.Air.LastShare) { case > Atmospherics.MinimumAirToSuspend: - tile.ExcitedGroup.ResetCooldowns(); + ExcitedGroupResetCooldowns(tile.ExcitedGroup); break; case > Atmospherics.MinimumMolesDeltaToMove: tile.ExcitedGroup.DismantleCooldown = 0; diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs index e3517e05b4..887cb95b41 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs @@ -7,6 +7,7 @@ using Content.Server.Atmos.Components; using Content.Server.Coordinates.Helpers; using Content.Shared.Atmos; using Robust.Shared.IoC; +using Robust.Shared.Map; using Robust.Shared.Maths; using Robust.Shared.Random; @@ -18,7 +19,7 @@ namespace Content.Server.Atmos.EntitySystems private readonly TileAtmosphereComparer _monstermosComparer = new(); - public void EqualizePressureInZone(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, int cycleNum) + public void EqualizePressureInZone(IMapGrid mapGrid, GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, int cycleNum) { if (tile.Air == null || (tile.MonstermosInfo.LastCycle >= cycleNum)) return; // Already done. @@ -80,7 +81,8 @@ namespace Content.Server.Atmos.EntitySystems if (adj.Air.Immutable) { // Looks like someone opened an airlock to space! - ExplosivelyDepressurize(gridAtmosphere, tile, cycleNum); + + ExplosivelyDepressurize(mapGrid, gridAtmosphere, tile, cycleNum); return; } } @@ -339,7 +341,7 @@ namespace Content.Server.Atmos.EntitySystems if (!otherTile.AdjacentBits.IsFlagSet(direction)) continue; var otherTile2 = otherTile.AdjacentTiles[j]; if (otherTile2?.Air?.Compare(tile.Air) == GasMixture.GasCompareResult.NoExchange) continue; - gridAtmosphere.AddActiveTile(otherTile2); + AddActiveTile(gridAtmosphere, otherTile2); break; } } @@ -349,7 +351,7 @@ namespace Content.Server.Atmos.EntitySystems ArrayPool.Shared.Return(takerTiles); } - public void ExplosivelyDepressurize(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, int cycleNum) + public void ExplosivelyDepressurize(IMapGrid mapGrid, GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, int cycleNum) { // Check if explosive depressurization is enabled and if the tile is valid. if (!MonstermosDepressurization || tile.Air == null) @@ -389,7 +391,7 @@ namespace Content.Server.Atmos.EntitySystems if (otherTile2.Air == null) continue; if (otherTile2.MonstermosInfo.LastQueueCycle == queueCycle) continue; - ConsiderFirelocks(otherTile, otherTile2); + ConsiderFirelocks(gridAtmosphere, otherTile, otherTile2); // The firelocks might have closed on us. if (!otherTile.AdjacentBits.IsFlagSet(direction)) continue; @@ -438,8 +440,8 @@ namespace Content.Server.Atmos.EntitySystems { var otherTile = progressionOrder[i]; if (otherTile.MonstermosInfo.CurrentTransferDirection == AtmosDirection.Invalid) continue; - gridAtmosphere.AddHighPressureDelta(otherTile); - gridAtmosphere.AddActiveTile(otherTile); + gridAtmosphere.HighPressureDelta.Add(otherTile); + AddActiveTile(gridAtmosphere, otherTile); var otherTile2 = otherTile.AdjacentTiles[otherTile.MonstermosInfo.CurrentTransferDirection.ToIndex()]; if (otherTile2?.Air == null) continue; var sum = otherTile2.Air.TotalMoles; @@ -455,9 +457,9 @@ namespace Content.Server.Atmos.EntitySystems otherTile2.PressureDirection = otherTile.MonstermosInfo.CurrentTransferDirection; } - otherTile.Air.Clear(); - otherTile.UpdateVisuals(); - HandleDecompressionFloorRip(gridAtmosphere, otherTile, sum); + otherTile.Air?.Clear(); + InvalidateVisuals(otherTile.GridIndex, otherTile.GridIndices); + HandleDecompressionFloorRip(mapGrid, otherTile, sum); } ArrayPool.Shared.Return(tiles); @@ -465,7 +467,7 @@ namespace Content.Server.Atmos.EntitySystems ArrayPool.Shared.Return(progressionOrder); } - private void ConsiderFirelocks(TileAtmosphere tile, TileAtmosphere other) + private void ConsiderFirelocks(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, TileAtmosphere other) { if (!_mapManager.TryGetGrid(tile.GridIndex, out var mapGrid)) return; @@ -491,8 +493,10 @@ namespace Content.Server.Atmos.EntitySystems if (!reconsiderAdjacent) return; - tile.UpdateAdjacent(); - other.UpdateAdjacent(); + UpdateAdjacent(mapGrid, gridAtmosphere, tile); + UpdateAdjacent(mapGrid, gridAtmosphere, other); + InvalidateVisuals(tile.GridIndex, tile.GridIndices); + InvalidateVisuals(other.GridIndex, other.GridIndices); } public void FinalizeEq(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile) @@ -524,8 +528,8 @@ namespace Content.Server.Atmos.EntitySystems otherTile.MonstermosInfo[direction.GetOpposite()] = 0; Merge(otherTile.Air, tile.Air.Remove(amount)); - tile.UpdateVisuals(); - otherTile.UpdateVisuals(); + InvalidateVisuals(tile.GridIndex, tile.GridIndices); + InvalidateVisuals(otherTile.GridIndex, otherTile.GridIndices); ConsiderPressureDifference(gridAtmosphere, tile, otherTile, amount); } } @@ -548,12 +552,12 @@ namespace Content.Server.Atmos.EntitySystems tile.AdjacentTiles[direction.ToIndex()].MonstermosInfo[direction.GetOpposite()] -= amount; } - private void HandleDecompressionFloorRip(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, float sum) + private void HandleDecompressionFloorRip(IMapGrid mapGrid, TileAtmosphere tile, float sum) { var chance = MathHelper.Clamp(sum / 500, 0.005f, 0.5f); if (sum > 20 && _robustRandom.Prob(chance)) - gridAtmosphere.PryTile(tile.GridIndices); + PryTile(mapGrid, tile.GridIndices); } private class TileAtmosphereComparer : IComparer diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs index 53a3a49e39..2580f4b223 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using Content.Server.Atmos.Components; using Content.Server.Atmos.Piping.Components; @@ -20,6 +21,11 @@ namespace Content.Server.Atmos.EntitySystems /// private const int LagCheckIterations = 30; + /// + /// Check current execution time every n instances processed. + /// + private const int InvalidCoordinatesLagCheckIterations = 50; + private int _currentRunAtmosphereIndex = 0; private bool _simulationPaused = false; @@ -30,10 +36,13 @@ namespace Content.Server.Atmos.EntitySystems if(!atmosphere.ProcessingPaused) atmosphere.CurrentRunTiles = new Queue(atmosphere.ActiveTiles); + if (!TryGetMapGrid(atmosphere, out var mapGrid)) + throw new Exception("Tried to process a grid atmosphere on an entity that isn't a grid!"); + var number = 0; while (atmosphere.CurrentRunTiles.TryDequeue(out var tile)) { - EqualizePressureInZone(atmosphere, tile, atmosphere.UpdateCounter); + EqualizePressureInZone(mapGrid, atmosphere, tile, atmosphere.UpdateCounter); if (number++ < LagCheckIterations) continue; number = 0; @@ -69,22 +78,22 @@ namespace Content.Server.Atmos.EntitySystems return true; } - private bool ProcessExcitedGroups(GridAtmosphereComponent atmosphere) + private bool ProcessExcitedGroups(GridAtmosphereComponent gridAtmosphere) { - if(!atmosphere.ProcessingPaused) - atmosphere.CurrentRunExcitedGroups = new Queue(atmosphere.ExcitedGroups); + if(!gridAtmosphere.ProcessingPaused) + gridAtmosphere.CurrentRunExcitedGroups = new Queue(gridAtmosphere.ExcitedGroups); var number = 0; - while (atmosphere.CurrentRunExcitedGroups.TryDequeue(out var excitedGroup)) + while (gridAtmosphere.CurrentRunExcitedGroups.TryDequeue(out var excitedGroup)) { excitedGroup.BreakdownCooldown++; excitedGroup.DismantleCooldown++; if(excitedGroup.BreakdownCooldown > Atmospherics.ExcitedGroupBreakdownCycles) - excitedGroup.SelfBreakdown(this, ExcitedGroupsSpaceIsAllConsuming); + ExcitedGroupSelfBreakdown(gridAtmosphere, excitedGroup, ExcitedGroupsSpaceIsAllConsuming); else if(excitedGroup.DismantleCooldown > Atmospherics.ExcitedGroupsDismantleCycles) - excitedGroup.Dismantle(); + ExcitedGroupDismantle(gridAtmosphere, excitedGroup); if (number++ < LagCheckIterations) continue; number = 0; @@ -195,7 +204,7 @@ namespace Content.Server.Atmos.EntitySystems atmosphere.CurrentRunAtmosDevices = new Queue(atmosphere.AtmosDevices); var time = _gameTiming.CurTime; - var updateEvent = new AtmosDeviceUpdateEvent(atmosphere); + var updateEvent = new AtmosDeviceUpdateEvent(); var number = 0; while (atmosphere.CurrentRunAtmosDevices.TryDequeue(out var device)) { @@ -237,8 +246,14 @@ namespace Content.Server.Atmos.EntitySystems atmosphere.Timer += frameTime; - if (atmosphere.InvalidatedCoords.Count != 0) - atmosphere.Revalidate(); + if ((atmosphere.InvalidatedCoords.Count != 0 || atmosphere.RevalidatePaused) && TryGetMapGrid(atmosphere, out var mapGrid)) + if (!GridRevalidate(mapGrid, atmosphere)) + { + atmosphere.RevalidatePaused = true; + return; + } + + atmosphere.RevalidatePaused = false; if (atmosphere.Timer < AtmosTime) continue; diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs index c9f93505c7..2853a6934e 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs @@ -48,21 +48,24 @@ namespace Content.Server.Atmos.EntitySystems public bool ConsiderSuperconductivity(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile) { - if (tile.ThermalConductivity == 0f) + if (tile.ThermalConductivity == 0f || !Superconduction) return false; - gridAtmosphere.AddSuperconductivityTile(tile); + gridAtmosphere.SuperconductivityTiles.Add(tile); return true; } public bool ConsiderSuperconductivity(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, bool starting) { + if (!Superconduction) + return false; + if (tile.Air == null || tile.Air.Temperature < (starting ? Atmospherics.MinimumTemperatureStartSuperConduction : Atmospherics.MinimumTemperatureForSuperconduction)) return false; - return !(gridAtmosphere.AtmosphereSystem.GetHeatCapacity(tile.Air) < Atmospherics.MCellWithRatio) + return !(GetHeatCapacity(tile.Air) < Atmospherics.MCellWithRatio) && ConsiderSuperconductivity(gridAtmosphere, tile); } @@ -82,7 +85,7 @@ namespace Content.Server.Atmos.EntitySystems // Make sure it's still hot enough to continue conducting. if (temperature < Atmospherics.MinimumTemperatureForSuperconduction) { - gridAtmosphere.RemoveSuperconductivityTile(tile); + gridAtmosphere.SuperconductivityTiles.Remove(tile); } } @@ -112,7 +115,7 @@ namespace Content.Server.Atmos.EntitySystems TemperatureShareOpenToSolid(tile, other); } - gridAtmosphere.AddActiveTile(tile); + AddActiveTile(gridAtmosphere, tile); } private void TemperatureShareOpenToSolid(TileAtmosphere tile, TileAtmosphere other) diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs index 4d6163868a..910ae05a51 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs @@ -3,19 +3,15 @@ using Content.Server.NodeContainer.EntitySystems; using Content.Shared.Atmos.EntitySystems; using Content.Shared.Maps; using JetBrains.Annotations; -using Robust.Shared.Configuration; using Robust.Shared.IoC; using Robust.Shared.Map; -using Robust.Shared.Prototypes; namespace Content.Server.Atmos.EntitySystems { [UsedImplicitly] public partial class AtmosphereSystem : SharedAtmosphereSystem { - [Dependency] private readonly IPrototypeManager _protoMan = default!; [Dependency] private readonly IMapManager _mapManager = default!; - [Dependency] private readonly IConfigurationManager _cfg = default!; private const float ExposedUpdateDelay = 1f; private float _exposedTimer = 0f; @@ -28,6 +24,7 @@ namespace Content.Server.Atmos.EntitySystems InitializeGases(); InitializeCVars(); + InitializeGrid(); #region Events @@ -57,7 +54,7 @@ namespace Content.Server.Atmos.EntitySystems return; } - GetGridAtmosphere(eventArgs.NewTile.GridIndex)?.Invalidate(eventArgs.NewTile.GridIndices); + InvalidateTile(eventArgs.NewTile.GridIndex, eventArgs.NewTile.GridIndices); } private void OnMapCreated(object? sender, MapEventArgs e) @@ -84,8 +81,7 @@ namespace Content.Server.Atmos.EntitySystems foreach (var exposed in EntityManager.ComponentManager.EntityQuery()) { // TODO ATMOS: Kill this with fire. - var atmos = GetGridAtmosphere(exposed.Owner.Transform.Coordinates); - var tile = atmos.GetTile(exposed.Owner.Transform.Coordinates); + var tile = GetTileAtmosphereOrCreateSpace(exposed.Owner.Transform.Coordinates); if (tile == null) continue; exposed.Update(tile, _exposedTimer, this); } diff --git a/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs b/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs index 6c96d10e88..3a24573cc3 100644 --- a/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs +++ b/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs @@ -144,14 +144,14 @@ namespace Content.Server.Atmos.EntitySystems /// /// Checks whether the overlay-relevant data for a gas tile has been updated. /// - /// + /// /// /// /// /// true if updated - private bool TryRefreshTile(GridAtmosphereComponent gam, GasOverlayData oldTile, Vector2i indices, out GasOverlayData overlayData) + private bool TryRefreshTile(GridId grid, GasOverlayData oldTile, Vector2i indices, out GasOverlayData overlayData) { - var tile = gam.GetTile(indices); + var tile = _atmosphereSystem.GetTileAtmosphereOrCreateSpace(grid, indices); if (tile == null) { @@ -287,7 +287,7 @@ namespace Content.Server.Atmos.EntitySystems { var chunk = GetOrCreateChunk(gridId, invalid); - if (!TryRefreshTile(gam, chunk.GetData(invalid), invalid, out var data)) continue; + if (!TryRefreshTile(grid.Index, chunk.GetData(invalid), invalid, out var data)) continue; if (!updatedTiles.TryGetValue(chunk, out var tiles)) { diff --git a/Content.Server/Atmos/ExcitedGroup.cs b/Content.Server/Atmos/ExcitedGroup.cs index 76831b4d69..adb7c28465 100644 --- a/Content.Server/Atmos/ExcitedGroup.cs +++ b/Content.Server/Atmos/ExcitedGroup.cs @@ -1,146 +1,16 @@ -using System; -using System.Collections.Generic; -using Content.Server.Atmos.Components; -using Content.Server.Atmos.EntitySystems; -using Content.Shared.Atmos; +using System.Collections.Generic; using Robust.Shared.ViewVariables; namespace Content.Server.Atmos { - public class ExcitedGroup : IDisposable + public class ExcitedGroup { - [ViewVariables] - private bool _disposed = false; + [ViewVariables] public bool Disposed = false; - [ViewVariables] - private readonly HashSet _tiles = new(); + [ViewVariables] public readonly List Tiles = new(100); - [ViewVariables] - private GridAtmosphereComponent _gridAtmosphereComponent = default!; + [ViewVariables] public int DismantleCooldown { get; set; } = 0; - [ViewVariables] - public int DismantleCooldown { get; set; } - - [ViewVariables] - public int BreakdownCooldown { get; set; } - - public void AddTile(TileAtmosphere tile) - { - _tiles.Add(tile); - tile.ExcitedGroup = this; - ResetCooldowns(); - } - - public bool RemoveTile(TileAtmosphere tile) - { - tile.ExcitedGroup = null; - return _tiles.Remove(tile); - } - - public void MergeGroups(ExcitedGroup other) - { - var ourSize = _tiles.Count; - var otherSize = other._tiles.Count; - - if (ourSize > otherSize) - { - foreach (var tile in other._tiles) - { - tile.ExcitedGroup = this; - _tiles.Add(tile); - } - other._tiles.Clear(); - other.Dispose(); - ResetCooldowns(); - } - else - { - foreach (var tile in _tiles) - { - tile.ExcitedGroup = other; - other._tiles.Add(tile); - } - _tiles.Clear(); - Dispose(); - other.ResetCooldowns(); - } - } - - ~ExcitedGroup() - { - Dispose(); - } - - public void Initialize(GridAtmosphereComponent gridAtmosphereComponent) - { - _gridAtmosphereComponent = gridAtmosphereComponent; - _gridAtmosphereComponent.AddExcitedGroup(this); - } - - public void ResetCooldowns() - { - BreakdownCooldown = 0; - DismantleCooldown = 0; - } - - public void SelfBreakdown(AtmosphereSystem atmosphereSystem, bool spaceIsAllConsuming = false) - { - var combined = new GasMixture(Atmospherics.CellVolume); - - var tileSize = _tiles.Count; - - if (_disposed) return; - - if (tileSize == 0) - { - Dispose(); - return; - } - - foreach (var tile in _tiles) - { - if (tile?.Air == null) continue; - atmosphereSystem.Merge(combined, tile.Air); - if (!spaceIsAllConsuming || !tile.Air.Immutable) continue; - combined.Clear(); - break; - } - - combined.Multiply(1 / (float)tileSize); - - foreach (var tile in _tiles) - { - if (tile?.Air == null) continue; - tile.Air.CopyFromMutable(combined); - tile.UpdateVisuals(); - } - - BreakdownCooldown = 0; - } - - public void Dismantle(bool unexcite = true) - { - foreach (var tile in _tiles) - { - if (tile == null) continue; - tile.ExcitedGroup = null; - if (!unexcite) continue; - tile.Excited = false; - _gridAtmosphereComponent.RemoveActiveTile(tile); - } - - _tiles.Clear(); - } - - public void Dispose() - { - if (_disposed) return; - _disposed = true; - _gridAtmosphereComponent.RemoveExcitedGroup(this); - - Dismantle(false); - - _gridAtmosphereComponent = null!; - } + [ViewVariables] public int BreakdownCooldown { get; set; } = 0; } } diff --git a/Content.Server/Atmos/Piping/Components/AtmosDeviceComponent.cs b/Content.Server/Atmos/Piping/Components/AtmosDeviceComponent.cs index 3880f93495..9b535e7e01 100644 --- a/Content.Server/Atmos/Piping/Components/AtmosDeviceComponent.cs +++ b/Content.Server/Atmos/Piping/Components/AtmosDeviceComponent.cs @@ -1,6 +1,7 @@ using System; using Content.Server.Atmos.Components; using Robust.Shared.GameObjects; +using Robust.Shared.Map; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.ViewVariables; @@ -21,40 +22,18 @@ namespace Content.Server.Atmos.Piping.Components [DataField("requireAnchored")] public bool RequireAnchored { get; private set; } = true; - public IGridAtmosphereComponent? Atmosphere { get; set; } - [ViewVariables] public TimeSpan LastProcess { get; set; } = TimeSpan.Zero; + + public GridId? JoinedGrid { get; set; } } - public abstract class BaseAtmosDeviceEvent : EntityEventArgs - { - public IGridAtmosphereComponent Atmosphere { get; } + public sealed class AtmosDeviceUpdateEvent : EntityEventArgs + {} - public BaseAtmosDeviceEvent(IGridAtmosphereComponent atmosphere) - { - Atmosphere = atmosphere; - } - } + public sealed class AtmosDeviceEnabledEvent : EntityEventArgs + {} - public sealed class AtmosDeviceUpdateEvent : BaseAtmosDeviceEvent - { - public AtmosDeviceUpdateEvent(IGridAtmosphereComponent atmosphere) : base(atmosphere) - { - } - } - - public sealed class AtmosDeviceEnabledEvent : BaseAtmosDeviceEvent - { - public AtmosDeviceEnabledEvent(IGridAtmosphereComponent atmosphere) : base(atmosphere) - { - } - } - - public sealed class AtmosDeviceDisabledEvent : BaseAtmosDeviceEvent - { - public AtmosDeviceDisabledEvent(IGridAtmosphereComponent atmosphere) : base(atmosphere) - { - } - } + public sealed class AtmosDeviceDisabledEvent : EntityEventArgs + {} } diff --git a/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs b/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs index 60f8fd3ead..5c0d7826c6 100644 --- a/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs +++ b/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs @@ -20,13 +20,13 @@ namespace Content.Server.Atmos.Piping.EntitySystems SubscribeLocalEvent(OnDeviceInitialize); SubscribeLocalEvent(OnDeviceShutdown); - SubscribeLocalEvent(OnDeviceBodyTypeChanged); SubscribeLocalEvent(OnDeviceParentChanged); + SubscribeLocalEvent(OnDeviceAnchorChanged); } private bool CanJoinAtmosphere(AtmosDeviceComponent component) { - return !component.RequireAnchored || !component.Owner.TryGetComponent(out PhysicsComponent? physics) || physics.BodyType == BodyType.Static; + return !component.RequireAnchored || !component.Owner.Transform.Anchored; } public void JoinAtmosphere(AtmosDeviceComponent component) @@ -34,26 +34,22 @@ namespace Content.Server.Atmos.Piping.EntitySystems if (!CanJoinAtmosphere(component)) return; - // We try to get a valid, simulated atmosphere. - if (!Get().TryGetSimulatedGridAtmosphere(component.Owner.Transform.MapPosition, out var atmosphere)) + // We try to add the device to a valid atmosphere. + if (!Get().AddAtmosDevice(component)) return; component.LastProcess = _gameTiming.CurTime; - component.Atmosphere = atmosphere; - atmosphere.AddAtmosDevice(component); - RaiseLocalEvent(component.Owner.Uid, new AtmosDeviceEnabledEvent(atmosphere), false); + RaiseLocalEvent(component.Owner.Uid, new AtmosDeviceEnabledEvent(), false); } public void LeaveAtmosphere(AtmosDeviceComponent component) { - var atmosphere = component.Atmosphere; - atmosphere?.RemoveAtmosDevice(component); - component.Atmosphere = null; - component.LastProcess = TimeSpan.Zero; + if (!Get().RemoveAtmosDevice(component)) + return; - if(atmosphere != null) - RaiseLocalEvent(component.Owner.Uid, new AtmosDeviceDisabledEvent(atmosphere), false); + component.LastProcess = TimeSpan.Zero; + RaiseLocalEvent(component.Owner.Uid, new AtmosDeviceDisabledEvent(), false); } public void RejoinAtmosphere(AtmosDeviceComponent component) @@ -72,13 +68,13 @@ namespace Content.Server.Atmos.Piping.EntitySystems LeaveAtmosphere(component); } - private void OnDeviceBodyTypeChanged(EntityUid uid, AtmosDeviceComponent component, PhysicsBodyTypeChangedEvent args) + private void OnDeviceAnchorChanged(EntityUid uid, AtmosDeviceComponent component, AnchorStateChangedEvent args) { // Do nothing if the component doesn't require being anchored to function. if (!component.RequireAnchored) return; - if (args.New == BodyType.Static) + if(component.Owner.Transform.Anchored) JoinAtmosphere(component); else LeaveAtmosphere(component); diff --git a/Content.Server/Atmos/Reactions/PlasmaFireReaction.cs b/Content.Server/Atmos/Reactions/PlasmaFireReaction.cs index 4df4ca508d..39a6b2963e 100644 --- a/Content.Server/Atmos/Reactions/PlasmaFireReaction.cs +++ b/Content.Server/Atmos/Reactions/PlasmaFireReaction.cs @@ -21,9 +21,8 @@ namespace Content.Server.Atmos.Reactions var location = holder as TileAtmosphere; mixture.ReactionResults[GasReaction.Fire] = 0; - // More plasma released at higher temperatures + // More plasma released at higher temperatures. var temperatureScale = 0f; - var superSaturation = false; if (temperature > Atmospherics.PlasmaUpperTemperature) temperatureScale = 1f; @@ -31,33 +30,31 @@ namespace Content.Server.Atmos.Reactions temperatureScale = (temperature - Atmospherics.PlasmaMinimumBurnTemperature) / (Atmospherics.PlasmaUpperTemperature - Atmospherics.PlasmaMinimumBurnTemperature); - if (temperatureScale > 0f) + if (temperatureScale > 0) { - var plasmaBurnRate = 0f; var oxygenBurnRate = Atmospherics.OxygenBurnRateBase - temperatureScale; + var plasmaBurnRate = 0f; - if (mixture.GetMoles(Gas.Oxygen) / mixture.GetMoles(Gas.Plasma) > - Atmospherics.SuperSaturationThreshold) - superSaturation = true; + var initialOxygenMoles = mixture.GetMoles(Gas.Oxygen); + var initialPlasmaMoles = mixture.GetMoles(Gas.Plasma); - if (mixture.GetMoles(Gas.Oxygen) > - mixture.GetMoles(Gas.Plasma) * Atmospherics.PlasmaOxygenFullburn) - plasmaBurnRate = (mixture.GetMoles(Gas.Plasma) * temperatureScale) / - Atmospherics.PlasmaBurnRateDelta; + // Supersaturation makes tritium. + var supersaturation = initialOxygenMoles / initialPlasmaMoles > Atmospherics.SuperSaturationThreshold; + + if (initialOxygenMoles > initialPlasmaMoles * Atmospherics.PlasmaOxygenFullburn) + plasmaBurnRate = initialPlasmaMoles * temperatureScale / Atmospherics.PlasmaBurnRateDelta; else - plasmaBurnRate = (temperatureScale * (mixture.GetMoles(Gas.Oxygen) / Atmospherics.PlasmaOxygenFullburn)) / Atmospherics.PlasmaBurnRateDelta; + plasmaBurnRate = temperatureScale * (initialOxygenMoles / Atmospherics.PlasmaOxygenFullburn) / Atmospherics.PlasmaBurnRateDelta; if (plasmaBurnRate > Atmospherics.MinimumHeatCapacity) { - plasmaBurnRate = MathF.Min(MathF.Min(plasmaBurnRate, mixture.GetMoles(Gas.Plasma)), mixture.GetMoles(Gas.Oxygen)/oxygenBurnRate); - mixture.SetMoles(Gas.Plasma, mixture.GetMoles(Gas.Plasma) - plasmaBurnRate); - mixture.SetMoles(Gas.Oxygen, mixture.GetMoles(Gas.Oxygen) - (plasmaBurnRate * oxygenBurnRate)); + plasmaBurnRate = MathF.Min(plasmaBurnRate, MathF.Min(initialPlasmaMoles, initialOxygenMoles / oxygenBurnRate)); + mixture.SetMoles(Gas.Plasma, initialPlasmaMoles - plasmaBurnRate); + mixture.SetMoles(Gas.Oxygen, initialOxygenMoles - plasmaBurnRate * oxygenBurnRate); + mixture.AdjustMoles(supersaturation ? Gas.Tritium : Gas.CarbonDioxide, plasmaBurnRate); - mixture.AdjustMoles(superSaturation ? Gas.Tritium : Gas.CarbonDioxide, plasmaBurnRate); - - energyReleased += Atmospherics.FirePlasmaEnergyReleased * (plasmaBurnRate); - - mixture.ReactionResults[GasReaction.Fire] += (plasmaBurnRate) * (1 + oxygenBurnRate); + energyReleased += Atmospherics.FirePlasmaEnergyReleased * plasmaBurnRate; + mixture.ReactionResults[GasReaction.Fire] += plasmaBurnRate * (1 + oxygenBurnRate); } } @@ -65,25 +62,25 @@ namespace Content.Server.Atmos.Reactions { var newHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture); if (newHeatCapacity > Atmospherics.MinimumHeatCapacity) - mixture.Temperature = ((temperature * oldHeatCapacity + energyReleased) / newHeatCapacity); + mixture.Temperature = (temperature * oldHeatCapacity + energyReleased) / newHeatCapacity; } if (location != null) { - temperature = mixture.Temperature; - if (temperature > Atmospherics.FireMinimumTemperatureToExist) + var mixTemperature = mixture.Temperature; + if (mixTemperature > Atmospherics.FireMinimumTemperatureToExist) { - atmosphereSystem.HotspotExpose(location.GridIndex, location.GridIndices, temperature, mixture.Volume); + atmosphereSystem.HotspotExpose(location.GridIndex, location.GridIndices, mixTemperature, mixture.Volume); foreach (var entity in location.GridIndices.GetEntitiesInTileFast(location.GridIndex)) { foreach (var temperatureExpose in entity.GetAllComponents()) { - temperatureExpose.TemperatureExpose(mixture, temperature, mixture.Volume); + temperatureExpose.TemperatureExpose(mixture, mixTemperature, mixture.Volume); } } - // TODO ATMOS: location.TemperatureExpose(mixture, temperature, mixture.Volume); + // TODO ATMOS: location.TemperatureExpose(mixture, mixTemperature, mixture.Volume); } } diff --git a/Content.Server/Atmos/TileAtmosphere.cs b/Content.Server/Atmos/TileAtmosphere.cs index d5f2881c05..a6249a0a30 100644 --- a/Content.Server/Atmos/TileAtmosphere.cs +++ b/Content.Server/Atmos/TileAtmosphere.cs @@ -1,7 +1,5 @@ #nullable disable warnings #nullable enable annotations -using System.Runtime.CompilerServices; -using Content.Server.Atmos.Components; using Content.Server.Interfaces; using Content.Shared.Atmos; using Content.Shared.Maps; @@ -11,6 +9,9 @@ using Robust.Shared.ViewVariables; namespace Content.Server.Atmos { + /// + /// Internal Atmos class that stores data about the atmosphere in a grid. + /// public class TileAtmosphere : IGasMixtureHolder { [ViewVariables] @@ -40,9 +41,6 @@ namespace Content.Server.Atmos [ViewVariables] public bool Excited { get; set; } - [ViewVariables] - private readonly GridAtmosphereComponent _gridAtmosphereComponent; - /// /// Adjacent tiles in the same order as . (NSEW) /// @@ -86,9 +84,8 @@ namespace Content.Server.Atmos [ViewVariables] public AtmosDirection BlockedAirflow { get; set; } = AtmosDirection.Invalid; - public TileAtmosphere(GridAtmosphereComponent atmosphereComponent, GridId gridIndex, Vector2i gridIndices, GasMixture? mixture = null, bool immutable = false) + public TileAtmosphere(GridId gridIndex, Vector2i gridIndices, GasMixture? mixture = null, bool immutable = false) { - _gridAtmosphereComponent = atmosphereComponent; GridIndex = gridIndex; GridIndices = gridIndices; Air = mixture; @@ -96,47 +93,5 @@ namespace Content.Server.Atmos if(immutable) Air?.MarkImmutable(); } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void UpdateVisuals() - { - if (Air == null) return; - - _gridAtmosphereComponent.GasTileOverlaySystem.Invalidate(GridIndex, GridIndices); - } - - public void UpdateAdjacent() - { - for (var i = 0; i < Atmospherics.Directions; i++) - { - var direction = (AtmosDirection) (1 << i); - - var otherIndices = GridIndices.Offset(direction.ToDirection()); - - var isSpace = _gridAtmosphereComponent.IsSpace(GridIndices); - var adjacent = _gridAtmosphereComponent.GetTile(otherIndices, !isSpace); - AdjacentTiles[direction.ToIndex()] = adjacent; - adjacent?.UpdateAdjacent(direction.GetOpposite()); - - if (adjacent != null && !BlockedAirflow.IsFlagSet(direction) && !_gridAtmosphereComponent.IsAirBlocked(adjacent.GridIndices, direction.GetOpposite())) - { - AdjacentBits |= direction; - } - } - } - - private void UpdateAdjacent(AtmosDirection direction) - { - AdjacentTiles[direction.ToIndex()] = _gridAtmosphereComponent.GetTile(GridIndices.Offset(direction.ToDirection())); - - if (!BlockedAirflow.IsFlagSet(direction) && !_gridAtmosphereComponent.IsAirBlocked(GridIndices.Offset(direction.ToDirection()), direction.GetOpposite())) - { - AdjacentBits |= direction; - } - else - { - AdjacentBits &= ~direction; - } - } } } diff --git a/Content.Server/NodeContainer/NodeGroups/PipeNet.cs b/Content.Server/NodeContainer/NodeGroups/PipeNet.cs index 5d04e23189..a1ce417ef3 100644 --- a/Content.Server/NodeContainer/NodeGroups/PipeNet.cs +++ b/Content.Server/NodeContainer/NodeGroups/PipeNet.cs @@ -8,7 +8,9 @@ using Content.Server.Interfaces; using Content.Server.NodeContainer.Nodes; using Content.Shared.Atmos; using Robust.Shared.GameObjects; +using Robust.Shared.Map; using Robust.Shared.Maths; +using Robust.Shared.Utility; using Robust.Shared.ViewVariables; namespace Content.Server.NodeContainer.NodeGroups @@ -30,16 +32,14 @@ namespace Content.Server.NodeContainer.NodeGroups [ViewVariables] private AtmosphereSystem? _atmosphereSystem; - [ViewVariables] - private IGridAtmosphereComponent? GridAtmos => - _atmosphereSystem?.GetGridAtmosphere(GridId); + public GridId Grid => GridId; public override void Initialize(Node sourceNode) { base.Initialize(sourceNode); _atmosphereSystem = EntitySystem.Get(); - GridAtmos?.AddPipeNet(this); + _atmosphereSystem.AddPipeNet(this); } public void Update() @@ -94,7 +94,8 @@ namespace Content.Server.NodeContainer.NodeGroups private void RemoveFromGridAtmos() { - GridAtmos?.RemovePipeNet(this); + DebugTools.AssertNotNull(_atmosphereSystem); + _atmosphereSystem?.RemovePipeNet(this); } } }