Merge branch 'master' into replace-sounds-with-sound-specifier
This commit is contained in:
@@ -47,7 +47,7 @@ namespace Content.Server.Atmos.Commands
|
||||
return;
|
||||
}
|
||||
|
||||
if (grid.HasComponent<IGridAtmosphereComponent>())
|
||||
if (grid.HasComponent<IAtmosphereComponent>())
|
||||
{
|
||||
shell.WriteLine("Grid already has an atmosphere.");
|
||||
return;
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace Content.Server.Atmos.Commands
|
||||
return;
|
||||
}
|
||||
|
||||
if (grid.HasComponent<IGridAtmosphereComponent>())
|
||||
if (grid.HasComponent<IAtmosphereComponent>())
|
||||
{
|
||||
shell.WriteLine("Grid already has an atmosphere.");
|
||||
return;
|
||||
|
||||
@@ -23,23 +23,20 @@ namespace Content.Server.Atmos.Components
|
||||
[ViewVariables]
|
||||
[ComponentDependency] private readonly FlammableComponent? _flammableComponent = null;
|
||||
|
||||
public void Update(TileAtmosphere tile, float frameDelta, AtmosphereSystem atmosphereSystem)
|
||||
public void Update(GasMixture air, float frameDelta, AtmosphereSystem atmosphereSystem)
|
||||
{
|
||||
if (_temperatureComponent != null)
|
||||
{
|
||||
if (tile.Air != null)
|
||||
{
|
||||
var temperatureDelta = tile.Air.Temperature - _temperatureComponent.CurrentTemperature;
|
||||
var tileHeatCapacity = atmosphereSystem.GetHeatCapacity(tile.Air);
|
||||
var heat = temperatureDelta * (tileHeatCapacity * _temperatureComponent.HeatCapacity / (tileHeatCapacity + _temperatureComponent.HeatCapacity));
|
||||
_temperatureComponent.ReceiveHeat(heat);
|
||||
}
|
||||
var temperatureDelta = air.Temperature - _temperatureComponent.CurrentTemperature;
|
||||
var tileHeatCapacity = atmosphereSystem.GetHeatCapacity(air);
|
||||
var heat = temperatureDelta * (tileHeatCapacity * _temperatureComponent.HeatCapacity / (tileHeatCapacity + _temperatureComponent.HeatCapacity));
|
||||
_temperatureComponent.ReceiveHeat(heat);
|
||||
_temperatureComponent.Update();
|
||||
}
|
||||
|
||||
_barotraumaComponent?.Update(tile.Air?.Pressure ?? 0);
|
||||
_barotraumaComponent?.Update(air.Pressure);
|
||||
|
||||
_flammableComponent?.Update(tile);
|
||||
_flammableComponent?.Update(air);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Doors;
|
||||
using Content.Server.Doors.Components;
|
||||
using Content.Shared.Doors;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Notification.Managers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Localization;
|
||||
|
||||
namespace Content.Server.Atmos.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Companion component to ServerDoorComponent that handles firelock-specific behavior -- primarily prying, and not being openable on open-hand click.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(IDoorCheck))]
|
||||
public class FirelockComponent : Component, IDoorCheck
|
||||
{
|
||||
public override string Name => "Firelock";
|
||||
|
||||
[ComponentDependency]
|
||||
private readonly ServerDoorComponent? _doorComponent = null;
|
||||
|
||||
public bool EmergencyPressureStop()
|
||||
{
|
||||
if (_doorComponent != null && _doorComponent.State == SharedDoorComponent.DoorState.Open && _doorComponent.CanCloseGeneric())
|
||||
{
|
||||
_doorComponent.Close();
|
||||
if (Owner.TryGetComponent(out AirtightComponent? airtight))
|
||||
{
|
||||
EntitySystem.Get<AirtightSystem>().SetAirblocked(airtight, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IDoorCheck.OpenCheck()
|
||||
{
|
||||
return !IsHoldingFire() && !IsHoldingPressure();
|
||||
}
|
||||
|
||||
bool IDoorCheck.DenyCheck() => false;
|
||||
|
||||
float? IDoorCheck.GetPryTime()
|
||||
{
|
||||
if (IsHoldingFire() || IsHoldingPressure())
|
||||
{
|
||||
return 1.5f;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
bool IDoorCheck.BlockActivate(ActivateEventArgs eventArgs) => true;
|
||||
|
||||
void IDoorCheck.OnStartPry(InteractUsingEventArgs eventArgs)
|
||||
{
|
||||
if (_doorComponent == null || _doorComponent.State != SharedDoorComponent.DoorState.Closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsHoldingPressure())
|
||||
{
|
||||
Owner.PopupMessage(eventArgs.User, Loc.GetString("firelock-component-is-holding-pressure-message"));
|
||||
}
|
||||
else if (IsHoldingFire())
|
||||
{
|
||||
Owner.PopupMessage(eventArgs.User, Loc.GetString("firelock-component-is-holding-fire-message"));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsHoldingPressure(float threshold = 20)
|
||||
{
|
||||
var atmosphereSystem = EntitySystem.Get<AtmosphereSystem>();
|
||||
|
||||
var minMoles = float.MaxValue;
|
||||
var maxMoles = 0f;
|
||||
|
||||
foreach (var adjacent in atmosphereSystem.GetAdjacentTileMixtures(Owner.Transform.Coordinates))
|
||||
{
|
||||
var moles = adjacent.TotalMoles;
|
||||
if (moles < minMoles)
|
||||
minMoles = moles;
|
||||
if (moles > maxMoles)
|
||||
maxMoles = moles;
|
||||
}
|
||||
|
||||
return (maxMoles - minMoles) > threshold;
|
||||
}
|
||||
|
||||
public bool IsHoldingFire()
|
||||
{
|
||||
var atmosphereSystem = EntitySystem.Get<AtmosphereSystem>();
|
||||
|
||||
if (!atmosphereSystem.TryGetGridAndTile(Owner.Transform.Coordinates, out var tuple))
|
||||
return false;
|
||||
|
||||
if (atmosphereSystem.GetTileMixture(tuple.Value.Grid, tuple.Value.Tile) == null)
|
||||
return false;
|
||||
|
||||
if (atmosphereSystem.IsHotspotActive(tuple.Value.Grid, tuple.Value.Tile))
|
||||
return true;
|
||||
|
||||
foreach (var adjacent in atmosphereSystem.GetAdjacentTiles(Owner.Transform.Coordinates))
|
||||
{
|
||||
if (atmosphereSystem.IsHotspotActive(tuple.Value.Grid, adjacent))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,7 +63,7 @@ namespace Content.Server.Atmos.Components
|
||||
UpdateAppearance();
|
||||
}
|
||||
|
||||
public void Update(TileAtmosphere tile)
|
||||
public void Update(GasMixture air)
|
||||
{
|
||||
// Slowly dry ourselves off if wet.
|
||||
if (FireStacks < 0)
|
||||
@@ -104,13 +104,13 @@ namespace Content.Server.Atmos.Components
|
||||
}
|
||||
|
||||
// If we're in an oxygenless environment, put the fire out.
|
||||
if (tile.Air?.GetMoles(Gas.Oxygen) < 1f)
|
||||
if (air.GetMoles(Gas.Oxygen) < 1f)
|
||||
{
|
||||
Extinguish();
|
||||
return;
|
||||
}
|
||||
|
||||
EntitySystem.Get<AtmosphereSystem>().HotspotExpose(tile.GridIndex, tile.GridIndices, 700f, 50f, true);
|
||||
EntitySystem.Get<AtmosphereSystem>().HotspotExpose(Owner.Transform.Coordinates, 700f, 50f, true);
|
||||
|
||||
var physics = Owner.GetComponent<IPhysBody>();
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#nullable disable warnings
|
||||
using System;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Body.Respiratory;
|
||||
|
||||
@@ -14,13 +14,14 @@ using Dependency = Robust.Shared.IoC.DependencyAttribute;
|
||||
namespace Content.Server.Atmos.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// This is our SSAir equivalent.
|
||||
/// Internal Atmos class. Use <see cref="AtmosphereSystem"/> to interact with atmos instead.
|
||||
/// </summary>
|
||||
[ComponentReference(typeof(IGridAtmosphereComponent))]
|
||||
[ComponentReference(typeof(IAtmosphereComponent))]
|
||||
[RegisterComponent, Serializable]
|
||||
public class GridAtmosphereComponent : Component, IGridAtmosphereComponent, ISerializationHooks
|
||||
public class GridAtmosphereComponent : Component, IAtmosphereComponent, ISerializationHooks
|
||||
{
|
||||
public override string Name => "GridAtmosphere";
|
||||
|
||||
public virtual bool Simulated => true;
|
||||
|
||||
[ViewVariables]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Content.Server.Atmos.Components
|
||||
{
|
||||
public interface IGridAtmosphereComponent : IComponent
|
||||
public interface IAtmosphereComponent : IComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether this atmosphere is simulated or not.
|
||||
13
Content.Server/Atmos/Components/SpaceAtmosphereComponent.cs
Normal file
13
Content.Server/Atmos/Components/SpaceAtmosphereComponent.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.Atmos.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(IAtmosphereComponent))]
|
||||
public class SpaceAtmosphereComponent : Component, IAtmosphereComponent
|
||||
{
|
||||
public override string Name => "SpaceAtmosphere";
|
||||
|
||||
public bool Simulated => false;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Shared.Atmos;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.Server.Atmos.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(IGridAtmosphereComponent))]
|
||||
public class SpaceGridAtmosphereComponent : UnsimulatedGridAtmosphereComponent
|
||||
{
|
||||
public override string Name => "SpaceGridAtmosphere";
|
||||
}
|
||||
}
|
||||
@@ -8,10 +8,9 @@ using Robust.Shared.Maths;
|
||||
namespace Content.Server.Atmos.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(IGridAtmosphereComponent))]
|
||||
[ComponentReference(typeof(GridAtmosphereComponent))]
|
||||
[ComponentReference(typeof(IAtmosphereComponent))]
|
||||
[Serializable]
|
||||
public class UnsimulatedGridAtmosphereComponent : GridAtmosphereComponent, IGridAtmosphereComponent
|
||||
public class UnsimulatedGridAtmosphereComponent : GridAtmosphereComponent
|
||||
{
|
||||
public override string Name => "UnsimulatedGridAtmosphere";
|
||||
|
||||
|
||||
@@ -117,6 +117,10 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
/// <returns>All tile mixtures in a grid.</returns>
|
||||
public IEnumerable<GasMixture> GetAllTileMixtures(GridId grid, bool invalidate = false)
|
||||
{
|
||||
// Return an array with a single space gas mixture for invalid grids.
|
||||
if (!grid.IsValid())
|
||||
return new []{ GasMixture.SpaceGas };
|
||||
|
||||
if (!_mapManager.TryGetGrid(grid, out var mapGrid))
|
||||
return Enumerable.Empty<GasMixture>();
|
||||
|
||||
@@ -666,7 +670,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
public GasMixture? GetTileMixture(EntityCoordinates coordinates, bool invalidate = false)
|
||||
{
|
||||
return TryGetGridAndTile(coordinates, out var tuple)
|
||||
? GetTileMixture(tuple.Value.Grid, tuple.Value.Tile, invalidate) : null;
|
||||
? GetTileMixture(tuple.Value.Grid, tuple.Value.Tile, invalidate) : GasMixture.SpaceGas;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -678,6 +682,10 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
/// <returns>The tile mixture, or null</returns>
|
||||
public GasMixture? GetTileMixture(GridId grid, Vector2i tile, bool invalidate = false)
|
||||
{
|
||||
// Always return space gas mixtures for invalid grids (grid 0)
|
||||
if (!grid.IsValid())
|
||||
return GasMixture.SpaceGas;
|
||||
|
||||
if (!_mapManager.TryGetGrid(grid, out var mapGrid))
|
||||
return null;
|
||||
|
||||
@@ -686,7 +694,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
return GetTileMixture(gridAtmosphere, tile, invalidate);
|
||||
}
|
||||
|
||||
if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out SpaceGridAtmosphereComponent? spaceAtmosphere))
|
||||
if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out SpaceAtmosphereComponent? _))
|
||||
{
|
||||
// Always return a new space gas mixture in this case.
|
||||
return GasMixture.SpaceGas;
|
||||
@@ -967,6 +975,10 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
/// <returns>All adjacent tile gas mixtures to the tile in question</returns>
|
||||
public IEnumerable<GasMixture> GetAdjacentTileMixtures(GridId grid, Vector2i tile, bool includeBlocked = false, bool invalidate = false)
|
||||
{
|
||||
// For invalid grids, return an array with a single space gas mixture in it.
|
||||
if (!grid.IsValid())
|
||||
return new []{ GasMixture.SpaceGas };
|
||||
|
||||
if (!_mapManager.TryGetGrid(grid, out var mapGrid))
|
||||
return Enumerable.Empty<GasMixture>();
|
||||
|
||||
@@ -1374,7 +1386,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
return false;
|
||||
|
||||
if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere)
|
||||
&& gridAtmosphere.AtmosDevices.Contains(atmosDevice))
|
||||
&& gridAtmosphere.AtmosDevices.Contains(atmosDevice))
|
||||
{
|
||||
atmosDevice.JoinedGrid = null;
|
||||
gridAtmosphere.AtmosDevices.Remove(atmosDevice);
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
#nullable disable warnings
|
||||
#nullable enable annotations
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Atmos.Reactions;
|
||||
using Content.Server.Coordinates.Helpers;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Maps;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Server.Atmos.EntitySystems
|
||||
{
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#nullable disable warnings
|
||||
#nullable enable annotations
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Shared.Atmos;
|
||||
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
#nullable disable warnings
|
||||
#nullable enable annotations
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Coordinates.Helpers;
|
||||
using Content.Server.Doors.Components;
|
||||
using Content.Shared.Atmos;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Atmos.EntitySystems
|
||||
{
|
||||
@@ -20,7 +18,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
|
||||
private readonly TileAtmosphereComparer _monstermosComparer = new();
|
||||
|
||||
private readonly TileAtmosphere[] _equalizeTiles = new TileAtmosphere[Atmospherics.MonstermosHardTileLimit];
|
||||
private readonly TileAtmosphere?[] _equalizeTiles = new TileAtmosphere[Atmospherics.MonstermosHardTileLimit];
|
||||
private readonly TileAtmosphere[] _equalizeGiverTiles = new TileAtmosphere[Atmospherics.MonstermosTileLimit];
|
||||
private readonly TileAtmosphere[] _equalizeTakerTiles = new TileAtmosphere[Atmospherics.MonstermosTileLimit];
|
||||
private readonly TileAtmosphere[] _equalizeQueue = new TileAtmosphere[Atmospherics.MonstermosTileLimit];
|
||||
@@ -28,7 +26,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
private readonly TileAtmosphere[] _depressurizeSpaceTiles = new TileAtmosphere[Atmospherics.MonstermosHardTileLimit];
|
||||
private readonly TileAtmosphere[] _depressurizeProgressionOrder = new TileAtmosphere[Atmospherics.MonstermosHardTileLimit * 2];
|
||||
|
||||
public void EqualizePressureInZone(IMapGrid mapGrid, GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, int cycleNum)
|
||||
private void EqualizePressureInZone(IMapGrid mapGrid, GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, int cycleNum)
|
||||
{
|
||||
if (tile.Air == null || (tile.MonstermosInfo.LastCycle >= cycleNum))
|
||||
return; // Already done.
|
||||
@@ -65,11 +63,12 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
for (var i = 0; i < tileCount; i++)
|
||||
{
|
||||
if (i > Atmospherics.MonstermosHardTileLimit) break;
|
||||
var exploring = _equalizeTiles[i];
|
||||
var exploring = _equalizeTiles[i]!;
|
||||
|
||||
if (i < Atmospherics.MonstermosTileLimit)
|
||||
{
|
||||
var tileMoles = exploring.Air.TotalMoles;
|
||||
// Tiles in the _equalizeTiles array cannot have null air.
|
||||
var tileMoles = exploring.Air!.TotalMoles;
|
||||
exploring.MonstermosInfo.MoleDelta = tileMoles;
|
||||
totalMoles += tileMoles;
|
||||
}
|
||||
@@ -106,7 +105,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
if (otherTile == null)
|
||||
continue;
|
||||
|
||||
_equalizeTiles[i].MonstermosInfo.LastQueueCycle = 0;
|
||||
otherTile.MonstermosInfo.LastQueueCycle = 0;
|
||||
}
|
||||
|
||||
tileCount = Atmospherics.MonstermosTileLimit;
|
||||
@@ -118,7 +117,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
|
||||
for (var i = 0; i < tileCount; i++)
|
||||
{
|
||||
var otherTile = _equalizeTiles[i];
|
||||
var otherTile = _equalizeTiles[i]!;
|
||||
otherTile.MonstermosInfo.LastCycle = cycleNum;
|
||||
otherTile.MonstermosInfo.MoleDelta -= averageMoles;
|
||||
if (otherTile.MonstermosInfo.MoleDelta > 0)
|
||||
@@ -133,7 +132,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
|
||||
var logN = MathF.Log2(tileCount);
|
||||
|
||||
// Optimization - try to spread gases using an O(nlogn) algorithm that has a chance of not working first to avoid O(n^2)
|
||||
// Optimization - try to spread gases using an O(n log n) algorithm that has a chance of not working first to avoid O(n^2)
|
||||
if (giverTilesLength > logN && takerTilesLength > logN)
|
||||
{
|
||||
// Even if it fails, it will speed up the next part.
|
||||
@@ -141,7 +140,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
|
||||
for (var i = 0; i < tileCount; i++)
|
||||
{
|
||||
var otherTile = _equalizeTiles[i];
|
||||
var otherTile = _equalizeTiles[i]!;
|
||||
otherTile.MonstermosInfo.FastDone = true;
|
||||
if (!(otherTile.MonstermosInfo.MoleDelta > 0)) continue;
|
||||
var eligibleDirections = AtmosDirection.Invalid;
|
||||
@@ -150,7 +149,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
{
|
||||
var direction = (AtmosDirection) (1 << j);
|
||||
if (!otherTile.AdjacentBits.IsFlagSet(direction)) continue;
|
||||
var tile2 = otherTile.AdjacentTiles[j];
|
||||
var tile2 = otherTile.AdjacentTiles[j]!;
|
||||
|
||||
// skip anything that isn't part of our current processing block.
|
||||
if (tile2.MonstermosInfo.FastDone || tile2.MonstermosInfo.LastQueueCycle != queueCycle)
|
||||
@@ -171,7 +170,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
|
||||
AdjustEqMovement(otherTile, direction, molesToMove);
|
||||
otherTile.MonstermosInfo.MoleDelta -= molesToMove;
|
||||
otherTile.AdjacentTiles[j].MonstermosInfo.MoleDelta += molesToMove;
|
||||
otherTile.AdjacentTiles[j]!.MonstermosInfo.MoleDelta += molesToMove;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +179,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
|
||||
for (var i = 0; i < tileCount; i++)
|
||||
{
|
||||
var otherTile = _equalizeTiles[i];
|
||||
var otherTile = _equalizeTiles[i]!;
|
||||
if (otherTile.MonstermosInfo.MoleDelta > 0)
|
||||
{
|
||||
_equalizeGiverTiles[giverTilesLength++] = otherTile;
|
||||
@@ -252,7 +251,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
if (otherTile.MonstermosInfo.CurrentTransferAmount != 0 && otherTile.MonstermosInfo.CurrentTransferDirection != AtmosDirection.Invalid)
|
||||
{
|
||||
AdjustEqMovement(otherTile, otherTile.MonstermosInfo.CurrentTransferDirection, otherTile.MonstermosInfo.CurrentTransferAmount);
|
||||
otherTile.AdjacentTiles[otherTile.MonstermosInfo.CurrentTransferDirection.ToIndex()]
|
||||
otherTile.AdjacentTiles[otherTile.MonstermosInfo.CurrentTransferDirection.ToIndex()]!
|
||||
.MonstermosInfo.CurrentTransferAmount += otherTile.MonstermosInfo.CurrentTransferAmount;
|
||||
otherTile.MonstermosInfo.CurrentTransferAmount = 0;
|
||||
}
|
||||
@@ -319,7 +318,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
|
||||
AdjustEqMovement(otherTile, otherTile.MonstermosInfo.CurrentTransferDirection, otherTile.MonstermosInfo.CurrentTransferAmount);
|
||||
|
||||
otherTile.AdjacentTiles[otherTile.MonstermosInfo.CurrentTransferDirection.ToIndex()]
|
||||
otherTile.AdjacentTiles[otherTile.MonstermosInfo.CurrentTransferDirection.ToIndex()]!
|
||||
.MonstermosInfo.CurrentTransferAmount += otherTile.MonstermosInfo.CurrentTransferAmount;
|
||||
otherTile.MonstermosInfo.CurrentTransferAmount = 0;
|
||||
}
|
||||
@@ -328,19 +327,19 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
|
||||
for (var i = 0; i < tileCount; i++)
|
||||
{
|
||||
var otherTile = _equalizeTiles[i];
|
||||
var otherTile = _equalizeTiles[i]!;
|
||||
FinalizeEq(gridAtmosphere, otherTile);
|
||||
}
|
||||
|
||||
for (var i = 0; i < tileCount; i++)
|
||||
{
|
||||
var otherTile = _equalizeTiles[i];
|
||||
var otherTile = _equalizeTiles[i]!;
|
||||
for (var j = 0; j < Atmospherics.Directions; j++)
|
||||
{
|
||||
var direction = (AtmosDirection) (1 << j);
|
||||
if (!otherTile.AdjacentBits.IsFlagSet(direction)) continue;
|
||||
var otherTile2 = otherTile.AdjacentTiles[j];
|
||||
if (otherTile2?.Air?.Compare(tile.Air) == GasMixture.GasCompareResult.NoExchange) continue;
|
||||
var otherTile2 = otherTile.AdjacentTiles[j]!;
|
||||
if (otherTile2.Air?.Compare(tile.Air) == GasMixture.GasCompareResult.NoExchange) continue;
|
||||
AddActiveTile(gridAtmosphere, otherTile2);
|
||||
break;
|
||||
}
|
||||
@@ -353,7 +352,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
Array.Clear(_equalizeQueue, 0, Atmospherics.MonstermosTileLimit);
|
||||
}
|
||||
|
||||
public void ExplosivelyDepressurize(IMapGrid mapGrid, GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, int cycleNum)
|
||||
private 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)
|
||||
@@ -376,7 +375,8 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
var otherTile = _depressurizeTiles[i];
|
||||
otherTile.MonstermosInfo.LastCycle = cycleNum;
|
||||
otherTile.MonstermosInfo.CurrentTransferDirection = AtmosDirection.Invalid;
|
||||
if (otherTile.Air.Immutable)
|
||||
// Tiles in the _depressurizeTiles array cannot have null air.
|
||||
if (otherTile.Air!.Immutable)
|
||||
{
|
||||
_depressurizeSpaceTiles[spaceTileCount++] = otherTile;
|
||||
otherTile.PressureSpecificTarget = otherTile;
|
||||
@@ -388,7 +388,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
var direction = (AtmosDirection) (1 << j);
|
||||
if (!otherTile.AdjacentBits.IsFlagSet(direction)) continue;
|
||||
var otherTile2 = otherTile.AdjacentTiles[j];
|
||||
if (otherTile2.Air == null) continue;
|
||||
if (otherTile2?.Air == null) continue;
|
||||
if (otherTile2.MonstermosInfo.LastQueueCycle == queueCycle) continue;
|
||||
|
||||
ConsiderFirelocks(gridAtmosphere, otherTile, otherTile2);
|
||||
@@ -421,8 +421,8 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
for (var j = 0; j < Atmospherics.Directions; j++)
|
||||
{
|
||||
var direction = (AtmosDirection) (1 << j);
|
||||
// TODO ATMOS This is a terrible hack that accounts for the mess that are space TileAtmospheres.
|
||||
if (!otherTile.AdjacentBits.IsFlagSet(direction) && !otherTile.Air.Immutable) continue;
|
||||
// Tiles in _depressurizeProgressionOrder cannot have null air.
|
||||
if (!otherTile.AdjacentBits.IsFlagSet(direction) && !otherTile.Air!.Immutable) continue;
|
||||
var tile2 = otherTile.AdjacentTiles[j];
|
||||
if (tile2?.MonstermosInfo.LastQueueCycle != queueCycle) continue;
|
||||
if (tile2.MonstermosInfo.LastSlowQueueCycle == queueCycleSlow) continue;
|
||||
@@ -509,7 +509,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
InvalidateVisuals(other.GridIndex, other.GridIndices);
|
||||
}
|
||||
|
||||
public void FinalizeEq(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile)
|
||||
private void FinalizeEq(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile)
|
||||
{
|
||||
Span<float> transferDirections = stackalloc float[Atmospherics.Directions];
|
||||
var hasTransferDirs = false;
|
||||
@@ -533,7 +533,8 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
if (otherTile?.Air == null) continue;
|
||||
if (amount > 0)
|
||||
{
|
||||
if (tile.Air.TotalMoles < amount)
|
||||
// Everything that calls this method already ensures that Air will not be null.
|
||||
if (tile.Air!.TotalMoles < amount)
|
||||
FinalizeEqNeighbors(gridAtmosphere, tile, transferDirections);
|
||||
|
||||
otherTile.MonstermosInfo[direction.GetOpposite()] = 0;
|
||||
@@ -551,15 +552,19 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
{
|
||||
var direction = (AtmosDirection) (1 << i);
|
||||
var amount = transferDirs[i];
|
||||
// Since AdjacentBits is set, AdjacentTiles[i] wouldn't be null, and neither would its air.
|
||||
if(amount < 0 && tile.AdjacentBits.IsFlagSet(direction))
|
||||
FinalizeEq(gridAtmosphere, tile.AdjacentTiles[i]); // A bit of recursion if needed.
|
||||
FinalizeEq(gridAtmosphere, tile.AdjacentTiles[i]!); // A bit of recursion if needed.
|
||||
}
|
||||
}
|
||||
|
||||
private void AdjustEqMovement(TileAtmosphere tile, AtmosDirection direction, float amount)
|
||||
{
|
||||
DebugTools.Assert(tile.AdjacentBits.HasFlag(direction));
|
||||
DebugTools.Assert(tile.AdjacentTiles[direction.ToIndex()] != null);
|
||||
tile.MonstermosInfo[direction] += amount;
|
||||
tile.AdjacentTiles[direction.ToIndex()].MonstermosInfo[direction.GetOpposite()] -= amount;
|
||||
// Every call to this method already ensures that the adjacent tile won't be null.
|
||||
tile.AdjacentTiles[direction.ToIndex()]!.MonstermosInfo[direction.GetOpposite()] -= amount;
|
||||
}
|
||||
|
||||
private void HandleDecompressionFloorRip(IMapGrid mapGrid, TileAtmosphere tile, float sum)
|
||||
@@ -573,9 +578,9 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
PryTile(mapGrid, tile.GridIndices);
|
||||
}
|
||||
|
||||
private class TileAtmosphereComparer : IComparer<TileAtmosphere>
|
||||
private class TileAtmosphereComparer : IComparer<TileAtmosphere?>
|
||||
{
|
||||
public int Compare(TileAtmosphere a, TileAtmosphere b)
|
||||
public int Compare(TileAtmosphere? a, TileAtmosphere? b)
|
||||
{
|
||||
if (a == null && b == null)
|
||||
return 0;
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
|
||||
private readonly AtmosDeviceUpdateEvent _updateEvent = new();
|
||||
private readonly Stopwatch _simulationStopwatch = new();
|
||||
|
||||
/// <summary>
|
||||
@@ -204,11 +205,10 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
atmosphere.CurrentRunAtmosDevices = new Queue<AtmosDeviceComponent>(atmosphere.AtmosDevices);
|
||||
|
||||
var time = _gameTiming.CurTime;
|
||||
var updateEvent = new AtmosDeviceUpdateEvent();
|
||||
var number = 0;
|
||||
while (atmosphere.CurrentRunAtmosDevices.TryDequeue(out var device))
|
||||
{
|
||||
EntityManager.EventBus.RaiseLocalEvent(device.Owner.Uid, updateEvent, false);
|
||||
RaiseLocalEvent(device.Owner.Uid, _updateEvent, false);
|
||||
device.LastProcess = time;
|
||||
|
||||
if (number++ < LagCheckIterations) continue;
|
||||
@@ -241,7 +241,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
{
|
||||
var atmosphere = _currentRunAtmosphere[_currentRunAtmosphereIndex];
|
||||
|
||||
if (atmosphere.Paused || atmosphere.LifeStage >= ComponentLifeStage.Stopping)
|
||||
if (atmosphere.Paused || !atmosphere.Simulated || atmosphere.LifeStage >= ComponentLifeStage.Stopping)
|
||||
continue;
|
||||
|
||||
atmosphere.Timer += frameTime;
|
||||
|
||||
@@ -8,6 +8,9 @@ using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Server.Atmos.EntitySystems
|
||||
{
|
||||
/// <summary>
|
||||
/// This is our SSAir equivalent, if you need to interact with or query atmos in any way, go through this.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public partial class AtmosphereSystem : SharedAtmosphereSystem
|
||||
{
|
||||
@@ -29,7 +32,6 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
#region Events
|
||||
|
||||
// Map events.
|
||||
_mapManager.MapCreated += OnMapCreated;
|
||||
_mapManager.TileChanged += OnTileChanged;
|
||||
|
||||
#endregion
|
||||
@@ -39,7 +41,6 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
{
|
||||
base.Shutdown();
|
||||
|
||||
_mapManager.MapCreated -= OnMapCreated;
|
||||
_mapManager.TileChanged -= OnTileChanged;
|
||||
}
|
||||
|
||||
@@ -57,17 +58,6 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
InvalidateTile(eventArgs.NewTile.GridIndex, eventArgs.NewTile.GridIndices);
|
||||
}
|
||||
|
||||
private void OnMapCreated(object? sender, MapEventArgs e)
|
||||
{
|
||||
if (e.Map == MapId.Nullspace)
|
||||
return;
|
||||
|
||||
var map = _mapManager.GetMapEntity(e.Map);
|
||||
|
||||
if (!map.HasComponent<IGridAtmosphereComponent>())
|
||||
map.AddComponent<SpaceGridAtmosphereComponent>();
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
@@ -81,7 +71,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
foreach (var exposed in EntityManager.ComponentManager.EntityQuery<AtmosExposedComponent>())
|
||||
{
|
||||
// TODO ATMOS: Kill this with fire.
|
||||
var tile = GetTileAtmosphereOrCreateSpace(exposed.Owner.Transform.Coordinates);
|
||||
var tile = GetTileMixture(exposed.Owner.Transform.Coordinates);
|
||||
if (tile == null) continue;
|
||||
exposed.Update(tile, _exposedTimer, this);
|
||||
}
|
||||
|
||||
@@ -6,20 +6,5 @@ namespace Content.Server.Atmos
|
||||
public interface IGasMixtureHolder
|
||||
{
|
||||
public GasMixture Air { get; set; }
|
||||
|
||||
public virtual void AssumeAir(GasMixture giver)
|
||||
{
|
||||
EntitySystem.Get<AtmosphereSystem>().Merge(Air, giver);
|
||||
}
|
||||
|
||||
public GasMixture RemoveAir(float amount)
|
||||
{
|
||||
return Air.Remove(amount);
|
||||
}
|
||||
|
||||
public GasMixture RemoveAirVolume(float ratio)
|
||||
{
|
||||
return Air.RemoveRatio(ratio);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ using Robust.Shared.ViewVariables;
|
||||
namespace Content.Server.Atmos.Piping.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds itself to a <see cref="IGridAtmosphereComponent"/> to be updated by.
|
||||
/// Adds itself to a <see cref="IAtmosphereComponent"/> to be updated by.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public class AtmosDeviceComponent : Component
|
||||
@@ -22,6 +22,19 @@ namespace Content.Server.Atmos.Piping.Components
|
||||
[DataField("requireAnchored")]
|
||||
public bool RequireAnchored { get; private set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether this device will join an entity system to process when not in a grid.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
[DataField("joinSystem")]
|
||||
public bool JoinSystem { get; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Whether we have joined an entity system to process.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool JoinedSystem { get; set; } = false;
|
||||
|
||||
[ViewVariables]
|
||||
public TimeSpan LastProcess { get; set; } = TimeSpan.Zero;
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Atmos.Piping.EntitySystems
|
||||
@@ -12,9 +12,14 @@ namespace Content.Server.Atmos.Piping.EntitySystems
|
||||
[UsedImplicitly]
|
||||
public class AtmosDeviceSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
||||
|
||||
private readonly AtmosDeviceUpdateEvent _updateEvent = new();
|
||||
|
||||
private float _timer = 0f;
|
||||
private readonly HashSet<AtmosDeviceComponent> _joinedDevices = new();
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -33,11 +38,24 @@ namespace Content.Server.Atmos.Piping.EntitySystems
|
||||
public void JoinAtmosphere(AtmosDeviceComponent component)
|
||||
{
|
||||
if (!CanJoinAtmosphere(component))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// We try to add the device to a valid atmosphere.
|
||||
// We try to add the device to a valid atmosphere, and if we can't, try to add it to the entity system.
|
||||
if (!_atmosphereSystem.AddAtmosDevice(component))
|
||||
return;
|
||||
{
|
||||
if (component.JoinSystem)
|
||||
{
|
||||
_joinedDevices.Add(component);
|
||||
component.JoinedSystem = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
component.LastProcess = _gameTiming.CurTime;
|
||||
|
||||
@@ -46,8 +64,19 @@ namespace Content.Server.Atmos.Piping.EntitySystems
|
||||
|
||||
public void LeaveAtmosphere(AtmosDeviceComponent component)
|
||||
{
|
||||
if (!_atmosphereSystem.RemoveAtmosDevice(component))
|
||||
// Try to remove the component from an atmosphere, and if not
|
||||
if (component.JoinedGrid != null && !_atmosphereSystem.RemoveAtmosDevice(component))
|
||||
{
|
||||
// The grid might have been removed but not us... This usually shouldn't happen.
|
||||
component.JoinedGrid = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (component.JoinedSystem)
|
||||
{
|
||||
_joinedDevices.Remove(component);
|
||||
component.JoinedSystem = false;
|
||||
}
|
||||
|
||||
component.LastProcess = TimeSpan.Zero;
|
||||
RaiseLocalEvent(component.Owner.Uid, new AtmosDeviceDisabledEvent(), false);
|
||||
@@ -85,5 +114,22 @@ namespace Content.Server.Atmos.Piping.EntitySystems
|
||||
{
|
||||
RejoinAtmosphere(component);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
_timer += frameTime;
|
||||
|
||||
if (_timer < _atmosphereSystem.AtmosTime)
|
||||
return;
|
||||
|
||||
_timer -= _atmosphereSystem.AtmosTime;
|
||||
|
||||
var time = _gameTiming.CurTime;
|
||||
foreach (var device in _joinedDevices)
|
||||
{
|
||||
RaiseLocalEvent(device.Owner.Uid, _updateEvent, false);
|
||||
device.LastProcess = time;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@ using Content.Server.Atmos.Piping.Trinary.Components;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.Piping;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Timing;
|
||||
@@ -24,33 +26,35 @@ namespace Content.Server.Atmos.Piping.Trinary.EntitySystems
|
||||
|
||||
private void OnFilterUpdated(EntityUid uid, GasFilterComponent filter, AtmosDeviceUpdateEvent args)
|
||||
{
|
||||
if (!filter.Enabled)
|
||||
return;
|
||||
var appearance = filter.Owner.GetComponentOrNull<AppearanceComponent>();
|
||||
|
||||
if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
|
||||
if (!filter.Enabled
|
||||
|| !ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
|
||||
|| !ComponentManager.TryGetComponent(uid, out AtmosDeviceComponent? device)
|
||||
|| !nodeContainer.TryGetNode(filter.InletName, out PipeNode? inletNode)
|
||||
|| !nodeContainer.TryGetNode(filter.FilterName, out PipeNode? filterNode)
|
||||
|| !nodeContainer.TryGetNode(filter.OutletName, out PipeNode? outletNode)
|
||||
|| outletNode.Air.Pressure >= Atmospherics.MaxOutputPressure) // No need to transfer if target is full.
|
||||
{
|
||||
appearance?.SetData(FilterVisuals.Enabled, false);
|
||||
return;
|
||||
|
||||
if (!ComponentManager.TryGetComponent(uid, out AtmosDeviceComponent? device))
|
||||
return;
|
||||
|
||||
if (!nodeContainer.TryGetNode(filter.InletName, out PipeNode? inletNode)
|
||||
|| !nodeContainer.TryGetNode(filter.FilterName, out PipeNode? filterNode)
|
||||
|| !nodeContainer.TryGetNode(filter.OutletName, out PipeNode? outletNode))
|
||||
return;
|
||||
|
||||
if (outletNode.Air.Pressure >= Atmospherics.MaxOutputPressure)
|
||||
return; // No need to transfer if target is full.
|
||||
}
|
||||
|
||||
// We multiply the transfer rate in L/s by the seconds passed since the last process to get the liters.
|
||||
var transferRatio = (float)(filter.TransferRate * (_gameTiming.CurTime - device.LastProcess).TotalSeconds) / inletNode.Air.Volume;
|
||||
|
||||
if (transferRatio <= 0)
|
||||
{
|
||||
appearance?.SetData(FilterVisuals.Enabled, false);
|
||||
return;
|
||||
}
|
||||
|
||||
var removed = inletNode.Air.RemoveRatio(transferRatio);
|
||||
|
||||
if (filter.FilteredGas.HasValue)
|
||||
{
|
||||
appearance?.SetData(FilterVisuals.Enabled, true);
|
||||
|
||||
var filteredOut = new GasMixture() {Temperature = removed.Temperature};
|
||||
|
||||
filteredOut.SetMoles(filter.FilteredGas.Value, removed.GetMoles(filter.FilteredGas.Value));
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#nullable disable warnings
|
||||
#nullable enable annotations
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Maps;
|
||||
using Robust.Shared.Map;
|
||||
@@ -10,6 +9,7 @@ namespace Content.Server.Atmos
|
||||
{
|
||||
/// <summary>
|
||||
/// Internal Atmos class that stores data about the atmosphere in a grid.
|
||||
/// You shouldn't use this directly, use <see cref="AtmosphereSystem"/> instead.
|
||||
/// </summary>
|
||||
public class TileAtmosphere : IGasMixtureHolder
|
||||
{
|
||||
@@ -71,6 +71,12 @@ namespace Content.Server.Atmos
|
||||
[ViewVariables]
|
||||
public GasMixture? Air { get; set; }
|
||||
|
||||
GasMixture IGasMixtureHolder.Air
|
||||
{
|
||||
get => Air ?? new GasMixture(Atmospherics.CellVolume){ Temperature = Temperature };
|
||||
set => Air = value;
|
||||
}
|
||||
|
||||
[ViewVariables]
|
||||
public float MaxFireTemperatureSustained { get; set; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user