Skip to content

Commit

Permalink
Rewrites ChooseAntags more robust with new antag selection methods
Browse files Browse the repository at this point in the history
  • Loading branch information
rbertoche committed Dec 22, 2024
1 parent 143c6a6 commit 33f15f4
Showing 1 changed file with 52 additions and 9 deletions.
61 changes: 52 additions & 9 deletions Content.Server/Antag/AntagSelectionSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,19 +204,62 @@ public void ChooseAntags(Entity<AntagSelectionComponent> ent, IList<ICommonSessi
var playerPool = GetPlayerPool(ent, pool, def);
var count = GetTargetAntagCount(ent, GetTotalPlayerCount(pool), def);

for (var i = 0; i < count; i++)
///// Einstein Engines changes /////
//
// Fixes issues caused by failures in making someone antag while
// not breaking any API on this system.
//
// This will either allocate `count` slots from the player pool,
// or will call MakeAntag with null sessions to fill up the slots.
//
if (def.PickPlayer)
{
var session = (ICommonSession?) null;
if (def.PickPlayer)
// Tries up to maxRetries times to assign antags.
// When any number of assignment fails, next iteration
// gets new items to replace those.
// Already selected or failed sessions are avoided.
// It retries until it ends with no failures or up
// to maxRetries attempts.

const int maxRetries = 4;
var retry = 0;
List<ICommonSession> 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);
}
}

Expand Down

0 comments on commit 33f15f4

Please sign in to comment.