Files
OldThink/Content.IntegrationTests/Tests/Minds/MindTests.EntityDeletion.cs

315 lines
12 KiB
C#
Raw Permalink Normal View History

Cherrypicks 3 (#382) * Mobs burn to ashes on excessive heat damage (#26971) * mobs burn to ashes on excessive heat damage * remove comment, remove random lines I didn't mean to add * combine code into behavior * clean unused * fix namespace * drop next to * fix spawn entities behavior spawning entities outside container * fix burning to ash not working on all mobs (#27158) * add ghostnado button to warp menu (#27556) * add ghostnado button to warp menu * translator ops --------- Co-authored-by: deltanedas <@deltanedas:kde.org> * Make arguments and parameters wrap to one variable per line (#27766) * Fix ghosts getting spawned in nullspace (#27617) * Add tests for ghost spawn position * Make ghosts spawn immediately * Format mind system * Move ghost spawning to GhostSystem * Spawn ghost on grid or map This fixes the ghosts being attached the parent entity instead of the grid. * Move logging out of the ghost system * Make round start observer spawn using GhostSystem * Move GameTicker ghost spawning to GhostSystem Moved the more robust character name selection code over. Moved the TimeOfDeath code over. Added canReturn logic. * Add overrides and default for ghost spawn coordinates * Add warning log to ghost spawn fail * Clean up test * Dont spawn ghost on map delete * Minor changes to the role test * Fix role test failing to spawn ghost It was failing the map check due to using Nullspace * Fix ghost tests when running in parallel Not sure what happened, but it seems to be because they were running simultaneously and overwriting values. * Clean up ghost tests * Test that map deletion does not spawn ghosts * Spawn ghost on the next available map * Disallow spawning on deleted maps * Fix map deletion ghost test * Cleanup --------- Co-authored-by: Whisper <121047731+QuietlyWhisper@users.noreply.github.com> Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com> Co-authored-by: ShadowCommander <shadowjjt@gmail.com>
2024-06-25 21:39:44 +00:00
#nullable enable
2023-06-21 14:11:58 +12:00
using System.Linq;
using Content.Server.GameTicking;
2023-08-25 18:50:46 +10:00
using Content.Shared.Ghost;
using Content.Shared.Mind;
using Content.Shared.Players;
2023-06-20 16:29:26 +12:00
using Robust.Server.Console;
using Robust.Server.GameObjects;
using Robust.Server.Player;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
namespace Content.IntegrationTests.Tests.Minds;
2023-06-21 14:11:58 +12:00
// Tests various scenarios where an entity that is associated with a player's mind is deleted.
public sealed partial class MindTests
2023-06-20 16:29:26 +12:00
{
2023-06-21 14:11:58 +12:00
// This test will do the following:
// - spawn a player
// - visit some entity
// - delete the entity being visited
// - assert that player returns to original entity
[Test]
public async Task TestDeleteVisiting()
{
2023-08-25 02:56:51 +02:00
await using var pair = await SetupPair();
var server = pair.Server;
2023-06-21 14:11:58 +12:00
var entMan = server.ResolveDependency<IServerEntityManager>();
var playerMan = server.ResolveDependency<IPlayerManager>();
var mindSystem = entMan.EntitySysManager.GetEntitySystem<SharedMindSystem>();
2023-06-21 14:11:58 +12:00
EntityUid playerEnt = default;
EntityUid visitEnt = default;
EntityUid mindId = default!;
MindComponent mind = default!;
2023-06-21 14:11:58 +12:00
await server.WaitAssertion(() =>
{
var player = playerMan.Sessions.Single();
2023-06-21 14:11:58 +12:00
playerEnt = entMan.SpawnEntity(null, MapCoordinates.Nullspace);
visitEnt = entMan.SpawnEntity(null, MapCoordinates.Nullspace);
mindId = mindSystem.CreateMind(player.UserId);
mind = entMan.GetComponent<MindComponent>(mindId);
mindSystem.TransferTo(mindId, playerEnt);
mindSystem.Visit(mindId, visitEnt);
2023-06-21 14:11:58 +12:00
Assert.Multiple(() =>
{
Assert.That(player.AttachedEntity, Is.EqualTo(visitEnt));
Assert.That(mind.VisitingEntity, Is.EqualTo(visitEnt));
});
2023-06-21 14:11:58 +12:00
});
await pair.RunTicksSync(5);
2023-06-21 14:11:58 +12:00
await server.WaitPost(() => entMan.DeleteEntity(visitEnt));
await pair.RunTicksSync(5);
2023-06-21 14:11:58 +12:00
#pragma warning disable NUnit2045 // Interdependent assertions.
Assert.That(mind.VisitingEntity, Is.Null);
2023-06-21 14:11:58 +12:00
Assert.That(entMan.EntityExists(mind.OwnedEntity));
Assert.That(mind.OwnedEntity, Is.EqualTo(playerEnt));
#pragma warning restore NUnit2045
2023-06-21 14:11:58 +12:00
// This used to throw so make sure it doesn't.
await server.WaitPost(() => entMan.DeleteEntity(mind.OwnedEntity!.Value));
await pair.RunTicksSync(5);
2023-06-21 14:11:58 +12:00
2023-08-25 02:56:51 +02:00
await pair.CleanReturnAsync();
2023-06-21 14:11:58 +12:00
}
// this is a variant of TestGhostOnDelete that just deletes the whole map.
[Test]
public async Task TestGhostOnDeleteMap()
{
2023-08-25 02:56:51 +02:00
await using var pair = await SetupPair(dirty: true);
var server = pair.Server;
var testMap = await pair.CreateTestMap();
Cherrypicks 3 (#382) * Mobs burn to ashes on excessive heat damage (#26971) * mobs burn to ashes on excessive heat damage * remove comment, remove random lines I didn't mean to add * combine code into behavior * clean unused * fix namespace * drop next to * fix spawn entities behavior spawning entities outside container * fix burning to ash not working on all mobs (#27158) * add ghostnado button to warp menu (#27556) * add ghostnado button to warp menu * translator ops --------- Co-authored-by: deltanedas <@deltanedas:kde.org> * Make arguments and parameters wrap to one variable per line (#27766) * Fix ghosts getting spawned in nullspace (#27617) * Add tests for ghost spawn position * Make ghosts spawn immediately * Format mind system * Move ghost spawning to GhostSystem * Spawn ghost on grid or map This fixes the ghosts being attached the parent entity instead of the grid. * Move logging out of the ghost system * Make round start observer spawn using GhostSystem * Move GameTicker ghost spawning to GhostSystem Moved the more robust character name selection code over. Moved the TimeOfDeath code over. Added canReturn logic. * Add overrides and default for ghost spawn coordinates * Add warning log to ghost spawn fail * Clean up test * Dont spawn ghost on map delete * Minor changes to the role test * Fix role test failing to spawn ghost It was failing the map check due to using Nullspace * Fix ghost tests when running in parallel Not sure what happened, but it seems to be because they were running simultaneously and overwriting values. * Clean up ghost tests * Test that map deletion does not spawn ghosts * Spawn ghost on the next available map * Disallow spawning on deleted maps * Fix map deletion ghost test * Cleanup --------- Co-authored-by: Whisper <121047731+QuietlyWhisper@users.noreply.github.com> Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com> Co-authored-by: ShadowCommander <shadowjjt@gmail.com>
2024-06-25 21:39:44 +00:00
var testMap2 = await pair.CreateTestMap();
2023-06-21 14:11:58 +12:00
var entMan = server.ResolveDependency<IServerEntityManager>();
var mapManager = server.ResolveDependency<IMapManager>();
var playerMan = server.ResolveDependency<IPlayerManager>();
var player = playerMan.Sessions.Single();
2023-06-21 14:11:58 +12:00
var mindSystem = entMan.EntitySysManager.GetEntitySystem<SharedMindSystem>();
2023-06-21 14:11:58 +12:00
EntityUid playerEnt = default;
EntityUid mindId = default!;
MindComponent mind = default!;
2023-06-21 14:11:58 +12:00
await server.WaitAssertion(() =>
{
Cherrypicks 3 (#382) * Mobs burn to ashes on excessive heat damage (#26971) * mobs burn to ashes on excessive heat damage * remove comment, remove random lines I didn't mean to add * combine code into behavior * clean unused * fix namespace * drop next to * fix spawn entities behavior spawning entities outside container * fix burning to ash not working on all mobs (#27158) * add ghostnado button to warp menu (#27556) * add ghostnado button to warp menu * translator ops --------- Co-authored-by: deltanedas <@deltanedas:kde.org> * Make arguments and parameters wrap to one variable per line (#27766) * Fix ghosts getting spawned in nullspace (#27617) * Add tests for ghost spawn position * Make ghosts spawn immediately * Format mind system * Move ghost spawning to GhostSystem * Spawn ghost on grid or map This fixes the ghosts being attached the parent entity instead of the grid. * Move logging out of the ghost system * Make round start observer spawn using GhostSystem * Move GameTicker ghost spawning to GhostSystem Moved the more robust character name selection code over. Moved the TimeOfDeath code over. Added canReturn logic. * Add overrides and default for ghost spawn coordinates * Add warning log to ghost spawn fail * Clean up test * Dont spawn ghost on map delete * Minor changes to the role test * Fix role test failing to spawn ghost It was failing the map check due to using Nullspace * Fix ghost tests when running in parallel Not sure what happened, but it seems to be because they were running simultaneously and overwriting values. * Clean up ghost tests * Test that map deletion does not spawn ghosts * Spawn ghost on the next available map * Disallow spawning on deleted maps * Fix map deletion ghost test * Cleanup --------- Co-authored-by: Whisper <121047731+QuietlyWhisper@users.noreply.github.com> Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com> Co-authored-by: ShadowCommander <shadowjjt@gmail.com>
2024-06-25 21:39:44 +00:00
playerEnt = entMan.SpawnEntity(null, testMap.GridCoords);
mindId = player.ContentData()!.Mind!.Value;
mind = entMan.GetComponent<MindComponent>(mindId);
mindSystem.TransferTo(mindId, playerEnt);
2023-06-21 14:11:58 +12:00
Assert.That(mind.CurrentEntity, Is.EqualTo(playerEnt));
});
await pair.RunTicksSync(5);
Cherrypicks 3 (#382) * Mobs burn to ashes on excessive heat damage (#26971) * mobs burn to ashes on excessive heat damage * remove comment, remove random lines I didn't mean to add * combine code into behavior * clean unused * fix namespace * drop next to * fix spawn entities behavior spawning entities outside container * fix burning to ash not working on all mobs (#27158) * add ghostnado button to warp menu (#27556) * add ghostnado button to warp menu * translator ops --------- Co-authored-by: deltanedas <@deltanedas:kde.org> * Make arguments and parameters wrap to one variable per line (#27766) * Fix ghosts getting spawned in nullspace (#27617) * Add tests for ghost spawn position * Make ghosts spawn immediately * Format mind system * Move ghost spawning to GhostSystem * Spawn ghost on grid or map This fixes the ghosts being attached the parent entity instead of the grid. * Move logging out of the ghost system * Make round start observer spawn using GhostSystem * Move GameTicker ghost spawning to GhostSystem Moved the more robust character name selection code over. Moved the TimeOfDeath code over. Added canReturn logic. * Add overrides and default for ghost spawn coordinates * Add warning log to ghost spawn fail * Clean up test * Dont spawn ghost on map delete * Minor changes to the role test * Fix role test failing to spawn ghost It was failing the map check due to using Nullspace * Fix ghost tests when running in parallel Not sure what happened, but it seems to be because they were running simultaneously and overwriting values. * Clean up ghost tests * Test that map deletion does not spawn ghosts * Spawn ghost on the next available map * Disallow spawning on deleted maps * Fix map deletion ghost test * Cleanup --------- Co-authored-by: Whisper <121047731+QuietlyWhisper@users.noreply.github.com> Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com> Co-authored-by: ShadowCommander <shadowjjt@gmail.com>
2024-06-25 21:39:44 +00:00
await server.WaitAssertion(() => mapManager.DeleteMap(testMap.MapId));
await pair.RunTicksSync(5);
2023-06-21 14:11:58 +12:00
await server.WaitAssertion(() =>
{
#pragma warning disable NUnit2045 // Interdependent assertions.
Cherrypicks 3 (#382) * Mobs burn to ashes on excessive heat damage (#26971) * mobs burn to ashes on excessive heat damage * remove comment, remove random lines I didn't mean to add * combine code into behavior * clean unused * fix namespace * drop next to * fix spawn entities behavior spawning entities outside container * fix burning to ash not working on all mobs (#27158) * add ghostnado button to warp menu (#27556) * add ghostnado button to warp menu * translator ops --------- Co-authored-by: deltanedas <@deltanedas:kde.org> * Make arguments and parameters wrap to one variable per line (#27766) * Fix ghosts getting spawned in nullspace (#27617) * Add tests for ghost spawn position * Make ghosts spawn immediately * Format mind system * Move ghost spawning to GhostSystem * Spawn ghost on grid or map This fixes the ghosts being attached the parent entity instead of the grid. * Move logging out of the ghost system * Make round start observer spawn using GhostSystem * Move GameTicker ghost spawning to GhostSystem Moved the more robust character name selection code over. Moved the TimeOfDeath code over. Added canReturn logic. * Add overrides and default for ghost spawn coordinates * Add warning log to ghost spawn fail * Clean up test * Dont spawn ghost on map delete * Minor changes to the role test * Fix role test failing to spawn ghost It was failing the map check due to using Nullspace * Fix ghost tests when running in parallel Not sure what happened, but it seems to be because they were running simultaneously and overwriting values. * Clean up ghost tests * Test that map deletion does not spawn ghosts * Spawn ghost on the next available map * Disallow spawning on deleted maps * Fix map deletion ghost test * Cleanup --------- Co-authored-by: Whisper <121047731+QuietlyWhisper@users.noreply.github.com> Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com> Co-authored-by: ShadowCommander <shadowjjt@gmail.com>
2024-06-25 21:39:44 +00:00
// Spawn ghost on the second map
var attachedEntity = player.AttachedEntity;
Assert.That(entMan.EntityExists(attachedEntity), Is.True);
Assert.That(attachedEntity, Is.Not.EqualTo(playerEnt));
Assert.That(entMan.HasComponent<GhostComponent>(attachedEntity));
var transform = entMan.GetComponent<TransformComponent>(attachedEntity.Value);
Assert.That(transform.MapID, Is.Not.EqualTo(MapId.Nullspace));
Assert.That(transform.MapID, Is.Not.EqualTo(testMap.MapId));
#pragma warning restore NUnit2045
2023-06-21 14:11:58 +12:00
});
2023-08-25 02:56:51 +02:00
await pair.CleanReturnAsync();
2023-06-21 14:11:58 +12:00
}
2023-06-20 16:29:26 +12:00
/// <summary>
/// Test that a ghost gets created when the player entity is deleted.
/// 1. Delete mob
/// 2. Assert is ghost
/// </summary>
[Test]
public async Task TestGhostOnDelete()
{
// Client is needed to spawn session
2023-08-25 02:56:51 +02:00
await using var pair = await SetupPair(dirty: true);
var server = pair.Server;
2023-06-20 16:29:26 +12:00
var entMan = server.ResolveDependency<IServerEntityManager>();
var playerMan = server.ResolveDependency<IPlayerManager>();
var player = playerMan.Sessions.Single();
2023-06-20 16:29:26 +12:00
2023-06-21 14:11:58 +12:00
Assert.That(!entMan.HasComponent<GhostComponent>(player.AttachedEntity), "Player was initially a ghost?");
2023-06-20 16:29:26 +12:00
2023-06-21 14:11:58 +12:00
// Delete entity
await server.WaitPost(() => entMan.DeleteEntity(player.AttachedEntity!.Value));
await pair.RunTicksSync(5);
2023-06-20 16:29:26 +12:00
2023-06-21 14:11:58 +12:00
Assert.That(entMan.HasComponent<GhostComponent>(player.AttachedEntity), "Player did not become a ghost");
2023-06-20 16:29:26 +12:00
2023-08-25 02:56:51 +02:00
await pair.CleanReturnAsync();
2023-06-20 16:29:26 +12:00
}
/// <summary>
/// Test that when the original mob gets deleted, the visited ghost does not get deleted.
/// And that the visited ghost becomes the main mob.
/// 1. Visit ghost
/// 2. Delete original mob
/// 3. Assert is ghost
/// 4. Assert was not deleted
/// 5. Assert is main mob
/// </summary>
[Test]
public async Task TestOriginalDeletedWhileGhostingKeepsGhost()
{
// Client is needed to spawn session
2023-08-25 02:56:51 +02:00
await using var pair = await SetupPair();
var server = pair.Server;
2023-06-20 16:29:26 +12:00
var entMan = server.ResolveDependency<IServerEntityManager>();
var playerMan = server.ResolveDependency<IPlayerManager>();
var mindSystem = entMan.EntitySysManager.GetEntitySystem<SharedMindSystem>();
2023-08-25 02:56:51 +02:00
var mind = GetMind(pair);
2023-06-20 16:29:26 +12:00
var player = playerMan.Sessions.Single();
#pragma warning disable NUnit2045 // Interdependent assertions.
Assert.That(player.AttachedEntity, Is.Not.Null);
Assert.That(entMan.EntityExists(player.AttachedEntity));
#pragma warning restore NUnit2045
var originalEntity = player.AttachedEntity.Value;
2023-06-20 16:29:26 +12:00
EntityUid ghost = default!;
await server.WaitAssertion(() =>
{
ghost = entMan.SpawnEntity(GameTicker.ObserverPrototypeName, MapCoordinates.Nullspace);
mindSystem.Visit(mind.Id, ghost);
2023-06-20 16:29:26 +12:00
});
Assert.Multiple(() =>
{
Assert.That(player.AttachedEntity, Is.EqualTo(ghost));
Assert.That(entMan.HasComponent<GhostComponent>(player.AttachedEntity), "player is not a ghost");
Assert.That(mind.Comp.VisitingEntity, Is.EqualTo(player.AttachedEntity));
Assert.That(mind.Comp.OwnedEntity, Is.EqualTo(originalEntity));
});
await pair.RunTicksSync(5);
2023-06-20 16:29:26 +12:00
await server.WaitAssertion(() => entMan.DeleteEntity(originalEntity));
await pair.RunTicksSync(5);
Assert.That(entMan.Deleted(originalEntity));
2023-06-20 16:29:26 +12:00
// Check that the player is still in control of the ghost
2023-08-25 02:56:51 +02:00
mind = GetMind(pair);
Assert.That(!entMan.Deleted(ghost), "ghost has been deleted");
Assert.Multiple(() =>
{
Assert.That(player.AttachedEntity, Is.EqualTo(ghost));
Assert.That(entMan.HasComponent<GhostComponent>(player.AttachedEntity));
Assert.That(mind.Comp.VisitingEntity, Is.Null);
Assert.That(mind.Comp.OwnedEntity, Is.EqualTo(ghost));
});
2023-06-20 16:29:26 +12:00
2023-08-25 02:56:51 +02:00
await pair.CleanReturnAsync();
2023-06-20 16:29:26 +12:00
}
/// <summary>
/// Test that ghosts can become admin ghosts without issue
/// 1. Become a ghost
/// 2. visit an admin ghost
/// 3. original ghost is deleted, player is an admin ghost.
/// </summary>
[Test]
public async Task TestGhostToAghost()
{
2023-08-25 02:56:51 +02:00
await using var pair = await SetupPair();
var server = pair.Server;
2023-06-20 16:29:26 +12:00
var entMan = server.ResolveDependency<IServerEntityManager>();
var playerMan = server.ResolveDependency<IPlayerManager>();
var serverConsole = server.ResolveDependency<IServerConsoleHost>();
var player = playerMan.Sessions.Single();
2023-06-20 16:29:26 +12:00
2023-08-25 02:56:51 +02:00
var ghost = await BecomeGhost(pair);
2023-06-20 16:29:26 +12:00
// Player is a normal ghost (not admin ghost).
Assert.That(entMan.GetComponent<MetaDataComponent>(player.AttachedEntity!.Value).EntityPrototype?.ID, Is.Not.EqualTo(GameTicker.AdminObserverPrototypeName));
2023-06-20 16:29:26 +12:00
// Try to become an admin ghost
await server.WaitAssertion(() => serverConsole.ExecuteCommand(player, "aghost"));
await pair.RunTicksSync(5);
2023-06-20 16:29:26 +12:00
Assert.That(entMan.Deleted(ghost), "old ghost was not deleted");
Assert.Multiple(() =>
{
Assert.That(player.AttachedEntity, Is.Not.EqualTo(ghost), "Player is still attached to the old ghost");
Assert.That(entMan.HasComponent<GhostComponent>(player.AttachedEntity), "Player did not become a new ghost");
Assert.That(entMan.GetComponent<MetaDataComponent>(player.AttachedEntity!.Value).EntityPrototype?.ID, Is.EqualTo(GameTicker.AdminObserverPrototypeName));
});
2023-06-20 16:29:26 +12:00
var mindId = player.ContentData()?.Mind;
Assert.That(mindId, Is.Not.Null);
var mind = entMan.GetComponent<MindComponent>(mindId.Value);
Assert.That(mind.VisitingEntity, Is.Null);
2023-06-20 16:29:26 +12:00
2023-08-25 02:56:51 +02:00
await pair.CleanReturnAsync();
2023-06-20 16:29:26 +12:00
}
/// <summary>
/// Test ghost getting deleted while player is connected spawns another ghost
/// 1. become ghost
/// 2. delete ghost
/// 3. new ghost is spawned
/// </summary>
[Test]
public async Task TestGhostDeletedSpawnsNewGhost()
{
// Client is needed to spawn session
2023-08-25 02:56:51 +02:00
await using var pair = await SetupPair();
var server = pair.Server;
2023-06-20 16:29:26 +12:00
var entMan = server.ResolveDependency<IServerEntityManager>();
var playerMan = server.ResolveDependency<IPlayerManager>();
var serverConsole = server.ResolveDependency<IServerConsoleHost>();
var player = playerMan.Sessions.Single();
2023-06-20 16:29:26 +12:00
EntityUid ghost = default!;
await server.WaitAssertion(() =>
{
Assert.That(player.AttachedEntity, Is.Not.EqualTo(null));
entMan.DeleteEntity(player.AttachedEntity!.Value);
});
await pair.RunTicksSync(5);
2023-06-20 16:29:26 +12:00
await server.WaitAssertion(() =>
{
// Is player a ghost?
Assert.That(player.AttachedEntity, Is.Not.EqualTo(null));
ghost = player.AttachedEntity!.Value;
Assert.That(entMan.HasComponent<GhostComponent>(ghost));
});
await pair.RunTicksSync(5);
2023-06-20 16:29:26 +12:00
await server.WaitAssertion(() =>
{
serverConsole.ExecuteCommand(player, "aghost");
});
await pair.RunTicksSync(5);
2023-06-20 16:29:26 +12:00
await server.WaitAssertion(() =>
{
#pragma warning disable NUnit2045 // Interdependent assertions.
2023-06-20 16:29:26 +12:00
Assert.That(entMan.Deleted(ghost));
Assert.That(player.AttachedEntity, Is.Not.EqualTo(ghost));
Assert.That(entMan.HasComponent<GhostComponent>(player.AttachedEntity!.Value));
#pragma warning restore NUnit2045
2023-06-20 16:29:26 +12:00
});
2023-08-25 02:56:51 +02:00
await pair.CleanReturnAsync();
2023-06-20 16:29:26 +12:00
}
}