Fix static ent collision spawn (#5933)

* Fix static ent collision spawn

* Fix test

* cool
This commit is contained in:
metalgearsloth
2025-05-15 19:11:20 +10:00
committed by GitHub
parent 2ac7bc3ce4
commit 73f6555624
3 changed files with 64 additions and 1 deletions

View File

@@ -294,6 +294,14 @@ public abstract partial class SharedPhysicsSystem
DebugTools.Assert(!fixB.Contacts.ContainsKey(fixA));
fixB.Contacts.Add(fixA, contact);
bodB.Contacts.AddLast(contact.BodyBNode);
// If it's a spawned static ent then need to wake any contacting entities.
// The issue is that static ents can never be awake and if it spawns on an asleep entity never gets a contact.
// Checking only bodyA should be okay because if bodyA is the other ent (i.e. dynamic / kinematic) then it should already be awake.
if (bodyA.BodyType == BodyType.Static && !bodyB.Awake)
{
WakeBody(uidB, body: bodyB);
}
}
/// <summary>

View File

@@ -4,6 +4,7 @@ using System.Numerics;
using NUnit.Framework;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Collision.Shapes;
@@ -17,6 +18,61 @@ namespace Robust.UnitTesting.Shared.Physics;
[TestFixture]
public sealed class Broadphase_Test
{
/// <summary>
/// Tests that spawned static ents properly collide with entities in range.
/// </summary>
[Test]
public void TestStaticSpawn()
{
var sim = RobustServerSimulation
.NewSimulation()
.InitializeInstance();
var entManager = sim.Resolve<IEntityManager>();
var fixtureSystem = entManager.System<FixtureSystem>();
var physicsSystem = entManager.System<SharedPhysicsSystem>();
var (mapEnt, mapId) = sim.CreateMap();
var dynamicEnt = entManager.SpawnAtPosition(null, new EntityCoordinates(mapEnt, Vector2.Zero));
var dynamicBody = entManager.AddComponent<PhysicsComponent>(dynamicEnt);
physicsSystem.SetBodyType(dynamicEnt, BodyType.Dynamic, body: dynamicBody);
fixtureSystem.TryCreateFixture(dynamicEnt, new PhysShapeCircle(1f), "fix1", collisionMask: 10);
physicsSystem.WakeBody(dynamicEnt, body: dynamicBody);
Assert.That(dynamicBody.Awake);
physicsSystem.SetAwake((dynamicEnt, dynamicBody), false);
Assert.That(!dynamicBody.Awake);
// Clear move buffer
entManager.System<SharedBroadphaseSystem>().FindNewContacts(
entManager.GetComponent<PhysicsMapComponent>(mapEnt),
entManager.GetComponent<MapComponent>(mapEnt).MapId);
var staticEnt = entManager.SpawnAtPosition(null, new EntityCoordinates(mapEnt, Vector2.Zero));
var staticBody = entManager.AddComponent<PhysicsComponent>(staticEnt);
physicsSystem.SetBodyType(staticEnt, BodyType.Static, body: staticBody);
fixtureSystem.TryCreateFixture(staticEnt, new PhysShapeCircle(1f), "fix1", collisionLayer: 10);
physicsSystem.SetCanCollide(staticEnt, true);
Assert.That(!staticBody.Awake);
Assert.That(staticBody.ContactCount, Is.EqualTo(0));
entManager.System<SharedBroadphaseSystem>().FindNewContacts(
entManager.GetComponent<PhysicsMapComponent>(mapEnt),
entManager.GetComponent<MapComponent>(mapEnt).MapId);
Assert.That(staticBody.ContactCount, Is.EqualTo(1));
physicsSystem.CollideContacts();
// Make sure it's actually marked as touching and not just "well it's in range right".
Assert.That(staticBody.Contacts.First!.Value.IsTouching, Is.EqualTo(true));
}
/// <summary>
/// If we reparent a sundries entity to another broadphase does it correctly update.
/// </summary>

View File

@@ -24,7 +24,6 @@ namespace Robust.UnitTesting.Shared.Physics
var server = StartServer();
await server.WaitIdleAsync();
var entManager = server.ResolveDependency<IEntityManager>();
var mapManager = server.ResolveDependency<IMapManager>();
var fixtureSystem = server.ResolveDependency<IEntitySystemManager>()
.GetEntitySystem<FixtureSystem>();
var physicsSystem = server.ResolveDependency<IEntitySystemManager>()