private (bool balanced, List<CCSPlayerController>? teamOne, List<CCSPlayerController>? teamTwo) BalanceNeeded()
{
CCSPlayerController[] terrorists = GetTeamClients(CsTeam.Terrorist);
CCSPlayerController[] counterTerrorists = GetTeamClients(CsTeam.CounterTerrorist);
int activeCount = terrorists.Length + counterTerrorists.Length;
// If teams are lopsided, balance is needed.
if (activeCount % 2 == 0)
{
if (terrorists.Length != counterTerrorists.Length)
{
return (true, null, null);
}
}
else if (Math.Abs(terrorists.Length - counterTerrorists.Length) > 1)
{
return (true, null, null);
}
// If number of players online is less than 4, don't balance, let them figure it out.
if (activeCount < 4)
{
return (false, null, null);
}
// If this is the final round, do not balance.
if (_timelimitConVar is not null &&
_roundRestartDelayConVar is not null &&
_roundTimeConVar is not null &&
_freezeTimeConVar is not null)
{
float timeLimit = _timelimitConVar.GetPrimitiveValue<float>() * 60;
float timeElapsed = Server.CurrentTime - _startTime;
float roundRestartDelay = _roundRestartDelayConVar.GetPrimitiveValue<float>();
//float roundTime = _roundTimeConVar.GetPrimitiveValue<float>() * 60;
//float freezeTime = _freezeTimeConVar.GetPrimitiveValue<int>();
float timeRemaining = timeLimit - (timeElapsed + roundRestartDelay);
//float maxRoundTime = roundTime + roundRestartDelay + freezeTime;
if (timeRemaining <= 0)
{
return (false, null, null);
}
}
// Some players performance are influenced by their teammates/enemies.
// As a result, after a balance, we must let (minimum rounds) pass, so we can re-calculate player ratings.
// Basically, old Kill-per-Round data becomes stale after a balance.
// Let's call it 5 rounds to calibrate.
if (_roundsPassedSinceBalance < 5)
{
return (false, null, null);
}
// Calculate the difference in average rating of both teams NOW.
float tAverageRating = GetTeamAverageRating(terrorists);
float ctAverageRating = GetTeamAverageRating(counterTerrorists);
float ratioBefore = Math.Max(tAverageRating / ctAverageRating, ctAverageRating / tAverageRating);
// Calculate what the difference in average rating of both teams would become AFTER we balance.
// This means we must first determine what the two teams would look like after a balance.
(List<CCSPlayerController> teamOne, List<CCSPlayerController> teamTwo) = BalanceTeams();
float teamOneAverageRating = GetTeamAverageRating([.. teamOne]);
float teamTwoAverageRating = GetTeamAverageRating([.. teamTwo]);
float ratioAfter = Math.Max(teamOneAverageRating / teamTwoAverageRating, teamTwoAverageRating / teamOneAverageRating);
// Determine how much of an improvement the balance would be.
// Compare ratioBefore with ratioAfter. If ratioAfter is at least 33% lower than ratioBefore, balance.
if (ratioAfter + ratioAfter * 0.33f < ratioBefore)
{
return (true, teamOne, teamTwo);
}
// Check if ratioBefore is outside our minimum threshold, and ratioAfter is inside our minimum threshold.
// If true, balance.
if (ratioBefore >= 2.0 && ratioAfter < 2.0)
{
return (true, teamOne, teamTwo);
}
// Otherwise, no balance needed.
return (false, null, null);
}
i only spent a day on the plugin so maybe there’s a problem 🤷
i’ll read the entire thing over later today since I finished working on spacewall (mostly)