Unstable Add thread-safe queue for deferred physics body creation

Introduces PhysicsBodyQueue to safely defer physics body creation to the main thread, addressing thread-safety issues with Farseer Physics during parallel updates. Updates LevelResource, TriggerComponent, BallastFloraBehavior, and MapEntity to use the queue for all physics body creation and refresh operations, ensuring they are processed outside of parallel loops. Also adds cleanup of the queue at round end.
This commit is contained in:
Eero
2025-12-28 14:42:17 +08:00
parent 45312af297
commit 49355fe32b
6 changed files with 191 additions and 9 deletions
@@ -73,6 +73,11 @@ namespace Barotrauma.Items.Components
public PhysicsBody PhysicsBody { get; private set; }
/// <summary>
/// Flag to prevent multiple queued refresh requests.
/// </summary>
private volatile bool physicsBodyRefreshQueued;
private float radius;
[Editable, Serialize(0.0f, IsPropertySaveable.Yes)]
public float Radius
@@ -83,7 +88,7 @@ namespace Barotrauma.Items.Components
{
if (radius == value) { return; }
radius = value;
if (PhysicsBody != null) { RefreshPhysicsBodySize(); }
if (PhysicsBody != null) { QueuePhysicsBodyRefresh(); }
}
}
@@ -97,7 +102,7 @@ namespace Barotrauma.Items.Components
{
if (width == value) { return; }
width = value;
if (PhysicsBody != null) { RefreshPhysicsBodySize(); }
if (PhysicsBody != null) { QueuePhysicsBodyRefresh(); }
}
}
@@ -111,10 +116,28 @@ namespace Barotrauma.Items.Components
{
if (height == value) { return; }
height = value;
if (PhysicsBody != null) { RefreshPhysicsBodySize(); }
if (PhysicsBody != null) { QueuePhysicsBodyRefresh(); }
}
}
/// <summary>
/// Queue the physics body refresh to be executed on the main thread.
/// This is necessary because physics body operations are not thread-safe.
/// </summary>
private void QueuePhysicsBodyRefresh()
{
if (physicsBodyRefreshQueued) { return; }
physicsBodyRefreshQueued = true;
PhysicsBodyQueue.EnqueueCreation(() =>
{
if (!item.Removed)
{
RefreshPhysicsBodySize();
}
physicsBodyRefreshQueued = false;
});
}
private float currentRadius, currentWidth, currentHeight;
private Vector2 bodyOffset;