Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Barotrauma/BarotraumaClient/ClientSource/DebugConsole.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1388,12 +1388,12 @@ async Task gameOwnershipTokenTest()
if (me.SimPosition.Length() > 2000.0f)
{
NewMessage("Removed " + me.Name + " (simposition " + me.SimPosition + ")", Color.Orange);
MapEntity.MapEntityList.RemoveAt(i);
MapEntity.MapEntityList.Remove(me);
}
else if (!me.ShouldBeSaved)
{
NewMessage("Removed " + me.Name + " (!ShouldBeSaved)", Color.Orange);
MapEntity.MapEntityList.RemoveAt(i);
MapEntity.MapEntityList.Remove(me);
}
else if (me is Item)
{
Expand Down
12 changes: 6 additions & 6 deletions Barotrauma/BarotraumaClient/ClientSource/Events/EventManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ partial class EventManager

public void DebugDraw(SpriteBatch spriteBatch)
{
foreach (Event ev in activeEvents)
foreach (Event ev in _activeEvents)
{
Vector2 drawPos = ev.DebugDrawPos;
drawPos.Y = -drawPos.Y;
Expand All @@ -41,7 +41,7 @@ public void DebugDraw(SpriteBatch spriteBatch)

public void DebugDrawHUD(SpriteBatch spriteBatch, float y)
{
foreach (ScriptedEvent scriptedEvent in activeEvents.Where(ev => !ev.IsFinished && ev is ScriptedEvent).Cast<ScriptedEvent>())
foreach (ScriptedEvent scriptedEvent in _activeEvents.Where(ev => !ev.IsFinished && ev is ScriptedEvent).Cast<ScriptedEvent>())
{
DrawEventTargetTags(spriteBatch, scriptedEvent);
}
Expand Down Expand Up @@ -156,7 +156,7 @@ void DrawTimeStamps(SpriteBatch sBatch, Color color, Vector2 pos, int order)
{
if (isGraphHovered || isGraphSelected)
{
foreach (var timeStamp in timeStamps)
foreach (var timeStamp in _timeStamps)
{
int t = (int)Math.Abs(Math.Round((timeStamp.Time - lastIntensityUpdate) / intensityGraphUpdateInterval));
if (t == order)
Expand Down Expand Up @@ -205,7 +205,7 @@ void DrawTimeStamps(SpriteBatch sBatch, Color color, Vector2 pos, int order)
}

adjustedYStep = GUI.AdjustForTextScale(12);
foreach (EventSet eventSet in pendingEventSets)
foreach (EventSet eventSet in _pendingEventSets)
{
if (Submarine.MainSub == null) { break; }

Expand Down Expand Up @@ -263,7 +263,7 @@ void DrawTimeStamps(SpriteBatch sBatch, Color color, Vector2 pos, int order)
y += yStep;

adjustedYStep = GUI.AdjustForTextScale(18);
foreach (Event ev in activeEvents.Where(ev => !ev.IsFinished || PlayerInput.IsShiftDown()))
foreach (Event ev in _activeEvents.Where(ev => !ev.IsFinished || PlayerInput.IsShiftDown()))
{
GUI.DrawString(spriteBatch, new Vector2(x + 5, y), ev.ToString(), (!ev.IsFinished ? Color.White : Color.Red) * 0.8f, null, 0, GUIStyle.SmallFont);

Expand Down Expand Up @@ -752,4 +752,4 @@ private static void ClientReadEventObjective(GameClient client, IReadMessage msg
entry.CanBeCompleted);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1933,7 +1933,7 @@ private void DrawMarker(SpriteBatch spriteBatch, string label, Identifier iconId

void CalculateDistance()
{
pathFinder ??= new PathFinder(WayPoint.WayPointList, false);
pathFinder ??= new PathFinder(WayPoint.WayPointList.ToList(), false);
var path = pathFinder.FindPath(ConvertUnits.ToSimUnits(transducerPosition), ConvertUnits.ToSimUnits(worldPosition));
if (!path.Unreachable)
{
Expand Down
10 changes: 5 additions & 5 deletions Barotrauma/BarotraumaClient/ClientSource/Map/Submarine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public static void ForceRemoveFromVisibleEntities(MapEntity entity)

public static void Draw(SpriteBatch spriteBatch, bool editing = false)
{
var entitiesToRender = !editing && visibleEntities != null ? visibleEntities : MapEntity.MapEntityList;
var entitiesToRender = !editing && visibleEntities != null ? visibleEntities : MapEntity.MapEntityList.ToList();

foreach (MapEntity e in entitiesToRender)
{
Expand All @@ -115,7 +115,7 @@ public static void Draw(SpriteBatch spriteBatch, bool editing = false)

public static void DrawFront(SpriteBatch spriteBatch, bool editing = false, Predicate<MapEntity> predicate = null)
{
var entitiesToRender = !editing && visibleEntities != null ? visibleEntities : MapEntity.MapEntityList;
var entitiesToRender = !editing && visibleEntities != null ? visibleEntities : MapEntity.MapEntityList.ToList();

foreach (MapEntity e in entitiesToRender)
{
Expand Down Expand Up @@ -164,7 +164,7 @@ public static void DrawFront(SpriteBatch spriteBatch, bool editing = false, Pred

public static void DrawDamageable(SpriteBatch spriteBatch, Effect damageEffect, bool editing = false, Predicate<MapEntity> predicate = null)
{
var entitiesToRender = !editing && visibleEntities != null ? visibleEntities : MapEntity.MapEntityList;
var entitiesToRender = !editing && visibleEntities != null ? visibleEntities : MapEntity.MapEntityList.ToList();

depthSortedDamageable.Clear();

Expand Down Expand Up @@ -197,7 +197,7 @@ public static void DrawDamageable(SpriteBatch spriteBatch, Effect damageEffect,

public static void DrawPaintedColors(SpriteBatch spriteBatch, bool editing = false, Predicate<MapEntity> predicate = null)
{
var entitiesToRender = !editing && visibleEntities != null ? visibleEntities : MapEntity.MapEntityList;
var entitiesToRender = !editing && visibleEntities != null ? visibleEntities : MapEntity.MapEntityList.ToList();

foreach (MapEntity e in entitiesToRender)
{
Expand All @@ -217,7 +217,7 @@ public static void DrawPaintedColors(SpriteBatch spriteBatch, bool editing = fal

public static void DrawBack(SpriteBatch spriteBatch, bool editing = false, Predicate<MapEntity> predicate = null)
{
var entitiesToRender = !editing && visibleEntities != null ? visibleEntities : MapEntity.MapEntityList;
var entitiesToRender = !editing && visibleEntities != null ? visibleEntities : MapEntity.MapEntityList.ToList();

foreach (MapEntity e in entitiesToRender)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,32 @@
using Barotrauma.Items.Components;
using Barotrauma.Networking;
using System.Collections.Concurrent;
using System.Collections.Generic;

namespace Barotrauma
{
partial class EntitySpawner : Entity, IServerSerializable
{
public readonly List<(Entity entity, bool isRemoval)> receivedEvents = new List<(Entity entity, bool isRemoval)>();
/// <summary>
/// Thread-safe queue for received entity spawn/remove events from the server.
/// </summary>
private readonly ConcurrentQueue<(Entity entity, bool isRemoval)> receivedEventsQueue = new ConcurrentQueue<(Entity entity, bool isRemoval)>();

/// <summary>
/// Gets a thread-safe snapshot of received events.
/// </summary>
public IEnumerable<(Entity entity, bool isRemoval)> GetReceivedEventsSnapshot()
{
return receivedEventsQueue.ToArray();
}

/// <summary>
/// Clears all received events from the queue.
/// </summary>
void ResetReceivedEvents()
{
while (receivedEventsQueue.TryDequeue(out _)) { }
}

public void ClientEventRead(IReadMessage message, float sendingTime)
{
Expand Down Expand Up @@ -34,7 +54,7 @@ public void ClientEventRead(IReadMessage message, float sendingTime)
{
DebugConsole.Log("Received entity removal message for ID " + entityId + ". Entity with a matching ID not found.");
}
receivedEvents.Add((entity, true));
receivedEventsQueue.Enqueue((entity, true));
}
else
{
Expand All @@ -57,7 +77,7 @@ public void ClientEventRead(IReadMessage message, float sendingTime)
GameAnalyticsManager.AddDesignEvent("ItemFabricated:" + (GameMain.GameSession?.GameMode?.Preset.Identifier ?? "none".ToIdentifier()) + ":" + newItem.Prefab.Identifier);
}
}
receivedEvents.Add((newItem, false));
receivedEventsQueue.Enqueue((newItem, false));
}
break;
case (byte)SpawnableType.Character:
Expand All @@ -68,7 +88,7 @@ public void ClientEventRead(IReadMessage message, float sendingTime)
}
else
{
receivedEvents.Add((character, false));
receivedEventsQueue.Enqueue((character, false));
}
break;
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3916,7 +3916,7 @@ private void WriteEventErrorData(ClientNetError error, UInt16 expectedID, UInt16
{
errorLines.Add("");
errorLines.Add("EntitySpawner events:");
foreach ((Entity entity, bool isRemoval) in Entity.Spawner.receivedEvents)
foreach ((Entity entity, bool isRemoval) in Entity.Spawner.GetReceivedEventsSnapshot())
{
errorLines.Add(
(isRemoval ? "Remove " : "Create ") +
Expand Down
13 changes: 8 additions & 5 deletions Barotrauma/BarotraumaServer/ServerSource/Characters/Character.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,14 @@ partial void KillProjSpecific(CauseOfDeathType causeOfDeath, Affliction causeOfD
}
}

// Create snapshot to avoid concurrent access issues during parallel updates
var clients = GameMain.Server.ConnectedClients.ToArray();

if (GameMain.Server is { ServerSettings.RespawnMode: RespawnMode.Permadeath } &&
GameMain.GameSession?.Campaign is MultiPlayerCampaign mpCampaign &&
causeOfDeath != CauseOfDeathType.Disconnected)
{
Client ownerClient = GameMain.Server.ConnectedClients.FirstOrDefault(c => c.Character == this);
Client ownerClient = clients.FirstOrDefault(c => c.Character == this);
if (ownerClient != null)
{
ownerClient.SpectateOnly = true;
Expand All @@ -51,7 +54,7 @@ partial void KillProjSpecific(CauseOfDeathType causeOfDeath, Affliction causeOfD

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)
{
(GameMain.GameSession?.GameMode as MultiPlayerCampaign)?.SaveExperiencePoints(ownerClient);
Expand All @@ -62,7 +65,7 @@ partial void KillProjSpecific(CauseOfDeathType causeOfDeath, Affliction causeOfD

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 (!LuaCsSetup.Instance.Game.overrideTraitors)
Expand All @@ -71,11 +74,11 @@ partial void KillProjSpecific(CauseOfDeathType causeOfDeath, Affliction causeOfD
}
}
}
foreach (Client client in GameMain.Server.ConnectedClients)
foreach (Client client in clients)
{
if (client.InGame)
{
client.PendingPositionUpdates.Enqueue(this);
client.TryEnqueuePositionUpdate(this);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,9 @@ public virtual void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent
case ControlEventData controlEventData:
Client owner = controlEventData.Owner;
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 });
break;
case CharacterStatusEventData statusEventData:
Expand Down Expand Up @@ -742,7 +744,9 @@ public void WriteSpawnData(IWriteMessage msg, UInt16 entityId, bool restrictMess
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)
{
msg.WriteBoolean(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,13 @@ public void IgnoreClient(Client c, float seconds)

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 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; }
}
Expand All @@ -95,7 +98,7 @@ private bool IsBlockedByAnotherConversation(IEnumerable<Entity> targets, float d
foreach (Entity e in targets)
{
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; }
}
}
Expand All @@ -117,13 +120,16 @@ private bool IsBlockedByAnotherConversation(Client targetClient, float duration)
partial void ShowDialog(Character speaker, Character targetCharacter)
{
targetClients.Clear();
// Create snapshot to avoid concurrent access issues during parallel updates
var clients = GameMain.Server.ConnectedClients.ToArray();

if (!TargetTag.IsEmpty)
{
IEnumerable<Entity> entities = ParentEvent.GetTargets(TargetTag);
foreach (Entity e in entities)
{
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)
{
targetClients.Add(targetClient);
Expand All @@ -135,7 +141,7 @@ partial void ShowDialog(Character speaker, Character targetCharacter)
}
else
{
foreach (Client c in GameMain.Server.ConnectedClients)
foreach (Client c in clients)
{
if (CanClientReceive(c))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,48 +9,52 @@ namespace Barotrauma;

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; }
if (!TargetTag.IsEmpty)
List<Client> targetClients = new List<Client>();
foreach (var target in ParentEvent.GetTargets(TargetTag))
{
List<Client> targetClients = new List<Client>();
foreach (var target in ParentEvent.GetTargets(TargetTag))
if (target is Character character)
{
if (target is Character character)
{
var ownerClient = GameMain.Server.ConnectedClients.Find(c => c.Character == character);
if (ownerClient != null)
{
targetClients.Add(ownerClient);
}
}
else
var ownerClient = clients.FirstOrDefault(c => c.Character == character);
if (ownerClient != null)
{
DebugConsole.AddWarning($"{target} is not a valid target for an EventLogAction. The target should be a character.",
ParentEvent.Prefab.ContentPackage);
targetClients.Add(ownerClient);
}
}
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: null);
}
Log(targetClients);
}

void Log(List<Client>? targetClients)
}
else
{
if (eventLog.TryAddEntry(ParentEvent.Prefab.Identifier, Id, displayText, clients) && ShowInServerLog)
{
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);
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);
}
}
}
Loading
Loading