ECS Atmos Part 5: Moves all logic from GridAtmosphereComponent to AtmosphereSystem. (#4331)

This commit is contained in:
Vera Aguilera Puerto
2021-07-23 11:09:01 +02:00
committed by GitHub
parent 354ef6daf3
commit 4112847142
23 changed files with 1242 additions and 1355 deletions

View File

@@ -1,24 +1,13 @@
// ReSharper disable once RedundantUsingDirective
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using Content.Server.Atmos.EntitySystems; using Content.Server.Atmos.EntitySystems;
using Content.Server.Atmos.Piping.Components; using Content.Server.Atmos.Piping.Components;
using Content.Server.CPUJob.JobQueues.Queues;
using Content.Server.NodeContainer.NodeGroups; using Content.Server.NodeContainer.NodeGroups;
using Content.Shared.Atmos;
using Content.Shared.Maps;
using Robust.Server.GameObjects;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Maths; using Robust.Shared.Maths;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Timing;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
using Dependency = Robust.Shared.IoC.DependencyAttribute; using Dependency = Robust.Shared.IoC.DependencyAttribute;
@@ -31,33 +20,21 @@ namespace Content.Server.Atmos.Components
[RegisterComponent, Serializable] [RegisterComponent, Serializable]
public class GridAtmosphereComponent : Component, IGridAtmosphereComponent, ISerializationHooks 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 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; 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] [ViewVariables]
public int UpdateCounter { get; set; } = 0; public int UpdateCounter { get; set; } = 0;
[ViewVariables]
public readonly HashSet<ExcitedGroup> ExcitedGroups = new(1000);
[ViewVariables]
public int ExcitedGroupCount => ExcitedGroups.Count;
[DataField("uniqueMixes")] [DataField("uniqueMixes")]
public List<GasMixture>? UniqueMixes; public List<GasMixture>? UniqueMixes;
@@ -73,6 +50,12 @@ namespace Content.Server.Atmos.Components
[ViewVariables] [ViewVariables]
public int ActiveTilesCount => ActiveTiles.Count; public int ActiveTilesCount => ActiveTiles.Count;
[ViewVariables]
public readonly HashSet<ExcitedGroup> ExcitedGroups = new(1000);
[ViewVariables]
public int ExcitedGroupCount => ExcitedGroups.Count;
[ViewVariables] [ViewVariables]
public readonly HashSet<TileAtmosphere> HotspotTiles = new(1000); public readonly HashSet<TileAtmosphere> HotspotTiles = new(1000);
@@ -85,9 +68,6 @@ namespace Content.Server.Atmos.Components
[ViewVariables] [ViewVariables]
public int SuperconductivityTilesCount => SuperconductivityTiles.Count; public int SuperconductivityTilesCount => SuperconductivityTiles.Count;
[ViewVariables]
public readonly HashSet<Vector2i> InvalidatedCoords = new(1000);
[ViewVariables] [ViewVariables]
public HashSet<TileAtmosphere> HighPressureDelta = new(1000); public HashSet<TileAtmosphere> HighPressureDelta = new(1000);
@@ -112,22 +92,21 @@ namespace Content.Server.Atmos.Components
[ViewVariables] [ViewVariables]
public Queue<AtmosDeviceComponent> CurrentRunAtmosDevices = new(); public Queue<AtmosDeviceComponent> CurrentRunAtmosDevices = new();
[ViewVariables]
public readonly HashSet<Vector2i> InvalidatedCoords = new(1000);
[ViewVariables]
public Queue<Vector2i> CurrentRunInvalidatedCoordinates = new();
[ViewVariables]
public int InvalidatedCoordsCount => InvalidatedCoords.Count;
[ViewVariables]
public long EqualizationQueueCycleControl { get; set; }
[ViewVariables] [ViewVariables]
public AtmosphereProcessingState State { get; set; } = AtmosphereProcessingState.TileEqualize; public AtmosphereProcessingState State { get; set; } = AtmosphereProcessingState.TileEqualize;
public GridAtmosphereComponent()
{
ProcessingPaused = false;
}
/// <inheritdoc />
public virtual void PryTile(Vector2i indices)
{
if (IsSpace(indices) || IsAirBlocked(indices)) return;
indices.PryTile(_gridId, _mapManager, _tileDefinitionManager, _serverEntityManager);
}
void ISerializationHooks.BeforeSerialization() void ISerializationHooks.BeforeSerialization()
{ {
var uniqueMixes = new List<GasMixture>(); var uniqueMixes = new List<GasMixture>();
@@ -156,403 +135,5 @@ namespace Content.Server.Atmos.Components
UniqueMixes = uniqueMixes; UniqueMixes = uniqueMixes;
TilesUniqueMixes = tiles; 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<GasTileOverlaySystem>();
AtmosphereSystem = EntitySystem.Get<AtmosphereSystem>();
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();
}
}
/// <inheritdoc />
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();
}
/// <inheritdoc />
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);
}
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void AddActiveTile(TileAtmosphere tile)
{
if (tile?.GridIndex != _gridId || tile.Air == null) return;
tile.Excited = true;
ActiveTiles.Add(tile);
}
/// <inheritdoc />
[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);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void AddHotspotTile(TileAtmosphere tile)
{
if (tile?.GridIndex != _gridId || tile?.Air == null) return;
HotspotTiles.Add(tile);
}
/// <inheritdoc />
[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);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void AddHighPressureDelta(TileAtmosphere tile)
{
if (tile.GridIndex != _gridId) return;
HighPressureDelta.Add(tile);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual bool HasHighPressureDelta(TileAtmosphere tile)
{
return HighPressureDelta.Contains(tile);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void AddExcitedGroup(ExcitedGroup excitedGroup)
{
ExcitedGroups.Add(excitedGroup);
}
/// <inheritdoc />
[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);
}
/// <inheritdoc />
public virtual TileAtmosphere? GetTile(EntityCoordinates coordinates, bool createSpace = true)
{
return GetTile(coordinates.ToVector2i(_serverEntityManager, _mapManager), createSpace);
}
/// <inheritdoc />
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;
}
/// <inheritdoc />
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;
}
/// <inheritdoc />
public virtual bool IsSpace(Vector2i indices)
{
if (_mapGridComponent == null) return default;
return _mapGridComponent.Grid.GetTileRef(indices).IsSpace();
}
public Dictionary<AtmosDirection, TileAtmosphere> GetAdjacentTiles(EntityCoordinates coordinates, bool includeAirBlocked = false)
{
return GetAdjacentTiles(coordinates.ToVector2i(_serverEntityManager, _mapManager), includeAirBlocked);
}
public Dictionary<AtmosDirection, TileAtmosphere> GetAdjacentTiles(Vector2i indices, bool includeAirBlocked = false)
{
var sides = new Dictionary<AtmosDirection, TileAtmosphere>();
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; }
/// <inheritdoc />
public float GetVolumeForCells(int cellCount)
{
if (_mapGridComponent == null) return default;
return _mapGridComponent.Grid.TileSize * cellCount * Atmospherics.CellVolume;
}
protected virtual IEnumerable<AirtightComponent> GetObstructingComponents(Vector2i indices)
{
var gridLookup = EntitySystem.Get<GridTileLookupSystem>();
foreach (var v in gridLookup.GetEntitiesIntersecting(_gridId, indices))
{
if (v.TryGetComponent<AirtightComponent>(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<TileAtmosphere> GetEnumerator()
{
return Tiles.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <inheritdoc />
public virtual void BurnTile(Vector2i gridIndices)
{
// TODO ATMOS
}
} }
} }

View File

@@ -1,181 +1,12 @@
using System.Collections.Generic; using Robust.Shared.GameObjects;
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;
namespace Content.Server.Atmos.Components namespace Content.Server.Atmos.Components
{ {
public interface IGridAtmosphereComponent : IComponent, IEnumerable<TileAtmosphere> public interface IGridAtmosphereComponent : IComponent
{ {
/// <summary> /// <summary>
/// Whether this atmosphere is simulated or not. /// Whether this atmosphere is simulated or not.
/// </summary> /// </summary>
bool Simulated { get; } bool Simulated { get; }
/// <summary>
/// Number of times <see cref="Update"/> has been called.
/// </summary>
int UpdateCounter { get; }
/// <summary>
/// Control variable for equalization.
/// </summary>
long EqualizationQueueCycleControl { get; set; }
/// <summary>
/// Attemps to pry a tile.
/// </summary>
/// <param name="indices"></param>
void PryTile(Vector2i indices);
/// <summary>
/// Burns a tile.
/// </summary>
/// <param name="gridIndices"></param>
void BurnTile(Vector2i gridIndices);
/// <summary>
/// Invalidates a coordinate to be revalidated again.
/// Use this after changing a tile's gas contents, or when the tile becomes space, etc.
/// </summary>
/// <param name="indices"></param>
void Invalidate(Vector2i indices);
/// <summary>
/// Attempts to fix a sudden vacuum by creating gas.
/// </summary>
void FixVacuum(Vector2i indices);
/// <summary>
/// Revalidates indices immediately.
/// </summary>
/// <param name="indices"></param>
void UpdateAdjacentBits(Vector2i indices);
/// <summary>
/// Adds an active tile so it becomes processed every update until it becomes inactive.
/// Also makes the tile excited.
/// </summary>
/// <param name="tile"></param>
void AddActiveTile(TileAtmosphere tile);
/// <summary>
/// Removes an active tile and disposes of its <seealso cref="ExcitedGroup"/>.
/// Use with caution.
/// </summary>
/// <param name="tile"></param>
void RemoveActiveTile(TileAtmosphere tile, bool disposeGroup = true);
/// <summary>
/// Marks a tile as having a hotspot so it can be processed.
/// </summary>
/// <param name="tile"></param>
void AddHotspotTile(TileAtmosphere tile);
/// <summary>
/// Removes a tile from the hotspot processing list.
/// </summary>
/// <param name="tile"></param>
void RemoveHotspotTile(TileAtmosphere tile);
/// <summary>
/// Marks a tile as superconductive so it can be processed.
/// </summary>
/// <param name="tile"></param>
void AddSuperconductivityTile(TileAtmosphere tile);
/// <summary>
/// Removes a tile from the superconductivity processing list.
/// </summary>
/// <param name="tile"></param>
void RemoveSuperconductivityTile(TileAtmosphere tile);
/// <summary>
/// Marks a tile has having high pressure differences that need to be equalized.
/// </summary>
/// <param name="tile"></param>
void AddHighPressureDelta(TileAtmosphere tile);
/// <summary>
/// Returns whether the tile in question is marked as having high pressure differences or not.
/// </summary>
/// <param name="tile"></param>
/// <returns></returns>
bool HasHighPressureDelta(TileAtmosphere tile);
/// <summary>
/// Adds a excited group to be processed.
/// </summary>
/// <param name="excitedGroup"></param>
void AddExcitedGroup(ExcitedGroup excitedGroup);
/// <summary>
/// Removes an excited group.
/// </summary>
/// <param name="excitedGroup"></param>
void RemoveExcitedGroup(ExcitedGroup excitedGroup);
/// <summary>
/// Returns a tile.
/// </summary>
/// <param name="indices"></param>
/// <param name="createSpace"></param>
/// <returns></returns>
TileAtmosphere? GetTile(Vector2i indices, bool createSpace = true);
/// <summary>
/// Returns a tile.
/// </summary>
/// <param name="coordinates"></param>
/// <param name="createSpace"></param>
/// <returns></returns>
TileAtmosphere? GetTile(EntityCoordinates coordinates, bool createSpace = true);
/// <summary>
/// Returns if the tile in question is air-blocked.
/// This could be due to a wall, an airlock, etc.
/// <seealso cref="AirtightComponent"/>
/// </summary>
/// <param name="indices"></param>
/// <param name="direction"></param>
/// <returns></returns>
bool IsAirBlocked(Vector2i indices, AtmosDirection direction);
/// <summary>
/// Returns if the tile in question is space.
/// </summary>
/// <param name="indices"></param>
/// <returns></returns>
bool IsSpace(Vector2i indices);
/// <summary>
/// Returns the volume in liters for a number of cells/tiles.
/// </summary>
/// <param name="cellCount"></param>
/// <returns></returns>
float GetVolumeForCells(int cellCount);
void RepopulateTiles();
/// <summary>
/// Returns a dictionary of adjacent TileAtmospheres.
/// </summary>
Dictionary<AtmosDirection, TileAtmosphere> GetAdjacentTiles(EntityCoordinates coordinates, bool includeAirBlocked = false);
/// <summary>
/// Returns a dictionary of adjacent TileAtmospheres.
/// </summary>
Dictionary<AtmosDirection, TileAtmosphere> GetAdjacentTiles(Vector2i indices, bool includeAirBlocked = false);
void AddPipeNet(IPipeNet pipeNet);
void RemovePipeNet(IPipeNet pipeNet);
void AddAtmosDevice(AtmosDeviceComponent atmosDevice);
void RemoveAtmosDevice(AtmosDeviceComponent atmosDevice);
} }
} }

View File

@@ -12,22 +12,5 @@ namespace Content.Server.Atmos.Components
public class SpaceGridAtmosphereComponent : UnsimulatedGridAtmosphereComponent public class SpaceGridAtmosphereComponent : UnsimulatedGridAtmosphereComponent
{ {
public override string Name => "SpaceGridAtmosphere"; 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<AirtightComponent> GetObstructingComponents(Vector2i indices)
{
return Enumerable.Empty<AirtightComponent>();
}
} }
} }

View File

@@ -16,55 +16,5 @@ namespace Content.Server.Atmos.Components
public override string Name => "UnsimulatedGridAtmosphere"; public override string Name => "UnsimulatedGridAtmosphere";
public override bool Simulated => false; 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) { }
} }
} }

View File

@@ -127,6 +127,7 @@ namespace Content.Server.Atmos.EntitySystems
AccumulatedFrameTime -= _updateCooldown; AccumulatedFrameTime -= _updateCooldown;
var currentTick = _gameTiming.CurTick; var currentTick = _gameTiming.CurTick;
var atmosphereSystem = Get<AtmosphereSystem>();
// Now we'll go through each player, then through each chunk in range of that player checking if the player is still in range // 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). // 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++) for (var x = 0; x < LocalViewRange; x++)
{ {
var Vector2i = new Vector2i(baseTile.X + x, baseTile.Y + y); var Vector2i = new Vector2i(baseTile.X + x, baseTile.Y + y);
debugOverlayContent[index++] = ConvertTileToData(gam.GetTile(Vector2i)); debugOverlayContent[index++] = ConvertTileToData(atmosphereSystem.GetTileAtmosphereOrCreateSpace(grid, gam, Vector2i));
} }
} }

View File

@@ -1,9 +1,13 @@
using Content.Shared.CCVar; using Content.Shared.CCVar;
using Robust.Shared.Configuration;
using Robust.Shared.IoC;
namespace Content.Server.Atmos.EntitySystems namespace Content.Server.Atmos.EntitySystems
{ {
public partial class AtmosphereSystem public partial class AtmosphereSystem
{ {
[Dependency] private readonly IConfigurationManager _cfg = default!;
public bool SpaceWind { get; private set; } public bool SpaceWind { get; private set; }
public string? SpaceWindSound { get; private set; } public string? SpaceWindSound { get; private set; }
public bool MonstermosEqualization { get; private set; } public bool MonstermosEqualization { get; private set; }

View File

@@ -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);
}
}
}

View File

@@ -4,12 +4,16 @@ using System.Linq;
using Content.Server.Atmos.Reactions; using Content.Server.Atmos.Reactions;
using Content.Server.Interfaces; using Content.Server.Interfaces;
using Content.Shared.Atmos; using Content.Shared.Atmos;
using Robust.Shared.IoC;
using Robust.Shared.Maths; using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
namespace Content.Server.Atmos.EntitySystems namespace Content.Server.Atmos.EntitySystems
{ {
public partial class AtmosphereSystem public partial class AtmosphereSystem
{ {
[Dependency] private readonly IPrototypeManager _protoMan = default!;
private GasReactionPrototype[] _gasReactions = Array.Empty<GasReactionPrototype>(); private GasReactionPrototype[] _gasReactions = Array.Empty<GasReactionPrototype>();
private float[] _gasSpecificHeats = new float[Atmospherics.TotalNumberOfGases]; private float[] _gasSpecificHeats = new float[Atmospherics.TotalNumberOfGases];
@@ -51,16 +55,23 @@ namespace Content.Server.Atmos.EntitySystems
return mixture.Temperature * GetHeatCapacity(mixture); return mixture.Temperature * GetHeatCapacity(mixture);
} }
public float GetThermalEnergy(GasMixture mixture, float cachedHeatCapacity)
{
return mixture.Temperature * cachedHeatCapacity;
}
public void Merge(GasMixture receiver, GasMixture giver) public void Merge(GasMixture receiver, GasMixture giver)
{ {
if (receiver.Immutable) return; if (receiver.Immutable) return;
if (MathF.Abs(receiver.Temperature - giver.Temperature) > Atmospherics.MinimumTemperatureDeltaToConsider) 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) if (combinedHeatCapacity > 0f)
{ {
receiver.Temperature = (GetThermalEnergy(giver) + GetThermalEnergy(receiver)) / combinedHeatCapacity; receiver.Temperature = (GetThermalEnergy(giver, giverHeatCapacity) + GetThermalEnergy(receiver, receiverHeatCapacity)) / combinedHeatCapacity;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -58,7 +58,7 @@ namespace Content.Server.Atmos.EntitySystems
private void ConsiderPressureDifference(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, TileAtmosphere other, float difference) private void ConsiderPressureDifference(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, TileAtmosphere other, float difference)
{ {
gridAtmosphere.AddHighPressureDelta(tile); gridAtmosphere.HighPressureDelta.Add(tile);
if (difference > tile.PressureDifference) if (difference > tile.PressureDifference)
{ {
tile.PressureDifference = difference; tile.PressureDifference = difference;

View File

@@ -4,8 +4,8 @@ using Content.Server.Atmos.Components;
using Content.Server.Atmos.Reactions; using Content.Server.Atmos.Reactions;
using Content.Server.Coordinates.Helpers; using Content.Server.Coordinates.Helpers;
using Content.Shared.Atmos; using Content.Shared.Atmos;
using Content.Shared.GameTicking;
using Content.Shared.Maps; using Content.Shared.Maps;
using Robust.Shared.Map;
namespace Content.Server.Atmos.EntitySystems namespace Content.Server.Atmos.EntitySystems
{ {
@@ -15,13 +15,13 @@ namespace Content.Server.Atmos.EntitySystems
{ {
if (!tile.Hotspot.Valid) if (!tile.Hotspot.Valid)
{ {
gridAtmosphere.RemoveHotspotTile(tile); gridAtmosphere.HotspotTiles.Remove(tile);
return; return;
} }
if (!tile.Excited) if (!tile.Excited)
{ {
gridAtmosphere.AddActiveTile(tile); AddActiveTile(gridAtmosphere, tile);
} }
if (!tile.Hotspot.SkippedFirstProcess) if (!tile.Hotspot.SkippedFirstProcess)
@@ -30,13 +30,14 @@ namespace Content.Server.Atmos.EntitySystems
return; return;
} }
tile.ExcitedGroup?.ResetCooldowns(); if(tile.ExcitedGroup != null)
ExcitedGroupResetCooldowns(tile.ExcitedGroup);
if ((tile.Hotspot.Temperature < Atmospherics.FireMinimumTemperatureToExist) || (tile.Hotspot.Volume <= 1f) 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.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.Hotspot = new Hotspot();
tile.UpdateVisuals(); InvalidateVisuals(tile.GridIndex, tile.GridIndices);
return; return;
} }
@@ -45,13 +46,17 @@ namespace Content.Server.Atmos.EntitySystems
if (tile.Hotspot.Bypassing) if (tile.Hotspot.Bypassing)
{ {
tile.Hotspot.State = 3; tile.Hotspot.State = 3;
gridAtmosphere.BurnTile(tile.GridIndices); // TODO ATMOS: Burn tile here
if (tile.Air.Temperature > Atmospherics.FireMinimumTemperatureToSpread) if (tile.Air.Temperature > Atmospherics.FireMinimumTemperatureToSpread)
{ {
var radiatedTemperature = tile.Air.Temperature * Atmospherics.FireSpreadRadiosityScale; var radiatedTemperature = tile.Air.Temperature * Atmospherics.FireSpreadRadiosityScale;
foreach (var otherTile in tile.AdjacentTiles) foreach (var otherTile in tile.AdjacentTiles)
{ {
// TODO ATMOS: This is sus. Suss this out.
if (otherTile == null)
continue;
if(!otherTile.Hotspot.Valid) if(!otherTile.Hotspot.Valid)
HotspotExpose(gridAtmosphere, otherTile, radiatedTemperature, Atmospherics.CellVolume/4); HotspotExpose(gridAtmosphere, otherTile, radiatedTemperature, Atmospherics.CellVolume/4);
} }
@@ -108,8 +113,8 @@ namespace Content.Server.Atmos.EntitySystems
tile.Hotspot.Start(); tile.Hotspot.Start();
gridAtmosphere.AddActiveTile(tile); AddActiveTile(gridAtmosphere, tile);
gridAtmosphere.AddHotspotTile(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); var affected = tile.Air.RemoveRatio(tile.Hotspot.Volume / tile.Air.Volume);
affected.Temperature = tile.Hotspot.Temperature; affected.Temperature = tile.Hotspot.Temperature;
gridAtmosphere.AtmosphereSystem.React(affected, tile); React(affected, tile);
tile.Hotspot.Temperature = affected.Temperature; tile.Hotspot.Temperature = affected.Temperature;
tile.Hotspot.Volume = affected.ReactionResults[GasReaction.Fire] * Atmospherics.FireGrowthRate; tile.Hotspot.Volume = affected.ReactionResults[GasReaction.Fire] * Atmospherics.FireGrowthRate;
Merge(tile.Air, affected); Merge(tile.Air, affected);
gridAtmosphere.Invalidate(tile.GridIndices); gridAtmosphere.InvalidatedCoords.Add(tile.GridIndices);
} }
var tileRef = tile.GridIndices.GetTileRef(tile.GridIndex); var tileRef = tile.GridIndices.GetTileRef(tile.GridIndex);

View File

@@ -12,7 +12,7 @@ namespace Content.Server.Atmos.EntitySystems
// Can't process a tile without air // Can't process a tile without air
if (tile.Air == null) if (tile.Air == null)
{ {
gridAtmosphere.RemoveActiveTile(tile); RemoveActiveTile(gridAtmosphere, tile);
return; return;
} }
@@ -46,7 +46,7 @@ namespace Content.Server.Atmos.EntitySystems
{ {
if (tile.ExcitedGroup != enemyTile.ExcitedGroup) if (tile.ExcitedGroup != enemyTile.ExcitedGroup)
{ {
tile.ExcitedGroup.MergeGroups(enemyTile.ExcitedGroup); ExcitedGroupMerge(gridAtmosphere, tile.ExcitedGroup, enemyTile.ExcitedGroup);
} }
shouldShareAir = true; shouldShareAir = true;
@@ -54,7 +54,7 @@ namespace Content.Server.Atmos.EntitySystems
{ {
if (!enemyTile.Excited) if (!enemyTile.Excited)
{ {
gridAtmosphere.AddActiveTile(enemyTile); AddActiveTile(gridAtmosphere, enemyTile);
} }
var excitedGroup = tile.ExcitedGroup; var excitedGroup = tile.ExcitedGroup;
@@ -63,14 +63,14 @@ namespace Content.Server.Atmos.EntitySystems
if (excitedGroup == null) if (excitedGroup == null)
{ {
excitedGroup = new ExcitedGroup(); excitedGroup = new ExcitedGroup();
excitedGroup.Initialize(gridAtmosphere); gridAtmosphere.ExcitedGroups.Add(excitedGroup);
} }
if (tile.ExcitedGroup == null) if (tile.ExcitedGroup == null)
excitedGroup.AddTile(tile); ExcitedGroupAddTile(excitedGroup, tile);
if(enemyTile.ExcitedGroup == null) if(enemyTile.ExcitedGroup == null)
excitedGroup.AddTile(enemyTile); ExcitedGroupAddTile(excitedGroup, enemyTile);
shouldShareAir = true; shouldShareAir = true;
} }
@@ -97,7 +97,8 @@ namespace Content.Server.Atmos.EntitySystems
if(tile.Air != null) if(tile.Air != null)
React(tile.Air, tile); React(tile.Air, tile);
tile.UpdateVisuals();
InvalidateVisuals(tile.GridIndex, tile.GridIndices);
var remove = true; var remove = true;
@@ -106,7 +107,7 @@ namespace Content.Server.Atmos.EntitySystems
remove = false; remove = false;
if(tile.ExcitedGroup == null && remove) if(tile.ExcitedGroup == null && remove)
gridAtmosphere.RemoveActiveTile(tile); RemoveActiveTile(gridAtmosphere, tile);
} }
private void Archive(TileAtmosphere tile, int fireCount) private void Archive(TileAtmosphere tile, int fireCount)
@@ -124,7 +125,7 @@ namespace Content.Server.Atmos.EntitySystems
switch (tile.Air.LastShare) switch (tile.Air.LastShare)
{ {
case > Atmospherics.MinimumAirToSuspend: case > Atmospherics.MinimumAirToSuspend:
tile.ExcitedGroup.ResetCooldowns(); ExcitedGroupResetCooldowns(tile.ExcitedGroup);
break; break;
case > Atmospherics.MinimumMolesDeltaToMove: case > Atmospherics.MinimumMolesDeltaToMove:
tile.ExcitedGroup.DismantleCooldown = 0; tile.ExcitedGroup.DismantleCooldown = 0;

View File

@@ -7,6 +7,7 @@ using Content.Server.Atmos.Components;
using Content.Server.Coordinates.Helpers; using Content.Server.Coordinates.Helpers;
using Content.Shared.Atmos; using Content.Shared.Atmos;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths; using Robust.Shared.Maths;
using Robust.Shared.Random; using Robust.Shared.Random;
@@ -18,7 +19,7 @@ namespace Content.Server.Atmos.EntitySystems
private readonly TileAtmosphereComparer _monstermosComparer = new(); 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)) if (tile.Air == null || (tile.MonstermosInfo.LastCycle >= cycleNum))
return; // Already done. return; // Already done.
@@ -80,7 +81,8 @@ namespace Content.Server.Atmos.EntitySystems
if (adj.Air.Immutable) if (adj.Air.Immutable)
{ {
// Looks like someone opened an airlock to space! // Looks like someone opened an airlock to space!
ExplosivelyDepressurize(gridAtmosphere, tile, cycleNum);
ExplosivelyDepressurize(mapGrid, gridAtmosphere, tile, cycleNum);
return; return;
} }
} }
@@ -339,7 +341,7 @@ namespace Content.Server.Atmos.EntitySystems
if (!otherTile.AdjacentBits.IsFlagSet(direction)) continue; if (!otherTile.AdjacentBits.IsFlagSet(direction)) continue;
var otherTile2 = otherTile.AdjacentTiles[j]; var otherTile2 = otherTile.AdjacentTiles[j];
if (otherTile2?.Air?.Compare(tile.Air) == GasMixture.GasCompareResult.NoExchange) continue; if (otherTile2?.Air?.Compare(tile.Air) == GasMixture.GasCompareResult.NoExchange) continue;
gridAtmosphere.AddActiveTile(otherTile2); AddActiveTile(gridAtmosphere, otherTile2);
break; break;
} }
} }
@@ -349,7 +351,7 @@ namespace Content.Server.Atmos.EntitySystems
ArrayPool<TileAtmosphere>.Shared.Return(takerTiles); ArrayPool<TileAtmosphere>.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. // Check if explosive depressurization is enabled and if the tile is valid.
if (!MonstermosDepressurization || tile.Air == null) if (!MonstermosDepressurization || tile.Air == null)
@@ -389,7 +391,7 @@ namespace Content.Server.Atmos.EntitySystems
if (otherTile2.Air == null) continue; if (otherTile2.Air == null) continue;
if (otherTile2.MonstermosInfo.LastQueueCycle == queueCycle) continue; if (otherTile2.MonstermosInfo.LastQueueCycle == queueCycle) continue;
ConsiderFirelocks(otherTile, otherTile2); ConsiderFirelocks(gridAtmosphere, otherTile, otherTile2);
// The firelocks might have closed on us. // The firelocks might have closed on us.
if (!otherTile.AdjacentBits.IsFlagSet(direction)) continue; if (!otherTile.AdjacentBits.IsFlagSet(direction)) continue;
@@ -438,8 +440,8 @@ namespace Content.Server.Atmos.EntitySystems
{ {
var otherTile = progressionOrder[i]; var otherTile = progressionOrder[i];
if (otherTile.MonstermosInfo.CurrentTransferDirection == AtmosDirection.Invalid) continue; if (otherTile.MonstermosInfo.CurrentTransferDirection == AtmosDirection.Invalid) continue;
gridAtmosphere.AddHighPressureDelta(otherTile); gridAtmosphere.HighPressureDelta.Add(otherTile);
gridAtmosphere.AddActiveTile(otherTile); AddActiveTile(gridAtmosphere, otherTile);
var otherTile2 = otherTile.AdjacentTiles[otherTile.MonstermosInfo.CurrentTransferDirection.ToIndex()]; var otherTile2 = otherTile.AdjacentTiles[otherTile.MonstermosInfo.CurrentTransferDirection.ToIndex()];
if (otherTile2?.Air == null) continue; if (otherTile2?.Air == null) continue;
var sum = otherTile2.Air.TotalMoles; var sum = otherTile2.Air.TotalMoles;
@@ -455,9 +457,9 @@ namespace Content.Server.Atmos.EntitySystems
otherTile2.PressureDirection = otherTile.MonstermosInfo.CurrentTransferDirection; otherTile2.PressureDirection = otherTile.MonstermosInfo.CurrentTransferDirection;
} }
otherTile.Air.Clear(); otherTile.Air?.Clear();
otherTile.UpdateVisuals(); InvalidateVisuals(otherTile.GridIndex, otherTile.GridIndices);
HandleDecompressionFloorRip(gridAtmosphere, otherTile, sum); HandleDecompressionFloorRip(mapGrid, otherTile, sum);
} }
ArrayPool<TileAtmosphere>.Shared.Return(tiles); ArrayPool<TileAtmosphere>.Shared.Return(tiles);
@@ -465,7 +467,7 @@ namespace Content.Server.Atmos.EntitySystems
ArrayPool<TileAtmosphere>.Shared.Return(progressionOrder); ArrayPool<TileAtmosphere>.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)) if (!_mapManager.TryGetGrid(tile.GridIndex, out var mapGrid))
return; return;
@@ -491,8 +493,10 @@ namespace Content.Server.Atmos.EntitySystems
if (!reconsiderAdjacent) if (!reconsiderAdjacent)
return; return;
tile.UpdateAdjacent(); UpdateAdjacent(mapGrid, gridAtmosphere, tile);
other.UpdateAdjacent(); UpdateAdjacent(mapGrid, gridAtmosphere, other);
InvalidateVisuals(tile.GridIndex, tile.GridIndices);
InvalidateVisuals(other.GridIndex, other.GridIndices);
} }
public void FinalizeEq(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile) public void FinalizeEq(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile)
@@ -524,8 +528,8 @@ namespace Content.Server.Atmos.EntitySystems
otherTile.MonstermosInfo[direction.GetOpposite()] = 0; otherTile.MonstermosInfo[direction.GetOpposite()] = 0;
Merge(otherTile.Air, tile.Air.Remove(amount)); Merge(otherTile.Air, tile.Air.Remove(amount));
tile.UpdateVisuals(); InvalidateVisuals(tile.GridIndex, tile.GridIndices);
otherTile.UpdateVisuals(); InvalidateVisuals(otherTile.GridIndex, otherTile.GridIndices);
ConsiderPressureDifference(gridAtmosphere, tile, otherTile, amount); ConsiderPressureDifference(gridAtmosphere, tile, otherTile, amount);
} }
} }
@@ -548,12 +552,12 @@ namespace Content.Server.Atmos.EntitySystems
tile.AdjacentTiles[direction.ToIndex()].MonstermosInfo[direction.GetOpposite()] -= amount; 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); var chance = MathHelper.Clamp(sum / 500, 0.005f, 0.5f);
if (sum > 20 && _robustRandom.Prob(chance)) if (sum > 20 && _robustRandom.Prob(chance))
gridAtmosphere.PryTile(tile.GridIndices); PryTile(mapGrid, tile.GridIndices);
} }
private class TileAtmosphereComparer : IComparer<TileAtmosphere> private class TileAtmosphereComparer : IComparer<TileAtmosphere>

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.Atmos.Components; using Content.Server.Atmos.Components;
using Content.Server.Atmos.Piping.Components; using Content.Server.Atmos.Piping.Components;
@@ -20,6 +21,11 @@ namespace Content.Server.Atmos.EntitySystems
/// </summary> /// </summary>
private const int LagCheckIterations = 30; private const int LagCheckIterations = 30;
/// <summary>
/// Check current execution time every n instances processed.
/// </summary>
private const int InvalidCoordinatesLagCheckIterations = 50;
private int _currentRunAtmosphereIndex = 0; private int _currentRunAtmosphereIndex = 0;
private bool _simulationPaused = false; private bool _simulationPaused = false;
@@ -30,10 +36,13 @@ namespace Content.Server.Atmos.EntitySystems
if(!atmosphere.ProcessingPaused) if(!atmosphere.ProcessingPaused)
atmosphere.CurrentRunTiles = new Queue<TileAtmosphere>(atmosphere.ActiveTiles); atmosphere.CurrentRunTiles = new Queue<TileAtmosphere>(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; var number = 0;
while (atmosphere.CurrentRunTiles.TryDequeue(out var tile)) while (atmosphere.CurrentRunTiles.TryDequeue(out var tile))
{ {
EqualizePressureInZone(atmosphere, tile, atmosphere.UpdateCounter); EqualizePressureInZone(mapGrid, atmosphere, tile, atmosphere.UpdateCounter);
if (number++ < LagCheckIterations) continue; if (number++ < LagCheckIterations) continue;
number = 0; number = 0;
@@ -69,22 +78,22 @@ namespace Content.Server.Atmos.EntitySystems
return true; return true;
} }
private bool ProcessExcitedGroups(GridAtmosphereComponent atmosphere) private bool ProcessExcitedGroups(GridAtmosphereComponent gridAtmosphere)
{ {
if(!atmosphere.ProcessingPaused) if(!gridAtmosphere.ProcessingPaused)
atmosphere.CurrentRunExcitedGroups = new Queue<ExcitedGroup>(atmosphere.ExcitedGroups); gridAtmosphere.CurrentRunExcitedGroups = new Queue<ExcitedGroup>(gridAtmosphere.ExcitedGroups);
var number = 0; var number = 0;
while (atmosphere.CurrentRunExcitedGroups.TryDequeue(out var excitedGroup)) while (gridAtmosphere.CurrentRunExcitedGroups.TryDequeue(out var excitedGroup))
{ {
excitedGroup.BreakdownCooldown++; excitedGroup.BreakdownCooldown++;
excitedGroup.DismantleCooldown++; excitedGroup.DismantleCooldown++;
if(excitedGroup.BreakdownCooldown > Atmospherics.ExcitedGroupBreakdownCycles) if(excitedGroup.BreakdownCooldown > Atmospherics.ExcitedGroupBreakdownCycles)
excitedGroup.SelfBreakdown(this, ExcitedGroupsSpaceIsAllConsuming); ExcitedGroupSelfBreakdown(gridAtmosphere, excitedGroup, ExcitedGroupsSpaceIsAllConsuming);
else if(excitedGroup.DismantleCooldown > Atmospherics.ExcitedGroupsDismantleCycles) else if(excitedGroup.DismantleCooldown > Atmospherics.ExcitedGroupsDismantleCycles)
excitedGroup.Dismantle(); ExcitedGroupDismantle(gridAtmosphere, excitedGroup);
if (number++ < LagCheckIterations) continue; if (number++ < LagCheckIterations) continue;
number = 0; number = 0;
@@ -195,7 +204,7 @@ namespace Content.Server.Atmos.EntitySystems
atmosphere.CurrentRunAtmosDevices = new Queue<AtmosDeviceComponent>(atmosphere.AtmosDevices); atmosphere.CurrentRunAtmosDevices = new Queue<AtmosDeviceComponent>(atmosphere.AtmosDevices);
var time = _gameTiming.CurTime; var time = _gameTiming.CurTime;
var updateEvent = new AtmosDeviceUpdateEvent(atmosphere); var updateEvent = new AtmosDeviceUpdateEvent();
var number = 0; var number = 0;
while (atmosphere.CurrentRunAtmosDevices.TryDequeue(out var device)) while (atmosphere.CurrentRunAtmosDevices.TryDequeue(out var device))
{ {
@@ -237,8 +246,14 @@ namespace Content.Server.Atmos.EntitySystems
atmosphere.Timer += frameTime; atmosphere.Timer += frameTime;
if (atmosphere.InvalidatedCoords.Count != 0) if ((atmosphere.InvalidatedCoords.Count != 0 || atmosphere.RevalidatePaused) && TryGetMapGrid(atmosphere, out var mapGrid))
atmosphere.Revalidate(); if (!GridRevalidate(mapGrid, atmosphere))
{
atmosphere.RevalidatePaused = true;
return;
}
atmosphere.RevalidatePaused = false;
if (atmosphere.Timer < AtmosTime) if (atmosphere.Timer < AtmosTime)
continue; continue;

View File

@@ -48,21 +48,24 @@ namespace Content.Server.Atmos.EntitySystems
public bool ConsiderSuperconductivity(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile) public bool ConsiderSuperconductivity(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile)
{ {
if (tile.ThermalConductivity == 0f) if (tile.ThermalConductivity == 0f || !Superconduction)
return false; return false;
gridAtmosphere.AddSuperconductivityTile(tile); gridAtmosphere.SuperconductivityTiles.Add(tile);
return true; return true;
} }
public bool ConsiderSuperconductivity(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, bool starting) public bool ConsiderSuperconductivity(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, bool starting)
{ {
if (!Superconduction)
return false;
if (tile.Air == null || tile.Air.Temperature < (starting if (tile.Air == null || tile.Air.Temperature < (starting
? Atmospherics.MinimumTemperatureStartSuperConduction ? Atmospherics.MinimumTemperatureStartSuperConduction
: Atmospherics.MinimumTemperatureForSuperconduction)) : Atmospherics.MinimumTemperatureForSuperconduction))
return false; return false;
return !(gridAtmosphere.AtmosphereSystem.GetHeatCapacity(tile.Air) < Atmospherics.MCellWithRatio) return !(GetHeatCapacity(tile.Air) < Atmospherics.MCellWithRatio)
&& ConsiderSuperconductivity(gridAtmosphere, tile); && ConsiderSuperconductivity(gridAtmosphere, tile);
} }
@@ -82,7 +85,7 @@ namespace Content.Server.Atmos.EntitySystems
// Make sure it's still hot enough to continue conducting. // Make sure it's still hot enough to continue conducting.
if (temperature < Atmospherics.MinimumTemperatureForSuperconduction) if (temperature < Atmospherics.MinimumTemperatureForSuperconduction)
{ {
gridAtmosphere.RemoveSuperconductivityTile(tile); gridAtmosphere.SuperconductivityTiles.Remove(tile);
} }
} }
@@ -112,7 +115,7 @@ namespace Content.Server.Atmos.EntitySystems
TemperatureShareOpenToSolid(tile, other); TemperatureShareOpenToSolid(tile, other);
} }
gridAtmosphere.AddActiveTile(tile); AddActiveTile(gridAtmosphere, tile);
} }
private void TemperatureShareOpenToSolid(TileAtmosphere tile, TileAtmosphere other) private void TemperatureShareOpenToSolid(TileAtmosphere tile, TileAtmosphere other)

View File

@@ -3,19 +3,15 @@ using Content.Server.NodeContainer.EntitySystems;
using Content.Shared.Atmos.EntitySystems; using Content.Shared.Atmos.EntitySystems;
using Content.Shared.Maps; using Content.Shared.Maps;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Shared.Configuration;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Prototypes;
namespace Content.Server.Atmos.EntitySystems namespace Content.Server.Atmos.EntitySystems
{ {
[UsedImplicitly] [UsedImplicitly]
public partial class AtmosphereSystem : SharedAtmosphereSystem public partial class AtmosphereSystem : SharedAtmosphereSystem
{ {
[Dependency] private readonly IPrototypeManager _protoMan = default!;
[Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
private const float ExposedUpdateDelay = 1f; private const float ExposedUpdateDelay = 1f;
private float _exposedTimer = 0f; private float _exposedTimer = 0f;
@@ -28,6 +24,7 @@ namespace Content.Server.Atmos.EntitySystems
InitializeGases(); InitializeGases();
InitializeCVars(); InitializeCVars();
InitializeGrid();
#region Events #region Events
@@ -57,7 +54,7 @@ namespace Content.Server.Atmos.EntitySystems
return; return;
} }
GetGridAtmosphere(eventArgs.NewTile.GridIndex)?.Invalidate(eventArgs.NewTile.GridIndices); InvalidateTile(eventArgs.NewTile.GridIndex, eventArgs.NewTile.GridIndices);
} }
private void OnMapCreated(object? sender, MapEventArgs e) private void OnMapCreated(object? sender, MapEventArgs e)
@@ -84,8 +81,7 @@ namespace Content.Server.Atmos.EntitySystems
foreach (var exposed in EntityManager.ComponentManager.EntityQuery<AtmosExposedComponent>()) foreach (var exposed in EntityManager.ComponentManager.EntityQuery<AtmosExposedComponent>())
{ {
// TODO ATMOS: Kill this with fire. // TODO ATMOS: Kill this with fire.
var atmos = GetGridAtmosphere(exposed.Owner.Transform.Coordinates); var tile = GetTileAtmosphereOrCreateSpace(exposed.Owner.Transform.Coordinates);
var tile = atmos.GetTile(exposed.Owner.Transform.Coordinates);
if (tile == null) continue; if (tile == null) continue;
exposed.Update(tile, _exposedTimer, this); exposed.Update(tile, _exposedTimer, this);
} }

View File

@@ -144,14 +144,14 @@ namespace Content.Server.Atmos.EntitySystems
/// <summary> /// <summary>
/// Checks whether the overlay-relevant data for a gas tile has been updated. /// Checks whether the overlay-relevant data for a gas tile has been updated.
/// </summary> /// </summary>
/// <param name="gam"></param> /// <param name="grid"></param>
/// <param name="oldTile"></param> /// <param name="oldTile"></param>
/// <param name="indices"></param> /// <param name="indices"></param>
/// <param name="overlayData"></param> /// <param name="overlayData"></param>
/// <returns>true if updated</returns> /// <returns>true if updated</returns>
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) if (tile == null)
{ {
@@ -287,7 +287,7 @@ namespace Content.Server.Atmos.EntitySystems
{ {
var chunk = GetOrCreateChunk(gridId, invalid); 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)) if (!updatedTiles.TryGetValue(chunk, out var tiles))
{ {

View File

@@ -1,146 +1,16 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using Content.Server.Atmos.Components;
using Content.Server.Atmos.EntitySystems;
using Content.Shared.Atmos;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
namespace Content.Server.Atmos namespace Content.Server.Atmos
{ {
public class ExcitedGroup : IDisposable public class ExcitedGroup
{ {
[ViewVariables] [ViewVariables] public bool Disposed = false;
private bool _disposed = false;
[ViewVariables] [ViewVariables] public readonly List<TileAtmosphere> Tiles = new(100);
private readonly HashSet<TileAtmosphere> _tiles = new();
[ViewVariables] [ViewVariables] public int DismantleCooldown { get; set; } = 0;
private GridAtmosphereComponent _gridAtmosphereComponent = default!;
[ViewVariables] [ViewVariables] public int BreakdownCooldown { get; set; } = 0;
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!;
}
} }
} }

View File

@@ -1,6 +1,7 @@
using System; using System;
using Content.Server.Atmos.Components; using Content.Server.Atmos.Components;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
@@ -21,40 +22,18 @@ namespace Content.Server.Atmos.Piping.Components
[DataField("requireAnchored")] [DataField("requireAnchored")]
public bool RequireAnchored { get; private set; } = true; public bool RequireAnchored { get; private set; } = true;
public IGridAtmosphereComponent? Atmosphere { get; set; }
[ViewVariables] [ViewVariables]
public TimeSpan LastProcess { get; set; } = TimeSpan.Zero; public TimeSpan LastProcess { get; set; } = TimeSpan.Zero;
public GridId? JoinedGrid { get; set; }
} }
public abstract class BaseAtmosDeviceEvent : EntityEventArgs public sealed class AtmosDeviceUpdateEvent : EntityEventArgs
{ {}
public IGridAtmosphereComponent Atmosphere { get; }
public BaseAtmosDeviceEvent(IGridAtmosphereComponent atmosphere) public sealed class AtmosDeviceEnabledEvent : EntityEventArgs
{ {}
Atmosphere = atmosphere;
}
}
public sealed class AtmosDeviceUpdateEvent : BaseAtmosDeviceEvent public sealed class AtmosDeviceDisabledEvent : EntityEventArgs
{ {}
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)
{
}
}
} }

View File

@@ -20,13 +20,13 @@ namespace Content.Server.Atmos.Piping.EntitySystems
SubscribeLocalEvent<AtmosDeviceComponent, ComponentInit>(OnDeviceInitialize); SubscribeLocalEvent<AtmosDeviceComponent, ComponentInit>(OnDeviceInitialize);
SubscribeLocalEvent<AtmosDeviceComponent, ComponentShutdown>(OnDeviceShutdown); SubscribeLocalEvent<AtmosDeviceComponent, ComponentShutdown>(OnDeviceShutdown);
SubscribeLocalEvent<AtmosDeviceComponent, PhysicsBodyTypeChangedEvent>(OnDeviceBodyTypeChanged);
SubscribeLocalEvent<AtmosDeviceComponent, EntParentChangedMessage>(OnDeviceParentChanged); SubscribeLocalEvent<AtmosDeviceComponent, EntParentChangedMessage>(OnDeviceParentChanged);
SubscribeLocalEvent<AtmosDeviceComponent, AnchorStateChangedEvent>(OnDeviceAnchorChanged);
} }
private bool CanJoinAtmosphere(AtmosDeviceComponent component) 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) public void JoinAtmosphere(AtmosDeviceComponent component)
@@ -34,26 +34,22 @@ namespace Content.Server.Atmos.Piping.EntitySystems
if (!CanJoinAtmosphere(component)) if (!CanJoinAtmosphere(component))
return; return;
// We try to get a valid, simulated atmosphere. // We try to add the device to a valid atmosphere.
if (!Get<AtmosphereSystem>().TryGetSimulatedGridAtmosphere(component.Owner.Transform.MapPosition, out var atmosphere)) if (!Get<AtmosphereSystem>().AddAtmosDevice(component))
return; return;
component.LastProcess = _gameTiming.CurTime; 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) public void LeaveAtmosphere(AtmosDeviceComponent component)
{ {
var atmosphere = component.Atmosphere; if (!Get<AtmosphereSystem>().RemoveAtmosDevice(component))
atmosphere?.RemoveAtmosDevice(component); return;
component.Atmosphere = null;
component.LastProcess = TimeSpan.Zero;
if(atmosphere != null) component.LastProcess = TimeSpan.Zero;
RaiseLocalEvent(component.Owner.Uid, new AtmosDeviceDisabledEvent(atmosphere), false); RaiseLocalEvent(component.Owner.Uid, new AtmosDeviceDisabledEvent(), false);
} }
public void RejoinAtmosphere(AtmosDeviceComponent component) public void RejoinAtmosphere(AtmosDeviceComponent component)
@@ -72,13 +68,13 @@ namespace Content.Server.Atmos.Piping.EntitySystems
LeaveAtmosphere(component); 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. // Do nothing if the component doesn't require being anchored to function.
if (!component.RequireAnchored) if (!component.RequireAnchored)
return; return;
if (args.New == BodyType.Static) if(component.Owner.Transform.Anchored)
JoinAtmosphere(component); JoinAtmosphere(component);
else else
LeaveAtmosphere(component); LeaveAtmosphere(component);

View File

@@ -21,9 +21,8 @@ namespace Content.Server.Atmos.Reactions
var location = holder as TileAtmosphere; var location = holder as TileAtmosphere;
mixture.ReactionResults[GasReaction.Fire] = 0; mixture.ReactionResults[GasReaction.Fire] = 0;
// More plasma released at higher temperatures // More plasma released at higher temperatures.
var temperatureScale = 0f; var temperatureScale = 0f;
var superSaturation = false;
if (temperature > Atmospherics.PlasmaUpperTemperature) if (temperature > Atmospherics.PlasmaUpperTemperature)
temperatureScale = 1f; temperatureScale = 1f;
@@ -31,33 +30,31 @@ namespace Content.Server.Atmos.Reactions
temperatureScale = (temperature - Atmospherics.PlasmaMinimumBurnTemperature) / temperatureScale = (temperature - Atmospherics.PlasmaMinimumBurnTemperature) /
(Atmospherics.PlasmaUpperTemperature - Atmospherics.PlasmaMinimumBurnTemperature); (Atmospherics.PlasmaUpperTemperature - Atmospherics.PlasmaMinimumBurnTemperature);
if (temperatureScale > 0f) if (temperatureScale > 0)
{ {
var plasmaBurnRate = 0f;
var oxygenBurnRate = Atmospherics.OxygenBurnRateBase - temperatureScale; var oxygenBurnRate = Atmospherics.OxygenBurnRateBase - temperatureScale;
var plasmaBurnRate = 0f;
if (mixture.GetMoles(Gas.Oxygen) / mixture.GetMoles(Gas.Plasma) > var initialOxygenMoles = mixture.GetMoles(Gas.Oxygen);
Atmospherics.SuperSaturationThreshold) var initialPlasmaMoles = mixture.GetMoles(Gas.Plasma);
superSaturation = true;
if (mixture.GetMoles(Gas.Oxygen) > // Supersaturation makes tritium.
mixture.GetMoles(Gas.Plasma) * Atmospherics.PlasmaOxygenFullburn) var supersaturation = initialOxygenMoles / initialPlasmaMoles > Atmospherics.SuperSaturationThreshold;
plasmaBurnRate = (mixture.GetMoles(Gas.Plasma) * temperatureScale) /
Atmospherics.PlasmaBurnRateDelta; if (initialOxygenMoles > initialPlasmaMoles * Atmospherics.PlasmaOxygenFullburn)
plasmaBurnRate = initialPlasmaMoles * temperatureScale / Atmospherics.PlasmaBurnRateDelta;
else else
plasmaBurnRate = (temperatureScale * (mixture.GetMoles(Gas.Oxygen) / Atmospherics.PlasmaOxygenFullburn)) / Atmospherics.PlasmaBurnRateDelta; plasmaBurnRate = temperatureScale * (initialOxygenMoles / Atmospherics.PlasmaOxygenFullburn) / Atmospherics.PlasmaBurnRateDelta;
if (plasmaBurnRate > Atmospherics.MinimumHeatCapacity) if (plasmaBurnRate > Atmospherics.MinimumHeatCapacity)
{ {
plasmaBurnRate = MathF.Min(MathF.Min(plasmaBurnRate, mixture.GetMoles(Gas.Plasma)), mixture.GetMoles(Gas.Oxygen)/oxygenBurnRate); plasmaBurnRate = MathF.Min(plasmaBurnRate, MathF.Min(initialPlasmaMoles, initialOxygenMoles / oxygenBurnRate));
mixture.SetMoles(Gas.Plasma, mixture.GetMoles(Gas.Plasma) - plasmaBurnRate); mixture.SetMoles(Gas.Plasma, initialPlasmaMoles - plasmaBurnRate);
mixture.SetMoles(Gas.Oxygen, mixture.GetMoles(Gas.Oxygen) - (plasmaBurnRate * oxygenBurnRate)); 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); var newHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture);
if (newHeatCapacity > Atmospherics.MinimumHeatCapacity) if (newHeatCapacity > Atmospherics.MinimumHeatCapacity)
mixture.Temperature = ((temperature * oldHeatCapacity + energyReleased) / newHeatCapacity); mixture.Temperature = (temperature * oldHeatCapacity + energyReleased) / newHeatCapacity;
} }
if (location != null) if (location != null)
{ {
temperature = mixture.Temperature; var mixTemperature = mixture.Temperature;
if (temperature > Atmospherics.FireMinimumTemperatureToExist) 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 entity in location.GridIndices.GetEntitiesInTileFast(location.GridIndex))
{ {
foreach (var temperatureExpose in entity.GetAllComponents<ITemperatureExpose>()) foreach (var temperatureExpose in entity.GetAllComponents<ITemperatureExpose>())
{ {
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);
} }
} }

View File

@@ -1,7 +1,5 @@
#nullable disable warnings #nullable disable warnings
#nullable enable annotations #nullable enable annotations
using System.Runtime.CompilerServices;
using Content.Server.Atmos.Components;
using Content.Server.Interfaces; using Content.Server.Interfaces;
using Content.Shared.Atmos; using Content.Shared.Atmos;
using Content.Shared.Maps; using Content.Shared.Maps;
@@ -11,6 +9,9 @@ using Robust.Shared.ViewVariables;
namespace Content.Server.Atmos namespace Content.Server.Atmos
{ {
/// <summary>
/// Internal Atmos class that stores data about the atmosphere in a grid.
/// </summary>
public class TileAtmosphere : IGasMixtureHolder public class TileAtmosphere : IGasMixtureHolder
{ {
[ViewVariables] [ViewVariables]
@@ -40,9 +41,6 @@ namespace Content.Server.Atmos
[ViewVariables] [ViewVariables]
public bool Excited { get; set; } public bool Excited { get; set; }
[ViewVariables]
private readonly GridAtmosphereComponent _gridAtmosphereComponent;
/// <summary> /// <summary>
/// Adjacent tiles in the same order as <see cref="AtmosDirection"/>. (NSEW) /// Adjacent tiles in the same order as <see cref="AtmosDirection"/>. (NSEW)
/// </summary> /// </summary>
@@ -86,9 +84,8 @@ namespace Content.Server.Atmos
[ViewVariables] [ViewVariables]
public AtmosDirection BlockedAirflow { get; set; } = AtmosDirection.Invalid; 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; GridIndex = gridIndex;
GridIndices = gridIndices; GridIndices = gridIndices;
Air = mixture; Air = mixture;
@@ -96,47 +93,5 @@ namespace Content.Server.Atmos
if(immutable) if(immutable)
Air?.MarkImmutable(); 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;
}
}
} }
} }

View File

@@ -8,7 +8,9 @@ using Content.Server.Interfaces;
using Content.Server.NodeContainer.Nodes; using Content.Server.NodeContainer.Nodes;
using Content.Shared.Atmos; using Content.Shared.Atmos;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Maths; using Robust.Shared.Maths;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
namespace Content.Server.NodeContainer.NodeGroups namespace Content.Server.NodeContainer.NodeGroups
@@ -30,16 +32,14 @@ namespace Content.Server.NodeContainer.NodeGroups
[ViewVariables] private AtmosphereSystem? _atmosphereSystem; [ViewVariables] private AtmosphereSystem? _atmosphereSystem;
[ViewVariables] public GridId Grid => GridId;
private IGridAtmosphereComponent? GridAtmos =>
_atmosphereSystem?.GetGridAtmosphere(GridId);
public override void Initialize(Node sourceNode) public override void Initialize(Node sourceNode)
{ {
base.Initialize(sourceNode); base.Initialize(sourceNode);
_atmosphereSystem = EntitySystem.Get<AtmosphereSystem>(); _atmosphereSystem = EntitySystem.Get<AtmosphereSystem>();
GridAtmos?.AddPipeNet(this); _atmosphereSystem.AddPipeNet(this);
} }
public void Update() public void Update()
@@ -94,7 +94,8 @@ namespace Content.Server.NodeContainer.NodeGroups
private void RemoveFromGridAtmos() private void RemoveFromGridAtmos()
{ {
GridAtmos?.RemovePipeNet(this); DebugTools.AssertNotNull(_atmosphereSystem);
_atmosphereSystem?.RemovePipeNet(this);
} }
} }
} }