diff --git a/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs b/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs index 5cdfefe6a..fb2cacc66 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs @@ -3225,7 +3225,7 @@ namespace Barotrauma if (args.Length > spawnLocationIndex + 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) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Door.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Door.cs index fad7c7fab..b3de4b02b 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Door.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Door.cs @@ -314,13 +314,21 @@ namespace Barotrauma.Items.Components 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); - } - else - { - Body?.SetTransform(Body.SimPosition + ConvertUnits.ToSimUnits(amount), 0.0f); + var capturedBody = Body; + var capturedNewPos = Body.SimPosition + ConvertUnits.ToSimUnits(amount); + if (ignoreContacts) + { + PhysicsBodyQueue.ExecuteOrDefer(() => + capturedBody.SetTransformIgnoreContacts(capturedNewPos, 0.0f)); + } + else + { + PhysicsBodyQueue.ExecuteOrDefer(() => + capturedBody.SetTransform(capturedNewPos, 0.0f)); + } } #if CLIENT UpdateConvexHulls(); @@ -786,13 +794,19 @@ namespace Barotrauma.Items.Components //immediately teleport it to the correct side if (Math.Sign(diff) != dir) { + // Defer physics operation if in parallel context (Farseer is not thread-safe) + var capturedBody = body; 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 { - 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)); } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/LevelResource.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/LevelResource.cs index 797ec14e7..5c672cda5 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/LevelResource.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/LevelResource.cs @@ -92,13 +92,16 @@ namespace Barotrauma.Items.Components { 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) { - trigger.SetTransformIgnoreContacts(item.SimPosition, 0.0f); + PhysicsBodyQueue.ExecuteOrDefer(() => capturedTrigger.SetTransformIgnoreContacts(capturedPos, 0.0f)); } 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) { - 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; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/ItemContainer.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/ItemContainer.cs index 722b63588..992b4bfc6 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/ItemContainer.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/ItemContainer.cs @@ -1011,7 +1011,11 @@ namespace Barotrauma.Items.Components if (flippedX ^ flippedY) { rotation = -rotation; } 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); } catch (Exception e) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/TriggerComponent.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/TriggerComponent.cs index c839d488c..228df8dc9 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/TriggerComponent.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/TriggerComponent.cs @@ -312,13 +312,18 @@ namespace Barotrauma.Items.Components Matrix transform = Matrix.CreateRotationZ(-item.RotationRad); 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) { - PhysicsBody.SetTransformIgnoreContacts(item.SimPosition + offset, -item.RotationRad); + PhysicsBodyQueue.ExecuteOrDefer(() => capturedBody.SetTransformIgnoreContacts(capturedPos, capturedRot)); } else { - PhysicsBody.SetTransform(item.SimPosition + offset, -item.RotationRad); + PhysicsBodyQueue.ExecuteOrDefer(() => capturedBody.SetTransform(capturedPos, capturedRot)); } PhysicsBody.UpdateDrawPosition(); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs index 2ce5e3d2d..8ad7bfea1 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs @@ -1822,7 +1822,13 @@ namespace Barotrauma try { #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 } catch (Exception e) @@ -1899,13 +1905,19 @@ namespace Barotrauma 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) { - body.SetTransformIgnoreContacts(body.SimPosition + ConvertUnits.ToSimUnits(amount), body.Rotation); + PhysicsBodyQueue.ExecuteOrDefer(() => + capturedBody.SetTransformIgnoreContacts(capturedNewPos, capturedRotation)); } else { - body.SetTransform(body.SimPosition + ConvertUnits.ToSimUnits(amount), body.Rotation); + PhysicsBodyQueue.ExecuteOrDefer(() => + capturedBody.SetTransform(capturedNewPos, capturedRotation)); } } foreach (ItemComponent ic in components) @@ -2563,7 +2575,12 @@ namespace Barotrauma if (item != this) { 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(); } + // Defer physics transform operations if in parallel context. + // Farseer's DynamicTree is not thread-safe. 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) { - 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) { - 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)