diff --git a/Content.IntegrationTests/Tests/Body/GibTest.cs b/Content.IntegrationTests/Tests/Body/GibTest.cs new file mode 100644 index 0000000000..c0032a8524 --- /dev/null +++ b/Content.IntegrationTests/Tests/Body/GibTest.cs @@ -0,0 +1,43 @@ +#nullable enable +using Content.Server.Body.Systems; +using Robust.Shared.GameObjects; + +namespace Content.IntegrationTests.Tests.Body; + +[TestFixture] +public sealed class GibTest +{ + [Test] + public async Task TestGib() + { + await using var pair = await PoolManager.GetServerClient(new PoolSettings { Connected = true }); + var (server, client) = (pair.Server, pair.Client); + var map = await pair.CreateTestMap(); + + EntityUid target1 = default; + EntityUid target2 = default; + + await server.WaitAssertion(() => target1 = server.EntMan.Spawn("MobHuman", map.MapCoords)); + await server.WaitAssertion(() => target2 = server.EntMan.Spawn("MobHuman", map.MapCoords)); + await pair.WaitCommand($"setoutfit {server.EntMan.GetNetEntity(target1)} CaptainGear"); + await pair.WaitCommand($"setoutfit {server.EntMan.GetNetEntity(target2)} CaptainGear"); + + await pair.RunTicksSync(5); + var nuid1 = pair.ToClientUid(target1); + var nuid2 = pair.ToClientUid(target2); + Assert.That(client.EntMan.EntityExists(nuid1)); + Assert.That(client.EntMan.EntityExists(nuid2)); + + await server.WaitAssertion(() => server.System().GibBody(target1, gibOrgans: false)); + await server.WaitAssertion(() => server.System().GibBody(target2, gibOrgans: true)); + + await pair.RunTicksSync(5); + await pair.WaitCommand("dirty"); + await pair.RunTicksSync(5); + + Assert.That(!client.EntMan.EntityExists(nuid1)); + Assert.That(!client.EntMan.EntityExists(nuid2)); + + await pair.CleanReturnAsync(); + } +} diff --git a/Content.Shared/Body/Systems/SharedBodySystem.Body.cs b/Content.Shared/Body/Systems/SharedBodySystem.Body.cs index 74a202386e..b1b40dccfa 100644 --- a/Content.Shared/Body/Systems/SharedBodySystem.Body.cs +++ b/Content.Shared/Body/Systems/SharedBodySystem.Body.cs @@ -9,6 +9,7 @@ using Content.Shared.Inventory; using Content.Shared.Inventory.Events; using Robust.Shared.Containers; using Robust.Shared.Map; +using Robust.Shared.Utility; namespace Content.Shared.Body.Systems; @@ -58,10 +59,6 @@ public partial class SharedBodySystem private void OnBodyRemoved(EntityUid uid, BodyComponent component, EntRemovedFromContainerMessage args) { - // TODO: lifestage shenanigans - if (TerminatingOrDeleted(uid)) - return; - // Root body part? var slotId = args.Container.ID; @@ -69,6 +66,8 @@ public partial class SharedBodySystem return; var entity = args.Entity; + DebugTools.Assert(!TryComp(entity, out BodyPartComponent? b) || b.Body == uid); + DebugTools.Assert(!TryComp(entity, out OrganComponent? o) || o.Body == uid); if (TryComp(entity, out BodyPartComponent? childPart)) { @@ -77,9 +76,7 @@ public partial class SharedBodySystem } if (TryComp(entity, out OrganComponent? organ)) - { RemoveOrgan(entity, uid, organ); - } } private void OnBodyInit(EntityUid bodyId, BodyComponent body, ComponentInit args) diff --git a/Content.Shared/Body/Systems/SharedBodySystem.Parts.cs b/Content.Shared/Body/Systems/SharedBodySystem.Parts.cs index 463a4b7661..cfebaf3094 100644 --- a/Content.Shared/Body/Systems/SharedBodySystem.Parts.cs +++ b/Content.Shared/Body/Systems/SharedBodySystem.Parts.cs @@ -29,31 +29,28 @@ public partial class SharedBodySystem var entity = args.Entity; var slotId = args.Container.ID; - if (component.Body != null) - { - if (TryComp(entity, out BodyPartComponent? childPart)) - { - AddPart(component.Body.Value, entity, slotId, childPart); - RecursiveBodyUpdate(entity, component.Body.Value, childPart); - } + if (component.Body == null) + return; - if (TryComp(entity, out OrganComponent? organ)) - { - AddOrgan(entity, component.Body.Value, uid, organ); - } + if (TryComp(entity, out BodyPartComponent? childPart)) + { + AddPart(component.Body.Value, entity, slotId, childPart); + RecursiveBodyUpdate(entity, component.Body.Value, childPart); } + + if (TryComp(entity, out OrganComponent? organ)) + AddOrgan(entity, component.Body.Value, uid, organ); } private void OnBodyPartRemoved(EntityUid uid, BodyPartComponent component, EntRemovedFromContainerMessage args) { - // TODO: lifestage shenanigans - if (TerminatingOrDeleted(uid)) - return; - // Body part removed from another body part. var entity = args.Entity; var slotId = args.Container.ID; + DebugTools.Assert(!TryComp(entity, out BodyPartComponent? b) || b.Body == component.Body); + DebugTools.Assert(!TryComp(entity, out OrganComponent? o) || o.Body == component.Body); + if (TryComp(entity, out BodyPartComponent? childPart) && childPart.Body != null) { RemovePart(childPart.Body.Value, entity, slotId, childPart); @@ -61,49 +58,44 @@ public partial class SharedBodySystem } if (TryComp(entity, out OrganComponent? organ)) - { RemoveOrgan(entity, uid, organ); - } } private void RecursiveBodyUpdate(EntityUid uid, EntityUid? bodyUid, BodyPartComponent component) { - foreach (var children in GetBodyPartChildren(uid, component)) + component.Body = bodyUid; + Dirty(uid, component); + + foreach (var slotId in component.Organs.Keys) { - if (children.Component.Body != bodyUid) + if (!Containers.TryGetContainer(uid, GetOrganContainerId(slotId), out var container)) + continue; + + foreach (var organ in container.ContainedEntities) { - children.Component.Body = bodyUid; - Dirty(children.Id, children.Component); + if (!TryComp(organ, out OrganComponent? organComp)) + continue; - foreach (var slotId in children.Component.Organs.Keys) - { - var organContainerId = GetOrganContainerId(slotId); + Dirty(organ, organComp); - if (!Containers.TryGetContainer(children.Id, organContainerId, out var container)) - continue; + if (organComp.Body != null) + RaiseLocalEvent(organ, new RemovedFromPartInBodyEvent(organComp.Body.Value, uid)); - foreach (var organ in container.ContainedEntities) - { - if (TryComp(organ, out OrganComponent? organComp)) - { - var oldBody = organComp.Body; - organComp.Body = bodyUid; + organComp.Body = bodyUid; + if (bodyUid != null) + RaiseLocalEvent(organ, new AddedToPartInBodyEvent(bodyUid.Value, uid)); + } + } - if (bodyUid != null) - { - var ev = new AddedToPartInBodyEvent(bodyUid.Value, children.Id); - RaiseLocalEvent(organ, ev); - } - else if (oldBody != null) - { - var ev = new RemovedFromPartInBodyEvent(oldBody.Value, children.Id); - RaiseLocalEvent(organ, ev); - } + foreach (var slotId in component.Children.Keys) + { + if (!Containers.TryGetContainer(uid, GetPartSlotContainerId(slotId), out var container)) + continue; - Dirty(organ, organComp); - } - } - } + foreach (var containedEnt in container.ContainedEntities) + { + if (TryComp(containedEnt, out BodyPartComponent? childPart)) + RecursiveBodyUpdate(containedEnt, bodyUid, childPart); } } }