Fix concurrent access issues with ConnectedClients
Replaced direct access to GameMain.Server.ConnectedClients with array snapshots in multiple server-side classes to prevent concurrent modification issues during parallel updates. Also updated PhysicsBody and LevelTrigger to avoid static/shared state in parallel contexts, improving thread safety and reliability.
This commit is contained in:
@@ -28,11 +28,14 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create snapshot to avoid concurrent access issues during parallel updates
|
||||||
|
var clients = GameMain.Server.ConnectedClients.ToArray();
|
||||||
|
|
||||||
if (GameMain.Server is { ServerSettings.RespawnMode: RespawnMode.Permadeath } &&
|
if (GameMain.Server is { ServerSettings.RespawnMode: RespawnMode.Permadeath } &&
|
||||||
GameMain.GameSession?.Campaign is MultiPlayerCampaign mpCampaign &&
|
GameMain.GameSession?.Campaign is MultiPlayerCampaign mpCampaign &&
|
||||||
causeOfDeath != CauseOfDeathType.Disconnected)
|
causeOfDeath != CauseOfDeathType.Disconnected)
|
||||||
{
|
{
|
||||||
Client ownerClient = GameMain.Server.ConnectedClients.FirstOrDefault(c => c.Character == this);
|
Client ownerClient = clients.FirstOrDefault(c => c.Character == this);
|
||||||
if (ownerClient != null)
|
if (ownerClient != null)
|
||||||
{
|
{
|
||||||
ownerClient.SpectateOnly = true;
|
ownerClient.SpectateOnly = true;
|
||||||
@@ -51,7 +54,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (HasAbilityFlag(AbilityFlags.RetainExperienceForNewCharacter))
|
if (HasAbilityFlag(AbilityFlags.RetainExperienceForNewCharacter))
|
||||||
{
|
{
|
||||||
var ownerClient = GameMain.Server.ConnectedClients.Find(c => c.Character == this);
|
var ownerClient = clients.FirstOrDefault(c => c.Character == this);
|
||||||
if (ownerClient != null)
|
if (ownerClient != null)
|
||||||
{
|
{
|
||||||
(GameMain.GameSession?.GameMode as MultiPlayerCampaign)?.SaveExperiencePoints(ownerClient);
|
(GameMain.GameSession?.GameMode as MultiPlayerCampaign)?.SaveExperiencePoints(ownerClient);
|
||||||
@@ -62,7 +65,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (CauseOfDeath.Killer != null && CauseOfDeath.Killer.IsTraitor && CauseOfDeath.Killer != this)
|
if (CauseOfDeath.Killer != null && CauseOfDeath.Killer.IsTraitor && CauseOfDeath.Killer != this)
|
||||||
{
|
{
|
||||||
var owner = GameMain.Server.ConnectedClients.Find(c => c.Character == this);
|
var owner = clients.FirstOrDefault(c => c.Character == this);
|
||||||
if (owner != null)
|
if (owner != null)
|
||||||
{
|
{
|
||||||
if (!GameMain.LuaCs.Game.overrideTraitors)
|
if (!GameMain.LuaCs.Game.overrideTraitors)
|
||||||
@@ -71,7 +74,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (Client client in GameMain.Server.ConnectedClients)
|
foreach (Client client in clients)
|
||||||
{
|
{
|
||||||
if (client.InGame)
|
if (client.InGame)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -490,7 +490,9 @@ namespace Barotrauma
|
|||||||
case ControlEventData controlEventData:
|
case ControlEventData controlEventData:
|
||||||
Client owner = controlEventData.Owner;
|
Client owner = controlEventData.Owner;
|
||||||
msg.WriteBoolean(owner == c && owner.Character == this);
|
msg.WriteBoolean(owner == c && owner.Character == this);
|
||||||
msg.WriteByte(owner != null && owner.Character == this && GameMain.Server.ConnectedClients.Contains(owner) ? owner.SessionId : (byte)0);
|
// Create snapshot to avoid concurrent access issues during parallel updates
|
||||||
|
var connectedClients = GameMain.Server.ConnectedClients.ToArray();
|
||||||
|
msg.WriteByte(owner != null && owner.Character == this && connectedClients.Contains(owner) ? owner.SessionId : (byte)0);
|
||||||
msg.WriteBoolean(info is { RenamingEnabled: true });
|
msg.WriteBoolean(info is { RenamingEnabled: true });
|
||||||
break;
|
break;
|
||||||
case CharacterStatusEventData statusEventData:
|
case CharacterStatusEventData statusEventData:
|
||||||
@@ -746,7 +748,9 @@ namespace Barotrauma
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Client ownerClient = GameMain.Server.ConnectedClients.Find(c => c.Character == this && (!c.SpectateOnly || !GameMain.Server.ServerSettings.AllowSpectating));
|
// Create snapshot to avoid concurrent access issues during parallel updates
|
||||||
|
var clients = GameMain.Server.ConnectedClients.ToArray();
|
||||||
|
Client ownerClient = clients.FirstOrDefault(c => c.Character == this && (!c.SpectateOnly || !GameMain.Server.ServerSettings.AllowSpectating));
|
||||||
if (ownerClient != null)
|
if (ownerClient != null)
|
||||||
{
|
{
|
||||||
msg.WriteBoolean(true);
|
msg.WriteBoolean(true);
|
||||||
|
|||||||
@@ -82,10 +82,13 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private bool IsBlockedByAnotherConversation(IEnumerable<Entity> targets, float duration)
|
private bool IsBlockedByAnotherConversation(IEnumerable<Entity> targets, float duration)
|
||||||
{
|
{
|
||||||
|
// Create snapshot to avoid concurrent access issues during parallel updates
|
||||||
|
var clients = GameMain.Server.ConnectedClients.ToArray();
|
||||||
|
|
||||||
if (targets == null || targets.None())
|
if (targets == null || targets.None())
|
||||||
{
|
{
|
||||||
//if the action doesn't target anyone in specific, it's shown to every client
|
//if the action doesn't target anyone in specific, it's shown to every client
|
||||||
foreach (var client in GameMain.Server.ConnectedClients)
|
foreach (var client in clients)
|
||||||
{
|
{
|
||||||
if (IsBlockedByAnotherConversation(client, duration)) { return true; }
|
if (IsBlockedByAnotherConversation(client, duration)) { return true; }
|
||||||
}
|
}
|
||||||
@@ -95,7 +98,7 @@ namespace Barotrauma
|
|||||||
foreach (Entity e in targets)
|
foreach (Entity e in targets)
|
||||||
{
|
{
|
||||||
if (e is not Character character || !character.IsRemotePlayer) { continue; }
|
if (e is not Character character || !character.IsRemotePlayer) { continue; }
|
||||||
Client targetClient = GameMain.Server.ConnectedClients.Find(c => c.Character == character);
|
Client targetClient = clients.FirstOrDefault(c => c.Character == character);
|
||||||
if (targetClient != null && IsBlockedByAnotherConversation(targetClient, duration)) { return true; }
|
if (targetClient != null && IsBlockedByAnotherConversation(targetClient, duration)) { return true; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,13 +120,16 @@ namespace Barotrauma
|
|||||||
partial void ShowDialog(Character speaker, Character targetCharacter)
|
partial void ShowDialog(Character speaker, Character targetCharacter)
|
||||||
{
|
{
|
||||||
targetClients.Clear();
|
targetClients.Clear();
|
||||||
|
// Create snapshot to avoid concurrent access issues during parallel updates
|
||||||
|
var clients = GameMain.Server.ConnectedClients.ToArray();
|
||||||
|
|
||||||
if (!TargetTag.IsEmpty)
|
if (!TargetTag.IsEmpty)
|
||||||
{
|
{
|
||||||
IEnumerable<Entity> entities = ParentEvent.GetTargets(TargetTag);
|
IEnumerable<Entity> entities = ParentEvent.GetTargets(TargetTag);
|
||||||
foreach (Entity e in entities)
|
foreach (Entity e in entities)
|
||||||
{
|
{
|
||||||
if (e is not Character character || !character.IsRemotePlayer) { continue; }
|
if (e is not Character character || !character.IsRemotePlayer) { continue; }
|
||||||
Client targetClient = GameMain.Server.ConnectedClients.Find(c => c.Character == character);
|
Client targetClient = clients.FirstOrDefault(c => c.Character == character);
|
||||||
if (targetClient != null)
|
if (targetClient != null)
|
||||||
{
|
{
|
||||||
targetClients.Add(targetClient);
|
targetClients.Add(targetClient);
|
||||||
@@ -135,7 +141,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (Client c in GameMain.Server.ConnectedClients)
|
foreach (Client c in clients)
|
||||||
{
|
{
|
||||||
if (CanClientReceive(c))
|
if (CanClientReceive(c))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,48 +9,52 @@ namespace Barotrauma;
|
|||||||
|
|
||||||
partial class EventLogAction : EventAction
|
partial class EventLogAction : EventAction
|
||||||
{
|
{
|
||||||
partial void AddEntryProjSpecific(EventLog? eventLog, string displayText)
|
partial void AddEntryProjSpecific(EventLog? eventLog, string displayText)
|
||||||
|
{
|
||||||
|
if (eventLog == null) { return; }
|
||||||
|
|
||||||
|
// Create snapshot to avoid concurrent access issues during parallel updates
|
||||||
|
var clients = GameMain.Server.ConnectedClients.ToArray();
|
||||||
|
|
||||||
|
if (!TargetTag.IsEmpty)
|
||||||
{
|
{
|
||||||
if (eventLog == null) { return; }
|
List<Client> targetClients = new List<Client>();
|
||||||
if (!TargetTag.IsEmpty)
|
foreach (var target in ParentEvent.GetTargets(TargetTag))
|
||||||
{
|
{
|
||||||
List<Client> targetClients = new List<Client>();
|
if (target is Character character)
|
||||||
foreach (var target in ParentEvent.GetTargets(TargetTag))
|
|
||||||
{
|
{
|
||||||
if (target is Character character)
|
var ownerClient = clients.FirstOrDefault(c => c.Character == character);
|
||||||
|
if (ownerClient != null)
|
||||||
{
|
{
|
||||||
var ownerClient = GameMain.Server.ConnectedClients.Find(c => c.Character == character);
|
targetClients.Add(ownerClient);
|
||||||
if (ownerClient != null)
|
|
||||||
{
|
|
||||||
targetClients.Add(ownerClient);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DebugConsole.AddWarning($"{target} is not a valid target for an EventLogAction. The target should be a character.",
|
|
||||||
ParentEvent.Prefab.ContentPackage);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (eventLog!.TryAddEntry(ParentEvent.Prefab.Identifier, Id, displayText, targetClients) && ShowInServerLog)
|
else
|
||||||
{
|
{
|
||||||
Log(targetClients);
|
DebugConsole.AddWarning($"{target} is not a valid target for an EventLogAction. The target should be a character.",
|
||||||
|
ParentEvent.Prefab.ContentPackage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
if (eventLog!.TryAddEntry(ParentEvent.Prefab.Identifier, Id, displayText, targetClients) && ShowInServerLog)
|
||||||
{
|
{
|
||||||
if (eventLog.TryAddEntry(ParentEvent.Prefab.Identifier, Id, displayText, GameMain.Server.ConnectedClients) && ShowInServerLog)
|
Log(targetClients);
|
||||||
{
|
|
||||||
Log(targetClients: null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Log(List<Client>? targetClients)
|
|
||||||
{
|
|
||||||
string clientStr = targetClients == null || targetClients.None() ?
|
|
||||||
string.Empty :
|
|
||||||
$" ({string.Join(", ", targetClients.Select(c => NetworkMember.ClientLogName(c)))})";
|
|
||||||
GameServer.Log($"Event \"{ParentEvent.Prefab.Name}\"{clientStr}: " + displayText,
|
|
||||||
ParentEvent is TraitorEvent ? ServerLog.MessageType.Traitors : ServerLog.MessageType.Chat);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (eventLog.TryAddEntry(ParentEvent.Prefab.Identifier, Id, displayText, clients) && ShowInServerLog)
|
||||||
|
{
|
||||||
|
Log(targetClients: null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Log(List<Client>? targetClients)
|
||||||
|
{
|
||||||
|
string clientStr = targetClients == null || targetClients.None() ?
|
||||||
|
string.Empty :
|
||||||
|
$" ({string.Join(", ", targetClients.Select(c => NetworkMember.ClientLogName(c)))})";
|
||||||
|
GameServer.Log($"Event \"{ParentEvent.Prefab.Name}\"{clientStr}: " + displayText,
|
||||||
|
ParentEvent is TraitorEvent ? ServerLog.MessageType.Traitors : ServerLog.MessageType.Chat);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+8
-3
@@ -1,3 +1,5 @@
|
|||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
partial class EventObjectiveAction : EventAction
|
partial class EventObjectiveAction : EventAction
|
||||||
@@ -13,9 +15,12 @@ namespace Barotrauma
|
|||||||
ParentObjectiveId,
|
ParentObjectiveId,
|
||||||
CanBeCompleted);
|
CanBeCompleted);
|
||||||
|
|
||||||
|
// Create snapshot to avoid concurrent access issues during parallel updates
|
||||||
|
var clients = GameMain.Server.ConnectedClients.ToArray();
|
||||||
|
|
||||||
if (TargetTag.IsEmpty)
|
if (TargetTag.IsEmpty)
|
||||||
{
|
{
|
||||||
foreach (var client in GameMain.Server.ConnectedClients)
|
foreach (var client in clients)
|
||||||
{
|
{
|
||||||
if (client.Character == null) { continue; }
|
if (client.Character == null) { continue; }
|
||||||
EventManager.ServerWriteObjective(client, objective);
|
EventManager.ServerWriteObjective(client, objective);
|
||||||
@@ -26,11 +31,11 @@ namespace Barotrauma
|
|||||||
foreach (var target in ParentEvent.GetTargets(TargetTag))
|
foreach (var target in ParentEvent.GetTargets(TargetTag))
|
||||||
{
|
{
|
||||||
if (target is not Character character) { continue; }
|
if (target is not Character character) { continue; }
|
||||||
var ownerClient = GameMain.Server.ConnectedClients.Find(c => c.Character == character);
|
var ownerClient = clients.FirstOrDefault(c => c.Character == character);
|
||||||
if (ownerClient == null) { continue; }
|
if (ownerClient == null) { continue; }
|
||||||
EventManager.ServerWriteObjective(ownerClient, objective);
|
EventManager.ServerWriteObjective(ownerClient, objective);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,10 @@ partial class HighlightAction : EventAction
|
|||||||
IEnumerable<Client>? targetClients = null;
|
IEnumerable<Client>? targetClients = null;
|
||||||
if (targetCharacters != null)
|
if (targetCharacters != null)
|
||||||
{
|
{
|
||||||
|
// Create snapshot to avoid concurrent access issues during parallel updates
|
||||||
|
var clients = GameMain.Server.ConnectedClients.ToArray();
|
||||||
targetClients = targetCharacters
|
targetClients = targetCharacters
|
||||||
.Select(c => GameMain.Server.ConnectedClients.FirstOrDefault(client => client.Character == c))
|
.Select(c => clients.FirstOrDefault(client => client.Character == c))
|
||||||
.Where(c => c != null)!;
|
.Where(c => c != null)!;
|
||||||
}
|
}
|
||||||
GameMain.Server?.CreateEntityEvent(item, new Item.SetHighlightEventData(State, highlightColor, targetClients));
|
GameMain.Server?.CreateEntityEvent(item, new Item.SetHighlightEventData(State, highlightColor, targetClients));
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Barotrauma.Networking;
|
using Barotrauma.Networking;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
@@ -22,7 +23,9 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private static void NotifyMissionUnlock(Mission mission)
|
private static void NotifyMissionUnlock(Mission mission)
|
||||||
{
|
{
|
||||||
foreach (Client client in GameMain.Server.ConnectedClients)
|
// Create snapshot to avoid concurrent access issues during parallel updates
|
||||||
|
var clients = GameMain.Server.ConnectedClients.ToArray();
|
||||||
|
foreach (Client client in clients)
|
||||||
{
|
{
|
||||||
NotifyMissionUnlock(mission, client);
|
NotifyMissionUnlock(mission, client);
|
||||||
}
|
}
|
||||||
@@ -40,4 +43,4 @@ namespace Barotrauma
|
|||||||
GameMain.Server.ServerPeer.Send(outmsg, client.Connection, DeliveryMethod.Reliable);
|
GameMain.Server.ServerPeer.Send(outmsg, client.Connection, DeliveryMethod.Reliable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,4 +25,4 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,9 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
var (msg, deliveryMethod) = PrepareToSend(opcode, data);
|
var (msg, deliveryMethod) = PrepareToSend(opcode, data);
|
||||||
|
|
||||||
foreach (Client client in GameMain.Server.ConnectedClients)
|
// Create snapshot to avoid concurrent access issues during parallel updates
|
||||||
|
var clients = GameMain.Server.ConnectedClients.ToArray();
|
||||||
|
foreach (Client client in clients)
|
||||||
{
|
{
|
||||||
if (predicate is not null && !predicate(client)) { continue; }
|
if (predicate is not null && !predicate(client)) { continue; }
|
||||||
|
|
||||||
@@ -391,4 +393,4 @@ namespace Barotrauma.Items.Components
|
|||||||
CreateServerEvent(new CircuitBoxServerUpdateSelection(nodes, wires, ios, labels));
|
CreateServerEvent(new CircuitBoxServerUpdateSelection(nodes, wires, ios, labels));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ namespace Barotrauma
|
|||||||
|
|
||||||
//don't create updates if all clients are very far from the hull
|
//don't create updates if all clients are very far from the hull
|
||||||
float hullUpdateDistanceSqr = NetConfig.HullUpdateDistance * NetConfig.HullUpdateDistance;
|
float hullUpdateDistanceSqr = NetConfig.HullUpdateDistance * NetConfig.HullUpdateDistance;
|
||||||
if (!GameMain.Server.ConnectedClients.Any(c =>
|
// Create snapshot to avoid concurrent access issues during parallel updates
|
||||||
|
var clients = GameMain.Server.ConnectedClients.ToArray();
|
||||||
|
if (!clients.Any(c =>
|
||||||
(c.Character != null && Vector2.DistanceSquared(c.Character.WorldPosition, WorldPosition) < hullUpdateDistanceSqr) ||
|
(c.Character != null && Vector2.DistanceSquared(c.Character.WorldPosition, WorldPosition) < hullUpdateDistanceSqr) ||
|
||||||
(c.SpectatePos != null && Vector2.DistanceSquared(c.SpectatePos.Value, WorldPosition) < hullUpdateDistanceSqr)) )
|
(c.SpectatePos != null && Vector2.DistanceSquared(c.SpectatePos.Value, WorldPosition) < hullUpdateDistanceSqr)) )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4799,7 +4799,9 @@ namespace Barotrauma.Networking
|
|||||||
public static string CharacterLogName(Character character)
|
public static string CharacterLogName(Character character)
|
||||||
{
|
{
|
||||||
if (character == null) { return "[NULL]"; }
|
if (character == null) { return "[NULL]"; }
|
||||||
Client client = GameMain.Server.ConnectedClients.Find(c => c.Character == character);
|
// Create snapshot to avoid concurrent access issues during parallel updates
|
||||||
|
var clients = GameMain.Server.ConnectedClients.ToArray();
|
||||||
|
Client client = clients.FirstOrDefault(c => c.Character == character);
|
||||||
return ClientLogName(client, character.LogName);
|
return ClientLogName(client, character.LogName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4810,8 +4812,8 @@ namespace Barotrauma.Networking
|
|||||||
GameMain.LuaCs?.Hook?.Call("serverLog", line, messageType);
|
GameMain.LuaCs?.Hook?.Call("serverLog", line, messageType);
|
||||||
|
|
||||||
GameMain.Server.ServerSettings.ServerLog.WriteLine(line, messageType);
|
GameMain.Server.ServerSettings.ServerLog.WriteLine(line, messageType);
|
||||||
|
var clients = GameMain.Server.ConnectedClients.ToArray();
|
||||||
foreach (Client client in GameMain.Server.ConnectedClients)
|
foreach (Client client in clients)
|
||||||
{
|
{
|
||||||
if (!client.HasPermission(ClientPermissions.ServerLog)) continue;
|
if (!client.HasPermission(ClientPermissions.ServerLog)) continue;
|
||||||
//use sendername as the message type
|
//use sendername as the message type
|
||||||
|
|||||||
@@ -673,13 +673,17 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly List<Entity> triggerersToRemove = new List<Entity>();
|
|
||||||
public static void RemoveInActiveTriggerers(PhysicsBody physicsBody, HashSet<Entity> triggerers)
|
public static void RemoveInActiveTriggerers(PhysicsBody physicsBody, HashSet<Entity> triggerers)
|
||||||
{
|
{
|
||||||
if (physicsBody == null) { return; }
|
if (physicsBody == null) { return; }
|
||||||
|
|
||||||
triggerersToRemove.Clear();
|
// Use local list instead of static field to avoid concurrent access issues during parallel updates
|
||||||
foreach (var triggerer in triggerers)
|
var triggerersToRemove = new List<Entity>();
|
||||||
|
|
||||||
|
// Create snapshot to avoid concurrent modification during enumeration
|
||||||
|
var triggererSnapshot = triggerers.ToArray();
|
||||||
|
|
||||||
|
foreach (var triggerer in triggererSnapshot)
|
||||||
{
|
{
|
||||||
if (triggerer.Removed)
|
if (triggerer.Removed)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -834,6 +834,12 @@ namespace Barotrauma
|
|||||||
if (!IsValidValue(simPosition, "position", -1e10f, 1e10f)) { return false; }
|
if (!IsValidValue(simPosition, "position", -1e10f, 1e10f)) { return false; }
|
||||||
if (!IsValidValue(rotation, "rotation")) { return false; }
|
if (!IsValidValue(rotation, "rotation")) { return false; }
|
||||||
|
|
||||||
|
if (PhysicsBodyQueue.IsInParallelContext)
|
||||||
|
{
|
||||||
|
PhysicsBodyQueue.Enqueue(() => SetTransform(simPosition, rotation, setPrevTransform));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
FarseerBody.SetTransform(simPosition, rotation);
|
FarseerBody.SetTransform(simPosition, rotation);
|
||||||
if (setPrevTransform) { SetPrevTransform(simPosition, rotation); }
|
if (setPrevTransform) { SetPrevTransform(simPosition, rotation); }
|
||||||
return true;
|
return true;
|
||||||
@@ -848,6 +854,12 @@ namespace Barotrauma
|
|||||||
if (!IsValidValue(simPosition, "position", -1e10f, 1e10f)) { return false; }
|
if (!IsValidValue(simPosition, "position", -1e10f, 1e10f)) { return false; }
|
||||||
if (!IsValidValue(rotation, "rotation")) { return false; }
|
if (!IsValidValue(rotation, "rotation")) { return false; }
|
||||||
|
|
||||||
|
if (PhysicsBodyQueue.IsInParallelContext)
|
||||||
|
{
|
||||||
|
PhysicsBodyQueue.Enqueue(() => SetTransformIgnoreContacts(simPosition, rotation, setPrevTransform));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
FarseerBody.SetTransformIgnoreContacts(ref simPosition, rotation);
|
FarseerBody.SetTransformIgnoreContacts(ref simPosition, rotation);
|
||||||
if (setPrevTransform) { SetPrevTransform(simPosition, rotation); }
|
if (setPrevTransform) { SetPrevTransform(simPosition, rotation); }
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
Reference in New Issue
Block a user