Fix error when disconnecting the client while a projectile is embedded (#36048)

* Add test for disconnecting the client while a projectile is embedded

* Add check for non-terminating grid or map

* Add test that an embeddable detaches when the target is deleted.

* Remove Explicit tag from TestDisconnectWhileEmbedded
This commit is contained in:
Tayrtahn
2025-03-24 20:16:13 -04:00
committed by GitHub
parent 2bc3561868
commit 0096dedb18
2 changed files with 93 additions and 0 deletions

View File

@@ -0,0 +1,91 @@
using Content.IntegrationTests.Tests.Interaction;
using Content.Shared.Projectiles;
using Robust.Shared.Network;
namespace Content.IntegrationTests.Tests.Embedding;
public sealed class EmbedTest : InteractionTest
{
/// <summary>
/// Embeddable entity that will be thrown at the target.
/// </summary>
private const string EmbeddableProtoId = "SurvivalKnife";
/// <summary>
/// Target entity that the thrown item will embed into.
/// </summary>
private const string TargetProtoId = "AirlockGlass";
/// <summary>
/// Embeds an entity with a <see cref="EmbeddableProjectileComponent"/> into a target,
/// then disconnects the client. Intended to reveal any clientside issues that might
/// occur due to reparenting during cleanup.
/// </summary>
[Test]
public async Task TestDisconnectWhileEmbedded()
{
// Spawn the target we're going to throw at
await SpawnTarget(TargetProtoId);
// Give the player the embeddable to throw
var projectile = await PlaceInHands(EmbeddableProtoId);
Assert.That(TryComp<EmbeddableProjectileComponent>(projectile, out var embedComp),
$"{EmbeddableProtoId} does not have EmbeddableProjectileComponent");
// Make sure the projectile isn't already embedded into anything
Assert.That(embedComp.EmbeddedIntoUid, Is.Null,
$"Projectile already embedded into {SEntMan.ToPrettyString(embedComp.EmbeddedIntoUid)}");
// Have the player throw the embeddable at the target
await ThrowItem();
// Wait a moment for the item to hit and embed
await RunSeconds(0.5f);
// Make sure the projectile is embedded into the target
Assert.That(embedComp.EmbeddedIntoUid, Is.EqualTo(ToServer(Target)),
"Projectile not embedded into target");
// Disconnect the client
var cNetMgr = Client.ResolveDependency<IClientNetManager>();
await Client.WaitPost(Client.EntMan.FlushEntities);
await Pair.RunTicksSync(1);
}
/// <summary>
/// Embeds an entity with a <see cref="EmbeddableProjectileComponent"/> into a target,
/// then deletes the target and makes sure the embeddable is not deleted.
/// </summary>
[Test]
public async Task TestEmbedDetach()
{
// Spawn the target we're going to throw at
await SpawnTarget(TargetProtoId);
// Give the player the embeddable to throw
var projectile = await PlaceInHands(EmbeddableProtoId);
Assert.That(TryComp<EmbeddableProjectileComponent>(projectile, out var embedComp),
$"{EmbeddableProtoId} does not have EmbeddableProjectileComponent");
// Make sure the projectile isn't already embedded into anything
Assert.That(embedComp.EmbeddedIntoUid, Is.Null,
$"Projectile already embedded into {SEntMan.ToPrettyString(embedComp.EmbeddedIntoUid)}");
// Have the player throw the embeddable at the target
await ThrowItem();
// Wait a moment for the item to hit and embed
await RunSeconds(0.5f);
// Make sure the projectile is embedded into the target
Assert.That(embedComp.EmbeddedIntoUid, Is.EqualTo(ToServer(Target)),
"Projectile not embedded into target");
// Delete the target
await Delete(Target.Value);
await RunTicks(1);
// Make sure the embeddable wasn't deleted with the target
AssertExists(projectile);
await AssertEntityLookup(EmbeddableProtoId);
}
}

View File

@@ -143,6 +143,8 @@ public abstract partial class SharedProjectileSystem : EntitySystem
} }
var xform = Transform(uid); var xform = Transform(uid);
if (TerminatingOrDeleted(xform.GridUid) && TerminatingOrDeleted(xform.MapUid))
return;
TryComp<PhysicsComponent>(uid, out var physics); TryComp<PhysicsComponent>(uid, out var physics);
_physics.SetBodyType(uid, BodyType.Dynamic, body: physics, xform: xform); _physics.SetBodyType(uid, BodyType.Dynamic, body: physics, xform: xform);
_transform.AttachToGridOrMap(uid, xform); _transform.AttachToGridOrMap(uid, xform);