ECS Atmos Part 5: Moves all logic from GridAtmosphereComponent to AtmosphereSystem. (#4331)
This commit is contained in:
committed by
GitHub
parent
354ef6daf3
commit
4112847142
@@ -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<ExcitedGroup> ExcitedGroups = new(1000);
|
||||
|
||||
[ViewVariables]
|
||||
public int ExcitedGroupCount => ExcitedGroups.Count;
|
||||
|
||||
[DataField("uniqueMixes")]
|
||||
public List<GasMixture>? UniqueMixes;
|
||||
|
||||
@@ -73,6 +50,12 @@ namespace Content.Server.Atmos.Components
|
||||
[ViewVariables]
|
||||
public int ActiveTilesCount => ActiveTiles.Count;
|
||||
|
||||
[ViewVariables]
|
||||
public readonly HashSet<ExcitedGroup> ExcitedGroups = new(1000);
|
||||
|
||||
[ViewVariables]
|
||||
public int ExcitedGroupCount => ExcitedGroups.Count;
|
||||
|
||||
[ViewVariables]
|
||||
public readonly HashSet<TileAtmosphere> HotspotTiles = new(1000);
|
||||
|
||||
@@ -85,9 +68,6 @@ namespace Content.Server.Atmos.Components
|
||||
[ViewVariables]
|
||||
public int SuperconductivityTilesCount => SuperconductivityTiles.Count;
|
||||
|
||||
[ViewVariables]
|
||||
public readonly HashSet<Vector2i> InvalidatedCoords = new(1000);
|
||||
|
||||
[ViewVariables]
|
||||
public HashSet<TileAtmosphere> HighPressureDelta = new(1000);
|
||||
|
||||
@@ -112,22 +92,21 @@ namespace Content.Server.Atmos.Components
|
||||
[ViewVariables]
|
||||
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]
|
||||
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()
|
||||
{
|
||||
var uniqueMixes = new List<GasMixture>();
|
||||
@@ -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<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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<TileAtmosphere>
|
||||
public interface IGridAtmosphereComponent : IComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether this atmosphere is simulated or not.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<AirtightComponent> GetObstructingComponents(Vector2i indices)
|
||||
{
|
||||
return Enumerable.Empty<AirtightComponent>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,6 +127,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
AccumulatedFrameTime -= _updateCooldown;
|
||||
|
||||
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
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<GasReactionPrototype>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<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.
|
||||
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<TileAtmosphere>.Shared.Return(tiles);
|
||||
@@ -465,7 +467,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
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))
|
||||
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<TileAtmosphere>
|
||||
|
||||
@@ -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
|
||||
/// </summary>
|
||||
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 bool _simulationPaused = false;
|
||||
|
||||
@@ -30,10 +36,13 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
if(!atmosphere.ProcessingPaused)
|
||||
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;
|
||||
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<ExcitedGroup>(atmosphere.ExcitedGroups);
|
||||
if(!gridAtmosphere.ProcessingPaused)
|
||||
gridAtmosphere.CurrentRunExcitedGroups = new Queue<ExcitedGroup>(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<AtmosDeviceComponent>(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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<AtmosExposedComponent>())
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
|
||||
@@ -144,14 +144,14 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
/// <summary>
|
||||
/// Checks whether the overlay-relevant data for a gas tile has been updated.
|
||||
/// </summary>
|
||||
/// <param name="gam"></param>
|
||||
/// <param name="grid"></param>
|
||||
/// <param name="oldTile"></param>
|
||||
/// <param name="indices"></param>
|
||||
/// <param name="overlayData"></param>
|
||||
/// <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)
|
||||
{
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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<TileAtmosphere> _tiles = new();
|
||||
[ViewVariables] public readonly List<TileAtmosphere> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{}
|
||||
}
|
||||
|
||||
@@ -20,13 +20,13 @@ namespace Content.Server.Atmos.Piping.EntitySystems
|
||||
|
||||
SubscribeLocalEvent<AtmosDeviceComponent, ComponentInit>(OnDeviceInitialize);
|
||||
SubscribeLocalEvent<AtmosDeviceComponent, ComponentShutdown>(OnDeviceShutdown);
|
||||
SubscribeLocalEvent<AtmosDeviceComponent, PhysicsBodyTypeChangedEvent>(OnDeviceBodyTypeChanged);
|
||||
SubscribeLocalEvent<AtmosDeviceComponent, EntParentChangedMessage>(OnDeviceParentChanged);
|
||||
SubscribeLocalEvent<AtmosDeviceComponent, AnchorStateChangedEvent>(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<AtmosphereSystem>().TryGetSimulatedGridAtmosphere(component.Owner.Transform.MapPosition, out var atmosphere))
|
||||
// We try to add the device to a valid atmosphere.
|
||||
if (!Get<AtmosphereSystem>().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<AtmosphereSystem>().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);
|
||||
|
||||
@@ -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<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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Internal Atmos class that stores data about the atmosphere in a grid.
|
||||
/// </summary>
|
||||
public class TileAtmosphere : IGasMixtureHolder
|
||||
{
|
||||
[ViewVariables]
|
||||
@@ -40,9 +41,6 @@ namespace Content.Server.Atmos
|
||||
[ViewVariables]
|
||||
public bool Excited { get; set; }
|
||||
|
||||
[ViewVariables]
|
||||
private readonly GridAtmosphereComponent _gridAtmosphereComponent;
|
||||
|
||||
/// <summary>
|
||||
/// Adjacent tiles in the same order as <see cref="AtmosDirection"/>. (NSEW)
|
||||
/// </summary>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<AtmosphereSystem>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user