From a2d8fa7a9b074d144f31e59451403f3793b73074 Mon Sep 17 00:00:00 2001 From: KISS <59531932+YuriyKiss@users.noreply.github.com> Date: Sun, 24 Mar 2024 07:32:57 +0200 Subject: [PATCH] Making possible to QueueDeleteEntity on EndCollideEvent (#4883) * made possible to destroy entity on EndCollideEvent * figured queue delete issue * review --------- Co-authored-by: metalgearsloth --- RELEASE-NOTES.md | 2 +- .../Physics/Dynamics/Contacts/Contact.cs | 3 +++ .../Systems/SharedPhysicsSystem.Components.cs | 12 ++++++++++-- .../Systems/SharedPhysicsSystem.Contacts.cs | 16 +++++++++------- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index bd589ba209..e7cb195519 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -43,7 +43,7 @@ END TEMPLATE--> ### Bugfixes -*None yet* +* Fix QueueDel during EndCollideEvents from throwing while removing contacts. ### Other diff --git a/Robust.Shared/Physics/Dynamics/Contacts/Contact.cs b/Robust.Shared/Physics/Dynamics/Contacts/Contact.cs index 2e6279c133..52ef03d0ef 100644 --- a/Robust.Shared/Physics/Dynamics/Contacts/Contact.cs +++ b/Robust.Shared/Physics/Dynamics/Contacts/Contact.cs @@ -376,6 +376,9 @@ namespace Robust.Shared.Physics.Dynamics.Contacts /// Grid = 1 << 3, + /// + /// Set right before the contact is deleted + /// Deleting = 1 << 4, } } diff --git a/Robust.Shared/Physics/Systems/SharedPhysicsSystem.Components.cs b/Robust.Shared/Physics/Systems/SharedPhysicsSystem.Components.cs index 487c06b231..6b15cecf17 100644 --- a/Robust.Shared/Physics/Systems/SharedPhysicsSystem.Components.cs +++ b/Robust.Shared/Physics/Systems/SharedPhysicsSystem.Components.cs @@ -186,17 +186,25 @@ public partial class SharedPhysicsSystem { if (body.Contacts.Count == 0) return; + // This variable is only used in edge-case scenario when contact flagged Deleting raises + // EndCollideEvent which will QueueDelete contact's entity + ushort contactsFlaggedDeleting = 0; var node = body.Contacts.First; while (node != null) { var contact = node.Value; node = node.Next; + // Destroy last so the linked-list doesn't get touched. - DestroyContact(contact); + if (!DestroyContact(contact)) + { + contactsFlaggedDeleting++; + } } - DebugTools.Assert(body.Contacts.Count == 0); + // This contact will be deleted before SimulateWorld runs since it is already set to be Deleted + DebugTools.Assert(body.Contacts.Count == contactsFlaggedDeleting); } /// diff --git a/Robust.Shared/Physics/Systems/SharedPhysicsSystem.Contacts.cs b/Robust.Shared/Physics/Systems/SharedPhysicsSystem.Contacts.cs index fbd944ec75..678b594bd2 100644 --- a/Robust.Shared/Physics/Systems/SharedPhysicsSystem.Contacts.cs +++ b/Robust.Shared/Physics/Systems/SharedPhysicsSystem.Contacts.cs @@ -310,11 +310,10 @@ public abstract partial class SharedPhysicsSystem (fixtureB.CollisionMask & fixtureA.CollisionLayer) == 0x0); } - public void DestroyContact(Contact contact) + public bool DestroyContact(Contact contact) { - // Don't recursive update or we're in for a bad time. if ((contact.Flags & ContactFlags.Deleting) != 0x0) - return; + return false; Fixture fixtureA = contact.FixtureA!; Fixture fixtureB = contact.FixtureB!; @@ -326,7 +325,7 @@ public abstract partial class SharedPhysicsSystem if (contact.IsTouching) { - var ev1 = new EndCollideEvent(aUid, bUid, contact.FixtureAId, contact.FixtureBId ,fixtureA, fixtureB, bodyA, bodyB); + var ev1 = new EndCollideEvent(aUid, bUid, contact.FixtureAId, contact.FixtureBId, fixtureA, fixtureB, bodyA, bodyB); var ev2 = new EndCollideEvent(bUid, aUid, contact.FixtureBId, contact.FixtureAId, fixtureB, fixtureA, bodyB, bodyA); RaiseLocalEvent(aUid, ref ev1); RaiseLocalEvent(bUid, ref ev2); @@ -335,10 +334,10 @@ public abstract partial class SharedPhysicsSystem if (contact.Manifold.PointCount > 0 && contact.FixtureA?.Hard == true && contact.FixtureB?.Hard == true) { if (bodyA.CanCollide) - SetAwake(aUid, bodyA, true); + SetAwake((aUid, bodyA), true); if (bodyB.CanCollide) - SetAwake(bUid, bodyB, true); + SetAwake((bUid, bodyB), true); } // Remove from the world @@ -347,16 +346,19 @@ public abstract partial class SharedPhysicsSystem // Remove from body 1 DebugTools.Assert(fixtureA.Contacts.ContainsKey(fixtureB)); fixtureA.Contacts.Remove(fixtureB); - DebugTools.Assert(bodyA.Contacts.Contains(contact.BodyANode!.Value)); + DebugTools.Assert(bodyA.Contacts.Contains(contact.BodyANode.Value)); bodyA.Contacts.Remove(contact.BodyANode); // Remove from body 2 DebugTools.Assert(fixtureB.Contacts.ContainsKey(fixtureA)); fixtureB.Contacts.Remove(fixtureA); + DebugTools.Assert(bodyB.Contacts.Contains(contact.BodyBNode.Value)); bodyB.Contacts.Remove(contact.BodyBNode); // Insert into the pool. _contactPool.Return(contact); + + return true; } internal void CollideContacts()