Defer physics transforms to ensure thread safety
Refactored multiple components to defer Farseer physics transform operations using PhysicsBodyQueue, preventing unsafe calls from parallel contexts. This change addresses thread safety issues with Farseer's DynamicTree and ensures transforms are executed in a safe context. Also increased the spawn amount limit in DebugConsole from 100 to 100000.
This commit is contained in:
@@ -3225,7 +3225,7 @@ namespace Barotrauma
|
|||||||
if (args.Length > spawnLocationIndex + 1)
|
if (args.Length > spawnLocationIndex + 1)
|
||||||
{
|
{
|
||||||
if (!int.TryParse(args[spawnLocationIndex + 1], NumberStyles.Any, CultureInfo.InvariantCulture, out amount)) { amount = 1; }
|
if (!int.TryParse(args[spawnLocationIndex + 1], NumberStyles.Any, CultureInfo.InvariantCulture, out amount)) { amount = 1; }
|
||||||
amount = Math.Min(amount, 100);
|
amount = Math.Min(amount, 100000);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.Length > spawnLocationIndex + 2)
|
if (args.Length > spawnLocationIndex + 2)
|
||||||
|
|||||||
@@ -314,13 +314,21 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
public override void Move(Vector2 amount, bool ignoreContacts = false)
|
public override void Move(Vector2 amount, bool ignoreContacts = false)
|
||||||
{
|
{
|
||||||
if (ignoreContacts)
|
// Defer physics operation if in parallel context (Farseer is not thread-safe)
|
||||||
|
if (Body != null)
|
||||||
{
|
{
|
||||||
Body?.SetTransformIgnoreContacts(Body.SimPosition + ConvertUnits.ToSimUnits(amount), 0.0f);
|
var capturedBody = Body;
|
||||||
}
|
var capturedNewPos = Body.SimPosition + ConvertUnits.ToSimUnits(amount);
|
||||||
else
|
if (ignoreContacts)
|
||||||
{
|
{
|
||||||
Body?.SetTransform(Body.SimPosition + ConvertUnits.ToSimUnits(amount), 0.0f);
|
PhysicsBodyQueue.ExecuteOrDefer(() =>
|
||||||
|
capturedBody.SetTransformIgnoreContacts(capturedNewPos, 0.0f));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PhysicsBodyQueue.ExecuteOrDefer(() =>
|
||||||
|
capturedBody.SetTransform(capturedNewPos, 0.0f));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#if CLIENT
|
#if CLIENT
|
||||||
UpdateConvexHulls();
|
UpdateConvexHulls();
|
||||||
@@ -786,13 +794,19 @@ namespace Barotrauma.Items.Components
|
|||||||
//immediately teleport it to the correct side
|
//immediately teleport it to the correct side
|
||||||
if (Math.Sign(diff) != dir)
|
if (Math.Sign(diff) != dir)
|
||||||
{
|
{
|
||||||
|
// Defer physics operation if in parallel context (Farseer is not thread-safe)
|
||||||
|
var capturedBody = body;
|
||||||
if (IsHorizontal)
|
if (IsHorizontal)
|
||||||
{
|
{
|
||||||
body.SetTransformIgnoreContacts(new Vector2(body.SimPosition.X, item.SimPosition.Y + dir * doorRectSimSize.Y * 2.0f), body.Rotation);
|
Vector2 newPos = new Vector2(body.SimPosition.X, item.SimPosition.Y + dir * doorRectSimSize.Y * 2.0f);
|
||||||
|
float rotation = body.Rotation;
|
||||||
|
PhysicsBodyQueue.ExecuteOrDefer(() => capturedBody.SetTransformIgnoreContacts(newPos, rotation));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
body.SetTransformIgnoreContacts(new Vector2(item.SimPosition.X + dir * doorRectSimSize.X * 1.2f, body.SimPosition.Y), body.Rotation);
|
Vector2 newPos = new Vector2(item.SimPosition.X + dir * doorRectSimSize.X * 1.2f, body.SimPosition.Y);
|
||||||
|
float rotation = body.Rotation;
|
||||||
|
PhysicsBodyQueue.ExecuteOrDefer(() => capturedBody.SetTransformIgnoreContacts(newPos, rotation));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -92,13 +92,16 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
if (trigger != null && amount.LengthSquared() > 0.00001f)
|
if (trigger != null && amount.LengthSquared() > 0.00001f)
|
||||||
{
|
{
|
||||||
|
// Defer physics operation if in parallel context (Farseer is not thread-safe)
|
||||||
|
var capturedTrigger = trigger;
|
||||||
|
var capturedPos = item.SimPosition;
|
||||||
if (ignoreContacts)
|
if (ignoreContacts)
|
||||||
{
|
{
|
||||||
trigger.SetTransformIgnoreContacts(item.SimPosition, 0.0f);
|
PhysicsBodyQueue.ExecuteOrDefer(() => capturedTrigger.SetTransformIgnoreContacts(capturedPos, 0.0f));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
trigger.SetTransform(item.SimPosition, 0.0f);
|
PhysicsBodyQueue.ExecuteOrDefer(() => capturedTrigger.SetTransform(capturedPos, 0.0f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,7 +137,10 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
if (trigger != null && Vector2.DistanceSquared(item.SimPosition, trigger.SimPosition) > 0.01f)
|
if (trigger != null && Vector2.DistanceSquared(item.SimPosition, trigger.SimPosition) > 0.01f)
|
||||||
{
|
{
|
||||||
trigger.SetTransform(item.SimPosition, 0.0f);
|
// Defer physics operation if in parallel context (Farseer is not thread-safe)
|
||||||
|
var capturedTrigger = trigger;
|
||||||
|
var capturedPos = item.SimPosition;
|
||||||
|
PhysicsBodyQueue.ExecuteOrDefer(() => capturedTrigger.SetTransform(capturedPos, 0.0f));
|
||||||
}
|
}
|
||||||
IsActive = false;
|
IsActive = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1011,7 +1011,11 @@ namespace Barotrauma.Items.Components
|
|||||||
if (flippedX ^ flippedY) { rotation = -rotation; }
|
if (flippedX ^ flippedY) { rotation = -rotation; }
|
||||||
rotation += -item.RotationRad;
|
rotation += -item.RotationRad;
|
||||||
}
|
}
|
||||||
contained.Item.body.FarseerBody.SetTransformIgnoreContacts(ref simPos, rotation);
|
// Defer physics operation if in parallel context (Farseer is not thread-safe)
|
||||||
|
var capturedBody = contained.Item.body.FarseerBody;
|
||||||
|
var capturedSimPos = simPos;
|
||||||
|
var capturedRotation = rotation;
|
||||||
|
PhysicsBodyQueue.ExecuteOrDefer(() => capturedBody.SetTransformIgnoreContacts(ref capturedSimPos, capturedRotation));
|
||||||
contained.Item.body.UpdateDrawPosition(interpolate: false);
|
contained.Item.body.UpdateDrawPosition(interpolate: false);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
|||||||
@@ -312,13 +312,18 @@ namespace Barotrauma.Items.Components
|
|||||||
Matrix transform = Matrix.CreateRotationZ(-item.RotationRad);
|
Matrix transform = Matrix.CreateRotationZ(-item.RotationRad);
|
||||||
offset = Vector2.Transform(offset, transform);
|
offset = Vector2.Transform(offset, transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Defer physics operations if in parallel context (Farseer is not thread-safe)
|
||||||
|
var capturedBody = PhysicsBody;
|
||||||
|
var capturedPos = item.SimPosition + offset;
|
||||||
|
var capturedRot = -item.RotationRad;
|
||||||
if (ignoreContacts)
|
if (ignoreContacts)
|
||||||
{
|
{
|
||||||
PhysicsBody.SetTransformIgnoreContacts(item.SimPosition + offset, -item.RotationRad);
|
PhysicsBodyQueue.ExecuteOrDefer(() => capturedBody.SetTransformIgnoreContacts(capturedPos, capturedRot));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PhysicsBody.SetTransform(item.SimPosition + offset, -item.RotationRad);
|
PhysicsBodyQueue.ExecuteOrDefer(() => capturedBody.SetTransform(capturedPos, capturedRot));
|
||||||
}
|
}
|
||||||
PhysicsBody.UpdateDrawPosition();
|
PhysicsBody.UpdateDrawPosition();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1822,7 +1822,13 @@ namespace Barotrauma
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
body.SetTransformIgnoreContacts(simPosition, rotation, setPrevTransform);
|
// Defer physics operation if in parallel context (Farseer is not thread-safe)
|
||||||
|
var capturedBody = body;
|
||||||
|
var capturedSimPos = simPosition;
|
||||||
|
var capturedRotation = rotation;
|
||||||
|
var capturedSetPrevTransform = setPrevTransform;
|
||||||
|
PhysicsBodyQueue.ExecuteOrDefer(() =>
|
||||||
|
capturedBody.SetTransformIgnoreContacts(capturedSimPos, capturedRotation, capturedSetPrevTransform));
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -1899,13 +1905,19 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (ItemList != null && body != null)
|
if (ItemList != null && body != null)
|
||||||
{
|
{
|
||||||
|
// Defer physics operation if in parallel context (Farseer is not thread-safe)
|
||||||
|
var capturedBody = body;
|
||||||
|
var capturedNewPos = body.SimPosition + ConvertUnits.ToSimUnits(amount);
|
||||||
|
var capturedRotation = body.Rotation;
|
||||||
if (ignoreContacts)
|
if (ignoreContacts)
|
||||||
{
|
{
|
||||||
body.SetTransformIgnoreContacts(body.SimPosition + ConvertUnits.ToSimUnits(amount), body.Rotation);
|
PhysicsBodyQueue.ExecuteOrDefer(() =>
|
||||||
|
capturedBody.SetTransformIgnoreContacts(capturedNewPos, capturedRotation));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
body.SetTransform(body.SimPosition + ConvertUnits.ToSimUnits(amount), body.Rotation);
|
PhysicsBodyQueue.ExecuteOrDefer(() =>
|
||||||
|
capturedBody.SetTransform(capturedNewPos, capturedRotation));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (ItemComponent ic in components)
|
foreach (ItemComponent ic in components)
|
||||||
@@ -2563,7 +2575,12 @@ namespace Barotrauma
|
|||||||
if (item != this)
|
if (item != this)
|
||||||
{
|
{
|
||||||
item.body.Enabled = false;
|
item.body.Enabled = false;
|
||||||
item.body.SetTransformIgnoreContacts(this.SimPosition, body.Rotation);
|
// Defer physics operation if in parallel context (Farseer is not thread-safe)
|
||||||
|
var capturedItemBody = item.body;
|
||||||
|
var capturedSimPos = this.SimPosition;
|
||||||
|
var capturedRotation = body.Rotation;
|
||||||
|
PhysicsBodyQueue.ExecuteOrDefer(() =>
|
||||||
|
capturedItemBody.SetTransformIgnoreContacts(capturedSimPos, capturedRotation));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2755,17 +2772,25 @@ namespace Barotrauma
|
|||||||
FindHull();
|
FindHull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Defer physics transform operations if in parallel context.
|
||||||
|
// Farseer's DynamicTree is not thread-safe.
|
||||||
if (Submarine == null && prevSub != null)
|
if (Submarine == null && prevSub != null)
|
||||||
{
|
{
|
||||||
body.SetTransformIgnoreContacts(body.SimPosition + prevSub.SimPosition, body.Rotation);
|
Vector2 newPos = body.SimPosition + prevSub.SimPosition;
|
||||||
|
float rotation = body.Rotation;
|
||||||
|
PhysicsBodyQueue.ExecuteOrDefer(() => body.SetTransformIgnoreContacts(newPos, rotation));
|
||||||
}
|
}
|
||||||
else if (Submarine != null && prevSub == null)
|
else if (Submarine != null && prevSub == null)
|
||||||
{
|
{
|
||||||
body.SetTransformIgnoreContacts(body.SimPosition - Submarine.SimPosition, body.Rotation);
|
Vector2 newPos = body.SimPosition - Submarine.SimPosition;
|
||||||
|
float rotation = body.Rotation;
|
||||||
|
PhysicsBodyQueue.ExecuteOrDefer(() => body.SetTransformIgnoreContacts(newPos, rotation));
|
||||||
}
|
}
|
||||||
else if (Submarine != null && prevSub != null && Submarine != prevSub)
|
else if (Submarine != null && prevSub != null && Submarine != prevSub)
|
||||||
{
|
{
|
||||||
body.SetTransformIgnoreContacts(body.SimPosition + prevSub.SimPosition - Submarine.SimPosition, body.Rotation);
|
Vector2 newPos = body.SimPosition + prevSub.SimPosition - Submarine.SimPosition;
|
||||||
|
float rotation = body.Rotation;
|
||||||
|
PhysicsBodyQueue.ExecuteOrDefer(() => body.SetTransformIgnoreContacts(newPos, rotation));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Submarine != prevSub)
|
if (Submarine != prevSub)
|
||||||
|
|||||||
Reference in New Issue
Block a user