From 0df6205a88ffcf995e242e9225d6bf8085135b73 Mon Sep 17 00:00:00 2001 From: Raphael Bertoche Date: Thu, 12 Dec 2024 03:06:56 -0300 Subject: [PATCH 01/11] Switches off throw in MakeAntag to a log.Error to prevent further errors We might never see the end of new antags being added using MakeAntag so better just cut it off by the root and mitigating the issue by preventing it from causing the round to not start. --- Content.Server/Antag/AntagSelectionSystem.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Content.Server/Antag/AntagSelectionSystem.cs b/Content.Server/Antag/AntagSelectionSystem.cs index 8efdc2738b9..198459724d7 100644 --- a/Content.Server/Antag/AntagSelectionSystem.cs +++ b/Content.Server/Antag/AntagSelectionSystem.cs @@ -264,7 +264,8 @@ public void MakeAntag(Entity ent, ICommonSession? sessi if (!getEntEv.Handled) { - throw new InvalidOperationException($"Attempted to make {session} antagonist in gamerule {ToPrettyString(ent)} but there was no valid entity for player."); + Log.Error($"Attempted to make {session} antagonist in gamerule {ToPrettyString(ent)} but there was no valid entity for player."); + return; } antagEnt = getEntEv.Entity; From 143c6a6a9c099e335300d6358181dcb3ceb6bef4 Mon Sep 17 00:00:00 2001 From: Raphael Bertoche Date: Sun, 22 Dec 2024 04:30:09 -0300 Subject: [PATCH 02/11] Adds methods TryGetItems and Where to AntagSelectionPlayerPool --- .../Antag/AntagSelectionPlayerPool.cs | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/Content.Server/Antag/AntagSelectionPlayerPool.cs b/Content.Server/Antag/AntagSelectionPlayerPool.cs index 87873e96d1a..c303698d293 100644 --- a/Content.Server/Antag/AntagSelectionPlayerPool.cs +++ b/Content.Server/Antag/AntagSelectionPlayerPool.cs @@ -23,5 +23,44 @@ public bool TryPickAndTake(IRobustRandom random, [NotNullWhen(true)] out ICommon return session != null; } + // EE + public bool TryGetItems(IRobustRandom random, + [NotNullWhen(true)] out ICommonSession[]? sessions, + int count, + bool allowDuplicates = true) + { + sessions = null; + List session_list = []; + + foreach (var pool in orderedPools) + { + if (pool.Count == 0) + continue; + + var picked = random.GetItems(pool, count - session_list.Count, allowDuplicates); + session_list.AddRange(picked); + if (session_list.Count < count) + { + continue; + } + sessions = session_list.ToArray(); + break; + } + + return sessions != null; + } + + // EE + public AntagSelectionPlayerPool Where(Func predicate) + { + var newPools = orderedPools.Select( + (pool) => + { + return pool.Where(predicate).ToList(); + } + ); + + return new AntagSelectionPlayerPool(newPools.ToList()); + } public int Count => orderedPools.Sum(p => p.Count); } From 33f15f40eec666e6081c0d397f06aacbbe9d24b0 Mon Sep 17 00:00:00 2001 From: Raphael Bertoche Date: Sun, 22 Dec 2024 04:31:14 -0300 Subject: [PATCH 03/11] Rewrites ChooseAntags more robust with new antag selection methods --- Content.Server/Antag/AntagSelectionSystem.cs | 61 +++++++++++++++++--- 1 file changed, 52 insertions(+), 9 deletions(-) diff --git a/Content.Server/Antag/AntagSelectionSystem.cs b/Content.Server/Antag/AntagSelectionSystem.cs index 198459724d7..99d5bc86614 100644 --- a/Content.Server/Antag/AntagSelectionSystem.cs +++ b/Content.Server/Antag/AntagSelectionSystem.cs @@ -204,19 +204,62 @@ public void ChooseAntags(Entity ent, IList failed = []; + + while (count != 0 && retry < maxRetries) { - if (!playerPool.TryPickAndTake(RobustRandom, out session)) - break; - - if (ent.Comp.SelectedSessions.Contains(session)) - continue; + var countFailed = 0; // Not at the same scope as `failed` + var sessions = (ICommonSession[]?) null; + if (!playerPool.TryGetItems(RobustRandom, out sessions, count, false)) + break; // Ends early if there are no eligible sessions + + foreach (var session in sessions) + { + MakeAntag(ent, session, def); + if (!ent.Comp.SelectedSessions.Contains(session)) + { + failed.Add(session); + countFailed++; + } + } + playerPool = playerPool.Where((session_) => + { + return !ent.Comp.SelectedSessions.Contains(session_) && + !failed.Contains(session_); + }); + count = countFailed; + retry++; } + } - MakeAntag(ent, session, def); + // This preserves previous behavior for when def.PickPlayer + // was not satisfied. This behavior is not that obvious to + // read from the previous code. + // It may otherwise process leftover slots if maxRetries have + // been reached. + + for (var i = 0; i < count; i++) + { + MakeAntag(ent, null, def); } } From df02f437e5399fe21a886d67765e9fdfe859c456 Mon Sep 17 00:00:00 2001 From: Raphael Bertoche Date: Sun, 22 Dec 2024 04:56:52 -0300 Subject: [PATCH 04/11] More comments to mark EE changes to ease merges --- Content.Server/Antag/AntagSelectionSystem.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Content.Server/Antag/AntagSelectionSystem.cs b/Content.Server/Antag/AntagSelectionSystem.cs index 99d5bc86614..d448f1cd451 100644 --- a/Content.Server/Antag/AntagSelectionSystem.cs +++ b/Content.Server/Antag/AntagSelectionSystem.cs @@ -261,6 +261,7 @@ public void ChooseAntags(Entity ent, IList @@ -307,6 +308,7 @@ public void MakeAntag(Entity ent, ICommonSession? sessi if (!getEntEv.Handled) { + ///// Einstein Engines change ///// Log.Error($"Attempted to make {session} antagonist in gamerule {ToPrettyString(ent)} but there was no valid entity for player."); return; } From d6e20528cc9575605b7b7d9ccc9512604848082a Mon Sep 17 00:00:00 2001 From: Raphael Bertoche Date: Sun, 22 Dec 2024 05:15:02 -0300 Subject: [PATCH 05/11] Typo on comment --- Content.Server/Antag/AntagSelectionSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Antag/AntagSelectionSystem.cs b/Content.Server/Antag/AntagSelectionSystem.cs index d448f1cd451..2b5eebc822d 100644 --- a/Content.Server/Antag/AntagSelectionSystem.cs +++ b/Content.Server/Antag/AntagSelectionSystem.cs @@ -215,7 +215,7 @@ public void ChooseAntags(Entity ent, IList Date: Sun, 22 Dec 2024 05:15:44 -0300 Subject: [PATCH 06/11] Rephrasing comment --- Content.Server/Antag/AntagSelectionSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Antag/AntagSelectionSystem.cs b/Content.Server/Antag/AntagSelectionSystem.cs index 2b5eebc822d..9409019a0b5 100644 --- a/Content.Server/Antag/AntagSelectionSystem.cs +++ b/Content.Server/Antag/AntagSelectionSystem.cs @@ -214,7 +214,7 @@ public void ChooseAntags(Entity ent, IList Date: Sun, 22 Dec 2024 05:29:59 -0300 Subject: [PATCH 07/11] Removes unnecessary variable and adds another early break --- Content.Server/Antag/AntagSelectionSystem.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Content.Server/Antag/AntagSelectionSystem.cs b/Content.Server/Antag/AntagSelectionSystem.cs index 9409019a0b5..6e0f51b5dc2 100644 --- a/Content.Server/Antag/AntagSelectionSystem.cs +++ b/Content.Server/Antag/AntagSelectionSystem.cs @@ -225,11 +225,13 @@ public void ChooseAntags(Entity ent, IList failed = []; - while (count != 0 && retry < maxRetries) + while (ent.Comp.SelectedSessions.Count < count && retry < maxRetries) { - var countFailed = 0; // Not at the same scope as `failed` var sessions = (ICommonSession[]?) null; - if (!playerPool.TryGetItems(RobustRandom, out sessions, count, false)) + if (!playerPool.TryGetItems(RobustRandom, + out sessions, + count - ent.Comp.SelectedSessions.Count, + false)) break; // Ends early if there are no eligible sessions foreach (var session in sessions) @@ -238,15 +240,17 @@ public void ChooseAntags(Entity ent, IList= count) + break; + playerPool = playerPool.Where((session_) => { return !ent.Comp.SelectedSessions.Contains(session_) && !failed.Contains(session_); }); - count = countFailed; retry++; } } From 813ddaa2159ab64843a18795a6f32ea2bf0504bb Mon Sep 17 00:00:00 2001 From: Raphael Bertoche Date: Sun, 22 Dec 2024 05:39:09 -0300 Subject: [PATCH 08/11] Oops. What worth is in a PR with no oops. --- Content.Server/Antag/AntagSelectionSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Antag/AntagSelectionSystem.cs b/Content.Server/Antag/AntagSelectionSystem.cs index 6e0f51b5dc2..1475285b20e 100644 --- a/Content.Server/Antag/AntagSelectionSystem.cs +++ b/Content.Server/Antag/AntagSelectionSystem.cs @@ -261,7 +261,7 @@ public void ChooseAntags(Entity ent, IList Date: Sun, 22 Dec 2024 05:42:15 -0300 Subject: [PATCH 09/11] Typo in comment. --- Content.Server/Antag/AntagSelectionSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Antag/AntagSelectionSystem.cs b/Content.Server/Antag/AntagSelectionSystem.cs index 1475285b20e..8e057ac54c7 100644 --- a/Content.Server/Antag/AntagSelectionSystem.cs +++ b/Content.Server/Antag/AntagSelectionSystem.cs @@ -215,7 +215,7 @@ public void ChooseAntags(Entity ent, IList Date: Sun, 22 Dec 2024 06:39:53 -0300 Subject: [PATCH 10/11] Replicates upstream change which is going to be necessary Made this portion of the code identical to wizden so to not conflict --- Content.Server/Antag/AntagSelectionSystem.cs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Content.Server/Antag/AntagSelectionSystem.cs b/Content.Server/Antag/AntagSelectionSystem.cs index 8e057ac54c7..34448dd9530 100644 --- a/Content.Server/Antag/AntagSelectionSystem.cs +++ b/Content.Server/Antag/AntagSelectionSystem.cs @@ -309,19 +309,16 @@ public void MakeAntag(Entity ent, ICommonSession? sessi { var getEntEv = new AntagSelectEntityEvent(session, ent); RaiseLocalEvent(ent, ref getEntEv, true); - - if (!getEntEv.Handled) - { - ///// Einstein Engines change ///// - Log.Error($"Attempted to make {session} antagonist in gamerule {ToPrettyString(ent)} but there was no valid entity for player."); - return; - } - antagEnt = getEntEv.Entity; } if (antagEnt is not { } player) + { + Log.Error($"Attempted to make {session} antagonist in gamerule {ToPrettyString(ent)} but there was no valid entity for player."); + if (session != null) + ent.Comp.SelectedSessions.Remove(session); return; + } var getPosEv = new AntagSelectLocationEvent(session, ent); RaiseLocalEvent(ent, ref getPosEv, true); @@ -332,11 +329,15 @@ public void MakeAntag(Entity ent, ICommonSession? sessi _transform.SetMapCoordinates((player, playerXform), pos); } + // If we want to just do a ghost role spawner, set up data here and then return early. + // This could probably be an event in the future if we want to be more refined about it. if (isSpawner) { if (!TryComp(player, out var spawnerComp)) { - Log.Error("Antag spawner with GhostRoleAntagSpawnerComponent."); + Log.Error($"Antag spawner {player} does not have a GhostRoleAntagSpawnerComponent."); + if (session != null) + ent.Comp.SelectedSessions.Remove(session); return; } From a595061a6763481e33045467b19b232f6b313f2b Mon Sep 17 00:00:00 2001 From: Raphael Bertoche Date: Sun, 22 Dec 2024 08:19:00 -0300 Subject: [PATCH 11/11] Adds assert to test for negatives --- Content.Server/Antag/AntagSelectionPlayerPool.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Content.Server/Antag/AntagSelectionPlayerPool.cs b/Content.Server/Antag/AntagSelectionPlayerPool.cs index c303698d293..f778b580471 100644 --- a/Content.Server/Antag/AntagSelectionPlayerPool.cs +++ b/Content.Server/Antag/AntagSelectionPlayerPool.cs @@ -2,6 +2,7 @@ using System.Linq; using Robust.Shared.Player; using Robust.Shared.Random; +using Robust.Shared.Utility; namespace Content.Server.Antag; @@ -29,6 +30,8 @@ public bool TryGetItems(IRobustRandom random, int count, bool allowDuplicates = true) { + DebugTools.Assert(count > 0, $"The count {nameof(count)} of requested sessions must be greater than zero!"); + sessions = null; List session_list = [];