mirror of
https://github.com/space-syndicate/space-station-14.git
synced 2026-10-09 18:31:17 +03:00
452 lines
17 KiB
C#
452 lines
17 KiB
C#
using System.Numerics;
|
|
using Content.IntegrationTests.Fixtures.Attributes;
|
|
using Content.Server.Atmos.EntitySystems;
|
|
using Content.Shared.Atmos;
|
|
using Content.Shared.Atmos.Components;
|
|
using Robust.Shared.GameObjects;
|
|
using Robust.Shared.Map;
|
|
using Robust.Shared.Utility;
|
|
|
|
namespace Content.IntegrationTests.Tests.Atmos;
|
|
|
|
/// <summary>
|
|
/// Tests for AtmosphereSystem.DeltaPressure and surrounding systems
|
|
/// handling the DeltaPressureComponent.
|
|
/// </summary>
|
|
[TestFixture]
|
|
[TestOf(typeof(DeltaPressureSystem))]
|
|
public sealed class DeltaPressureTest : AtmosTest
|
|
{
|
|
#region Prototypes
|
|
|
|
[TestPrototypes]
|
|
private const string Prototypes = @"
|
|
- type: entity
|
|
parent: BaseStructure
|
|
id: DeltaPressureSolidTest
|
|
placement:
|
|
mode: SnapgridCenter
|
|
snap:
|
|
- Wall
|
|
components:
|
|
- type: Physics
|
|
bodyType: Static
|
|
- type: Fixtures
|
|
fixtures:
|
|
fix1:
|
|
shape:
|
|
!type:PhysShapeAabb
|
|
bounds: ""-0.5,-0.5,0.5,0.5""
|
|
mask:
|
|
- FullTileMask
|
|
layer:
|
|
- WallLayer
|
|
density: 1000
|
|
- type: Airtight
|
|
- type: DeltaPressure
|
|
minPressure: 15000
|
|
minPressureDelta: 10000
|
|
scalingType: Threshold
|
|
baseDamage:
|
|
types:
|
|
Structural: 1000
|
|
- type: Damageable
|
|
- type: Injurable
|
|
- type: Destructible
|
|
thresholds:
|
|
- trigger:
|
|
!type:DamageTrigger
|
|
damage: 300
|
|
behaviors:
|
|
- !type:SpawnEntitiesBehavior
|
|
spawn:
|
|
Girder:
|
|
min: 1
|
|
max: 1
|
|
- !type:DoActsBehavior
|
|
acts: [ ""Destruction"" ]
|
|
|
|
- type: entity
|
|
parent: DeltaPressureSolidTest
|
|
id: DeltaPressureSolidTestNoAutoJoin
|
|
components:
|
|
- type: DeltaPressure
|
|
autoJoinProcessingList: false
|
|
|
|
- type: entity
|
|
parent: DeltaPressureSolidTest
|
|
id: DeltaPressureSolidTestAbsolute
|
|
components:
|
|
- type: DeltaPressure
|
|
minPressure: 10000
|
|
minPressureDelta: 15000
|
|
scalingType: Threshold
|
|
baseDamage:
|
|
types:
|
|
Structural: 1000
|
|
|
|
- type: entity
|
|
parent: DeltaPressureSolidTest
|
|
id: DeltaPressureSolidTestDeltaOnly
|
|
components:
|
|
- type: DeltaPressure
|
|
minPressure: 100000
|
|
minPressureDelta: 10000
|
|
scalingType: Threshold
|
|
baseDamage:
|
|
types:
|
|
Structural: 1000
|
|
";
|
|
|
|
#endregion
|
|
|
|
protected override ResPath? TestMapPath => new("Maps/Test/Atmospherics/DeltaPressure/deltapressuretest.yml");
|
|
|
|
[SidedDependency(Side.Server)] private readonly SharedTransformSystem _xformSys = default!;
|
|
|
|
// TODO ATMOS TESTS
|
|
// - Check for directional windows (partial airtight ents) properly computing pressure differences
|
|
// - Check for multi-tick damage (window with n damage threshold should take n ticks to destroy)
|
|
// - Check that all maps do not explode into a million pieces on load due to dP
|
|
// - Ensure that all tests work for a map that has an origin at a non zero coordinate
|
|
|
|
/// <summary>
|
|
/// Asserts that an entity with a DeltaPressureComponent with autoJoinProcessingList
|
|
/// set to true is automatically added to the DeltaPressure processing list
|
|
/// on the grid's GridAtmosphereComponent.
|
|
///
|
|
/// Also asserts that an entity with a DeltaPressureComponent with autoJoinProcessingList
|
|
/// set to false is not automatically added to the DeltaPressure processing list.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ProcessingListAutoJoinTest()
|
|
{
|
|
await Server.WaitAssertion(() =>
|
|
{
|
|
var uid = SSpawnAtPosition("DeltaPressureSolidTest", new EntityCoordinates(ProcessEnt, Vector2.Zero));
|
|
var dpEnt = new Entity<DeltaPressureComponent>(uid, SEntMan.GetComponent<DeltaPressureComponent>(uid));
|
|
|
|
Assert.That(SAtmos.IsDeltaPressureEntityInList(RelevantAtmos, dpEnt),
|
|
"Entity was not in processing list when it should have automatically joined!");
|
|
SEntMan.DeleteEntity(uid);
|
|
Assert.That(!SAtmos.IsDeltaPressureEntityInList(RelevantAtmos, dpEnt),
|
|
"Entity was still in processing list after deletion!");
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that an entity that doesn't need to be damaged by DeltaPressure
|
|
/// is not damaged by DeltaPressure.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ProcessingDeltaStandbyTest()
|
|
{
|
|
Entity<DeltaPressureComponent> dpEnt = default;
|
|
TileAtmosphere tile = null!;
|
|
AtmosDirection direction = default;
|
|
|
|
// Load our test map in and assert that it exists.
|
|
await Server.WaitAssertion(() =>
|
|
{
|
|
var uid = SSpawnAtPosition("DeltaPressureSolidTest", new EntityCoordinates(ProcessEnt, Vector2.Zero));
|
|
dpEnt = new Entity<DeltaPressureComponent>(uid, SEntMan.GetComponent<DeltaPressureComponent>(uid));
|
|
Assert.That(SAtmos.IsDeltaPressureEntityInList(ProcessEnt, dpEnt),
|
|
"Entity was not in processing list when it should have been added!");
|
|
});
|
|
|
|
for (var i = 0; i < Atmospherics.Directions; i++)
|
|
{
|
|
await Server.WaitAssertion(() =>
|
|
{
|
|
var indices = _xformSys.GetGridOrMapTilePosition(dpEnt);
|
|
|
|
direction = (AtmosDirection)(1 << i);
|
|
var offsetIndices = indices.Offset(direction);
|
|
tile = RelevantAtmos.Comp.Tiles[offsetIndices];
|
|
|
|
Assert.That(tile.Air, Is.Not.Null, $"Tile at {offsetIndices} should have air!");
|
|
|
|
var toPressurize = dpEnt.Comp!.MinPressureDelta - 10;
|
|
var moles = (toPressurize * tile.Air.Volume) / (Atmospherics.R * Atmospherics.T20C);
|
|
|
|
tile.Air!.AdjustMoles(Gas.Nitrogen, moles);
|
|
});
|
|
|
|
await Server.WaitRunTicks(1);
|
|
|
|
// Entity should exist, if it took one tick of damage then it should be instantly destroyed.
|
|
await Server.WaitAssertion(() =>
|
|
{
|
|
Assert.That(!SEntMan.Deleted(dpEnt),
|
|
$"{dpEnt} should still exist after experiencing non-threshold pressure from {direction} side!");
|
|
tile.Air!.Clear();
|
|
});
|
|
|
|
await Server.WaitRunTicks(1);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that an entity that needs to be damaged by DeltaPressure
|
|
/// is damaged by DeltaPressure when the pressure is above the threshold.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ProcessingDeltaDamageTest()
|
|
{
|
|
Entity<DeltaPressureComponent> dpEnt = default;
|
|
AtmosDirection direction = default;
|
|
|
|
// Load our test map in and assert that it exists.
|
|
await Server.WaitPost(() =>
|
|
{
|
|
SAtmos.SetAtmosphereSimulation(ProcessEnt, false);
|
|
});
|
|
|
|
for (var i = 0; i < Atmospherics.Directions; i++)
|
|
{
|
|
await Server.WaitPost(() =>
|
|
{
|
|
SAtmos.RunProcessingFull(ProcessEnt, ProcessEnt.Owner, SAtmos.AtmosTickRate);
|
|
});
|
|
|
|
await Server.WaitAssertion(() =>
|
|
{
|
|
// Need to spawn an entity each run to ensure it works for all directions.
|
|
var uid = SSpawnAtPosition("DeltaPressureSolidTest",
|
|
new EntityCoordinates(ProcessEnt.Owner, Vector2.Zero));
|
|
dpEnt = new Entity<DeltaPressureComponent>(uid, SEntMan.GetComponent<DeltaPressureComponent>(uid));
|
|
Assert.That(SAtmos.IsDeltaPressureEntityInList(ProcessEnt.Owner, dpEnt),
|
|
"Entity was not in processing list when it should have been added!");
|
|
|
|
var indices = _xformSys.GetGridOrMapTilePosition(dpEnt);
|
|
|
|
direction = (AtmosDirection)(1 << i);
|
|
var offsetIndices = indices.Offset(direction);
|
|
var tile = RelevantAtmos.Comp.Tiles[offsetIndices];
|
|
|
|
Assert.That(tile.Air, Is.Not.Null, $"Tile at {offsetIndices} should have air!");
|
|
|
|
var toPressurize = dpEnt.Comp!.MinPressureDelta + 10;
|
|
var moles = (toPressurize * tile.Air.Volume) / (Atmospherics.R * Atmospherics.T20C);
|
|
|
|
tile.Air!.AdjustMoles(Gas.Nitrogen, moles);
|
|
});
|
|
|
|
// get jiggy with it! hit that dance white boy!
|
|
await Server.WaitPost(() =>
|
|
{
|
|
SAtmos.RunProcessingFull(ProcessEnt, ProcessEnt.Owner, SAtmos.AtmosTickRate);
|
|
});
|
|
|
|
// need to run some ticks as deleted entities are queued for removal
|
|
// and not removed instantly
|
|
await Server.WaitRunTicks(1);
|
|
|
|
// Entity shouldn't exist, if it took one tick of damage then it should be instantly destroyed.
|
|
await Server.WaitAssertion(() =>
|
|
{
|
|
Assert.That(SEntMan.Deleted(dpEnt),
|
|
$"{dpEnt} still exists after experiencing threshold pressure from {direction} side!");
|
|
|
|
// Gas may leak out between deleted entities, as such completely clear the grid just in case.
|
|
foreach (var mix in SAtmos.GetAllMixtures(ProcessEnt))
|
|
{
|
|
mix.Clear();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that an entity that doesn't need to be damaged by DeltaPressure
|
|
/// is not damaged by DeltaPressure when using absolute pressure thresholds.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ProcessingAbsoluteStandbyTest()
|
|
{
|
|
Entity<DeltaPressureComponent> dpEnt = default;
|
|
TileAtmosphere tile = null!;
|
|
AtmosDirection direction = default;
|
|
|
|
await Server.WaitAssertion(() =>
|
|
{
|
|
var uid = SSpawnAtPosition("DeltaPressureSolidTestAbsolute",
|
|
new EntityCoordinates(ProcessEnt.Owner, Vector2.Zero));
|
|
dpEnt = new Entity<DeltaPressureComponent>(uid, SEntMan.GetComponent<DeltaPressureComponent>(uid));
|
|
Assert.That(SAtmos.IsDeltaPressureEntityInList(ProcessEnt.Owner, dpEnt),
|
|
"Entity was not in processing list when it should have been added!");
|
|
});
|
|
|
|
for (var i = 0; i < Atmospherics.Directions; i++)
|
|
{
|
|
await Server.WaitAssertion(() =>
|
|
{
|
|
var indices = _xformSys.GetGridOrMapTilePosition(dpEnt);
|
|
var gridAtmosComp = SComp<GridAtmosphereComponent>(ProcessEnt);
|
|
|
|
direction = (AtmosDirection)(1 << i);
|
|
var offsetIndices = indices.Offset(direction);
|
|
tile = gridAtmosComp.Tiles[offsetIndices];
|
|
Assert.That(tile.Air, Is.Not.Null, $"Tile at {offsetIndices} should have air!");
|
|
|
|
var toPressurize = dpEnt.Comp!.MinPressure - 10; // just below absolute threshold
|
|
var moles = (toPressurize * tile.Air.Volume) / (Atmospherics.R * Atmospherics.T20C);
|
|
tile.Air!.AdjustMoles(Gas.Nitrogen, moles);
|
|
});
|
|
|
|
await Server.WaitRunTicks(1);
|
|
|
|
await Server.WaitAssertion(() =>
|
|
{
|
|
Assert.That(!SEntMan.Deleted(dpEnt),
|
|
$"{dpEnt} should still exist after experiencing non-threshold absolute pressure from {direction} side!");
|
|
tile.Air!.Clear();
|
|
});
|
|
|
|
await Server.WaitRunTicks(1);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that an entity that needs to be damaged by DeltaPressure
|
|
/// is damaged by DeltaPressure when the pressure is above the absolute threshold.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ProcessingAbsoluteDamageTest()
|
|
{
|
|
Entity<DeltaPressureComponent> dpEnt = default;
|
|
TileAtmosphere tile = null!;
|
|
AtmosDirection direction = default;
|
|
|
|
for (var i = 0; i < Atmospherics.Directions; i++)
|
|
{
|
|
await Server.WaitAssertion(() =>
|
|
{
|
|
// Spawn fresh entity each iteration to verify all directions work
|
|
var uid = SSpawnAtPosition("DeltaPressureSolidTestAbsolute",
|
|
new EntityCoordinates(ProcessEnt.Owner, Vector2.Zero));
|
|
dpEnt = new Entity<DeltaPressureComponent>(uid, SComp<DeltaPressureComponent>(uid));
|
|
Assert.That(SAtmos.IsDeltaPressureEntityInList(ProcessEnt.Owner, dpEnt),
|
|
"Entity was not in processing list when it should have been added!");
|
|
|
|
var indices = _xformSys.GetGridOrMapTilePosition(dpEnt);
|
|
var gridAtmosComp = SComp<GridAtmosphereComponent>(ProcessEnt);
|
|
|
|
direction = (AtmosDirection)(1 << i);
|
|
var offsetIndices = indices.Offset(direction);
|
|
tile = gridAtmosComp.Tiles[offsetIndices];
|
|
Assert.That(tile.Air, Is.Not.Null, $"Tile at {offsetIndices} should have air!");
|
|
|
|
// Above absolute threshold but below delta threshold to ensure absolute alone causes damage
|
|
var toPressurize = dpEnt.Comp!.MinPressure + 10;
|
|
var moles = (toPressurize * tile.Air.Volume) / (Atmospherics.R * Atmospherics.T20C);
|
|
tile.Air!.AdjustMoles(Gas.Nitrogen, moles);
|
|
});
|
|
|
|
await Server.WaitPost(() =>
|
|
{
|
|
SAtmos.RunProcessingFull(ProcessEnt, ProcessEnt.Owner, SAtmos.AtmosTickRate);
|
|
});
|
|
|
|
await Server.WaitRunTicks(30);
|
|
|
|
await Server.WaitAssertion(() =>
|
|
{
|
|
Assert.That(SEntMan.Deleted(dpEnt),
|
|
$"{dpEnt} still exists after experiencing threshold absolute pressure from {direction} side!");
|
|
tile.Air!.Clear();
|
|
});
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that diagonal pressure groupings do not trigger delta pressure damage.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ProcessingDeltaCardinalOnlyStandbyTest()
|
|
{
|
|
Entity<DeltaPressureComponent> dpEnt = default;
|
|
|
|
await Server.WaitAssertion(delegate
|
|
{
|
|
SAtmos.SetAtmosphereSimulation(ProcessEnt, false);
|
|
var uid = SSpawnAtPosition("DeltaPressureSolidTestDeltaOnly",
|
|
new EntityCoordinates(ProcessEnt.Owner, Vector2.Zero));
|
|
dpEnt = new Entity<DeltaPressureComponent>(uid, SComp<DeltaPressureComponent>(uid));
|
|
Assert.That(SAtmos.IsDeltaPressureEntityInList(ProcessEnt.Owner, dpEnt),
|
|
"Entity was not in processing list when it should have been added!");
|
|
|
|
var indices = _xformSys.GetGridOrMapTilePosition(dpEnt);
|
|
var tiles = RelevantAtmos.Comp.Tiles;
|
|
|
|
// Same pressure on each opposing pair: N==S and E==W, so delta should be zero.
|
|
SetTilePressure(tiles[indices.Offset(AtmosDirection.North)], 12_000f);
|
|
SetTilePressure(tiles[indices.Offset(AtmosDirection.South)], 12_000f);
|
|
SetTilePressure(tiles[indices.Offset(AtmosDirection.East)], 100f);
|
|
SetTilePressure(tiles[indices.Offset(AtmosDirection.West)], 100f);
|
|
});
|
|
|
|
await Server.WaitPost(delegate
|
|
{
|
|
SAtmos.RunProcessingFull(ProcessEnt, ProcessEnt.Owner, SAtmos.AtmosTickRate);
|
|
});
|
|
await Server.WaitRunTicks(1);
|
|
|
|
await Server.WaitAssertion(delegate
|
|
{
|
|
Assert.That(!SEntMan.Deleted(dpEnt),
|
|
$"{dpEnt} should not take damage when only diagonal comparisons would differ.");
|
|
foreach (var mix in SAtmos.GetAllMixtures(ProcessEnt))
|
|
{
|
|
mix.Clear();
|
|
}
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that opposing pressure groupings do trigger delta pressure damage.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ProcessingDeltaCardinalOnlyDamageTest()
|
|
{
|
|
Entity<DeltaPressureComponent> dpEnt = default;
|
|
|
|
await Server.WaitAssertion(delegate
|
|
{
|
|
var uid = SEntMan.SpawnAtPosition("DeltaPressureSolidTestDeltaOnly", new EntityCoordinates(ProcessEnt.Owner, Vector2.Zero));
|
|
dpEnt = new Entity<DeltaPressureComponent>(uid, SEntMan.GetComponent<DeltaPressureComponent>(uid));
|
|
Assert.That(SAtmos.IsDeltaPressureEntityInList(ProcessEnt.Owner, dpEnt), "Entity was not in processing list when it should have been added!");
|
|
});
|
|
|
|
await Server.WaitRunTicks(1);
|
|
|
|
await Server.WaitPost(delegate
|
|
{
|
|
var indices = _xformSys.GetGridOrMapTilePosition(dpEnt);
|
|
var tiles = RelevantAtmos.Comp.Tiles;
|
|
// There was a nasty bug where the indexing for comparisons was off and diagonals were
|
|
// being compared against instead of cardinals. This test basically
|
|
// stamps that out, so hopefully something silly doesn't happen again
|
|
// smile
|
|
SetTilePressure(tiles[indices.Offset(AtmosDirection.North)], 12_000f);
|
|
SetTilePressure(tiles[indices.Offset(AtmosDirection.South)], 100f);
|
|
SetTilePressure(tiles[indices.Offset(AtmosDirection.East)], 12_000f);
|
|
SetTilePressure(tiles[indices.Offset(AtmosDirection.West)], 100f);
|
|
});
|
|
|
|
await Server.WaitPost(delegate
|
|
{
|
|
SAtmos.RunProcessingFull(ProcessEnt, ProcessEnt.Owner, SAtmos.AtmosTickRate);
|
|
});
|
|
await Server.WaitRunTicks(30);
|
|
|
|
await Server.WaitAssertion(delegate
|
|
{
|
|
Assert.That(SEntMan.Deleted(dpEnt), $"{dpEnt} should take damage when opposing cardinals have threshold pressure differences.");
|
|
foreach (var mix in SAtmos.GetAllMixtures(ProcessEnt))
|
|
{
|
|
mix.Clear();
|
|
}
|
|
});
|
|
}
|
|
}
|