diff --git a/Content.IntegrationTests/Tests/Administration/Logs/AddTests.cs b/Content.IntegrationTests/Tests/Administration/Logs/AddTests.cs index 7f338c300c..4127206c2a 100644 --- a/Content.IntegrationTests/Tests/Administration/Logs/AddTests.cs +++ b/Content.IntegrationTests/Tests/Administration/Logs/AddTests.cs @@ -336,4 +336,49 @@ public class AddTests : ContentIntegrationTest Assert.Pass(); } + + [Test] + public async Task DuplicatePlayerIdDoesNotThrowTest() + { + var (client, server) = await StartConnectedServerClientPair(serverOptions: new ServerContentIntegrationOption + { + CVarOverrides = + { + [CCVars.AdminLogsQueueSendDelay.Name] = "0" + }, + }); + + await Task.WhenAll(client.WaitIdleAsync(), server.WaitIdleAsync()); + + var sPlayers = server.ResolveDependency(); + var sSystems = server.ResolveDependency(); + + var sAdminLogSystem = sSystems.GetEntitySystem(); + + var guid = Guid.NewGuid(); + + await server.WaitPost(() => + { + var player = sPlayers.ServerSessions.Single(); + + sAdminLogSystem.Add(LogType.Unknown, $"{player:first} {player:second} test log: {guid}"); + }); + + await WaitUntil(server, async () => + { + var logs = await sAdminLogSystem.CurrentRoundLogs(new LogFilter + { + Search = guid.ToString() + }); + + if (logs.Count == 0) + { + return false; + } + + return true; + }); + + Assert.Pass(); + } } diff --git a/Content.Server/Administration/Logs/AdminLogSystem.Json.cs b/Content.Server/Administration/Logs/AdminLogSystem.Json.cs index bee8baa3f7..928eae22b3 100644 --- a/Content.Server/Administration/Logs/AdminLogSystem.Json.cs +++ b/Content.Server/Administration/Logs/AdminLogSystem.Json.cs @@ -35,11 +35,11 @@ public partial class AdminLogSystem _sawmill.Debug($"Admin log converters found: {string.Join(" ", converterNames)}"); } - private (JsonDocument json, List players, List<(int id, string? name)> entities) ToJson( + private (JsonDocument json, HashSet players, Dictionary entities) ToJson( Dictionary properties) { - var entities = new List<(int id, string? name)>(); - var players = new List(); + var entities = new Dictionary(); + var players = new HashSet(); var parsed = new Dictionary(); foreach (var key in properties.Keys) @@ -54,7 +54,7 @@ public partial class AdminLogSystem var parsedKey = NamingPolicy.ConvertName(key); parsed.Add(parsedKey, value); - EntityUid? entityId = properties[key] switch + var entityId = properties[key] switch { EntityUid id => id, EntityStringRepresentation rep => rep.Uid, @@ -72,9 +72,7 @@ public partial class AdminLogSystem ? metadata.EntityName : null; - if (entities.Any(e => e.id == (int) uid)) continue; - - entities.Add(((int) uid, entityName)); + entities.TryAdd((int) uid, entityName); if (_entityManager.TryGetComponent(uid, out ActorComponent? actor)) { diff --git a/Content.Server/Administration/Logs/AdminLogSystem.cs b/Content.Server/Administration/Logs/AdminLogSystem.cs index d437e4ac54..bf46d88ae1 100644 --- a/Content.Server/Administration/Logs/AdminLogSystem.cs +++ b/Content.Server/Administration/Logs/AdminLogSystem.cs @@ -243,7 +243,7 @@ public partial class AdminLogSystem : SharedAdminLogSystem } } - private async void Add(LogType type, LogImpact impact, string message, JsonDocument json, List players, List<(int id, string? name)> entities) + private async void Add(LogType type, LogImpact impact, string message, JsonDocument json, HashSet players, Dictionary entities) { var logId = NextLogId; var date = DateTime.UtcNow; diff --git a/Content.Server/Administration/Logs/QueuedLog.cs b/Content.Server/Administration/Logs/QueuedLog.cs index 7dd62ab5ca..e126712e07 100644 --- a/Content.Server/Administration/Logs/QueuedLog.cs +++ b/Content.Server/Administration/Logs/QueuedLog.cs @@ -1,12 +1,11 @@ using System.Collections.Generic; using Content.Server.Database; -using JetBrains.Annotations; namespace Content.Server.Administration.Logs; public readonly struct QueuedLog { - public QueuedLog(AdminLog log, List<(int id, string? name)> entities) + public QueuedLog(AdminLog log, Dictionary entities) { Log = log; Entities = entities; @@ -14,9 +13,9 @@ public readonly struct QueuedLog public AdminLog Log { get; } - public List<(int id, string? name)> Entities { get; } + public Dictionary Entities { get; } - public void Deconstruct(out AdminLog log, out List<(int id, string? name)> entities) + public void Deconstruct(out AdminLog log, out Dictionary entities) { log = Log; entities = Entities; diff --git a/Content.Shared/Administration/Logs/LogStringHandler.cs b/Content.Shared/Administration/Logs/LogStringHandler.cs index 621d1f959b..ffe7ecc1e6 100644 --- a/Content.Shared/Administration/Logs/LogStringHandler.cs +++ b/Content.Shared/Administration/Logs/LogStringHandler.cs @@ -40,22 +40,20 @@ public ref struct LogStringHandler format = argument[0] == '@' ? argument[1..] : argument; } - if (!Values.TryAdd(format, value)) + if (Values.TryAdd(format, value) || + Values[format] == (object?) value) { - if (Values[format] == (object?) value) - { - return; - } + return; + } - var originalFormat = format; - var i = 2; + var originalFormat = format; + var i = 2; + format = $"{originalFormat}_{i}"; + + while (!Values.TryAdd(format, value)) + { format = $"{originalFormat}_{i}"; - - while (!Values.TryAdd(format, value)) - { - format = $"{originalFormat}_{i}"; - i++; - } + i++; } }