From eae1ed4dcfb62df8470de356ff78db36f94542f1 Mon Sep 17 00:00:00 2001 From: terencehill Date: Fri, 27 May 2022 22:49:13 +0200 Subject: [PATCH] Change server's player sorting algorithm to work as the scoreboard's one, so it doesn't scan all score fields but stops at the first mismatch. It required inverting score registration order and avoiding sorting scores alphabetically. While at it I tweaked score registration order a little bit. Remove hardcoded priority list (sb_extra_sorting_field) from scoreboard's algorithm, score registration order can be used now. --- qcsrc/client/hud/panel/scoreboard.qc | 38 ++++--------- qcsrc/common/scores.qh | 80 +++++++++++++--------------- qcsrc/server/scores.qc | 42 +++++++++++---- 3 files changed, 82 insertions(+), 78 deletions(-) diff --git a/qcsrc/client/hud/panel/scoreboard.qc b/qcsrc/client/hud/panel/scoreboard.qc index 393e15c13..3f6fced99 100644 --- a/qcsrc/client/hud/panel/scoreboard.qc +++ b/qcsrc/client/hud/panel/scoreboard.qc @@ -167,8 +167,6 @@ string Label_getInfo(string label, int mode) void PrintScoresLabels() { Label_getInfo(string_null, 1); } string TranslateScoresLabel(string label) { return Label_getInfo(label, 0); } -#define SB_EXTRA_SORTING_FIELDS 5 -PlayerScoreField sb_extra_sorting_field[SB_EXTRA_SORTING_FIELDS]; void Scoreboard_InitScores() { int i, f; @@ -183,13 +181,6 @@ void Scoreboard_InitScores() ps_primary = it; if(f == SFL_SORT_PRIO_SECONDARY) ps_secondary = it; - if(ps_primary == it || ps_secondary == it) - continue; - if (scores_label(it) == "kills") sb_extra_sorting_field[0] = it; - if (scores_label(it) == "deaths") sb_extra_sorting_field[1] = it; - if (scores_label(it) == "suicides") sb_extra_sorting_field[2] = it; - if (scores_label(it) == "dmg") sb_extra_sorting_field[3] = it; - if (scores_label(it) == "dmgtaken") sb_extra_sorting_field[4] = it; }); if(ps_secondary == NULL) ps_secondary = ps_primary; @@ -275,27 +266,20 @@ float Scoreboard_ComparePlayerScores(entity left, entity right) return false; } - entity fld = NULL; - int r; - for (int i = -2; i < SB_EXTRA_SORTING_FIELDS; ++i) - { - if (i < 0) - { - if (!fld) fld = ps_primary; - else if (ps_secondary == ps_primary) continue; - else fld = ps_secondary; - } - else - { - fld = sb_extra_sorting_field[i]; - if (fld == ps_primary || fld == ps_secondary) continue; - } - if (!fld) continue; + int res = Scoreboard_CompareScore(left.scores(ps_primary), right.scores(ps_primary), scores_flags(ps_primary)); + if (res >= 0) return res; - r = Scoreboard_CompareScore(left.scores(fld), right.scores(fld), scores_flags(fld)); - if (r >= 0) return r; + if (ps_secondary && ps_secondary != ps_primary) + { + res = Scoreboard_CompareScore(left.scores(ps_secondary), right.scores(ps_secondary), scores_flags(ps_secondary)); + if (res >= 0) return res; } + FOREACH(Scores, (it != ps_primary && it != ps_secondary), { + res = Scoreboard_CompareScore(left.scores(it), right.scores(it), scores_flags(it)); + if (res >= 0) return res; + }); + if (left.sv_entnum < right.sv_entnum) return true; diff --git a/qcsrc/common/scores.qh b/qcsrc/common/scores.qh index 28d6ad576..630df90c2 100644 --- a/qcsrc/common/scores.qh +++ b/qcsrc/common/scores.qh @@ -5,7 +5,8 @@ #define REGISTER_SP(id) REGISTER(Scores, SP, id, m_id, new_pure(PlayerScoreField)) REGISTRY(Scores, MAX_SCORE); REGISTER_REGISTRY(Scores) -REGISTRY_SORT(Scores); +// do not sort alphabetically, player sort priority is based on score registration order +//REGISTRY_SORT(Scores); REGISTRY_CHECK(Scores); REGISTRY_DEFINE_GET(Scores, NULL) @@ -14,70 +15,41 @@ STATIC_INIT(Scores_renumber) { FOREACH(Scores, true, it.m_id = i); } /* * Score indices */ - #ifdef GAMEQC -// fields not networked via the score system -REGISTER_SP(END); - -REGISTER_SP(PING); -REGISTER_SP(PL); -REGISTER_SP(NAME); -REGISTER_SP(SEPARATOR); - -REGISTER_SP(KDRATIO); // kills / deaths -REGISTER_SP(SUM); // kills - deaths -REGISTER_SP(FRAGS); // kills - suicides - // networked fields +// NOTE: score registration order is used as player sort priority (after primary and secondary) -REGISTER_SP(SCORE); - -REGISTER_SP(DMG); -REGISTER_SP(DMGTAKEN); +// TODO: move gamemode scores to gamemode files +// TODO: allow gamemodes to fully customize player sorting priority, even the common ones -REGISTER_SP(KILLS); -REGISTER_SP(DEATHS); -REGISTER_SP(SUICIDES); -REGISTER_SP(TEAMKILLS); - -REGISTER_SP(ELO); - -REGISTER_SP(FPS); - -// TODO: move to common mutators - -REGISTER_SP(RACE_TIME); REGISTER_SP(RACE_LAPS); +REGISTER_SP(RACE_TIME); REGISTER_SP(RACE_FASTEST); -//REGISTER_SP(CTS_TIME); -//REGISTER_SP(CTS_LAPS); -//REGISTER_SP(CTS_FASTEST); - REGISTER_SP(ASSAULT_OBJECTIVES); -REGISTER_SP(CTF_PICKUPS); +REGISTER_SP(CTF_CAPS); REGISTER_SP(CTF_FCKILLS); REGISTER_SP(CTF_RETURNS); -REGISTER_SP(CTF_CAPS); -REGISTER_SP(CTF_CAPTIME); REGISTER_SP(CTF_DROPS); +REGISTER_SP(CTF_PICKUPS); +REGISTER_SP(CTF_CAPTIME); REGISTER_SP(DOM_TAKES); REGISTER_SP(DOM_TICKS); REGISTER_SP(FREEZETAG_REVIVALS); +REGISTER_SP(KEEPAWAY_CARRIERKILLS); REGISTER_SP(KEEPAWAY_PICKUPS); REGISTER_SP(KEEPAWAY_BCTIME); -REGISTER_SP(KEEPAWAY_CARRIERKILLS); -REGISTER_SP(KH_PICKUPS); REGISTER_SP(KH_CAPS); REGISTER_SP(KH_KCKILLS); -REGISTER_SP(KH_PUSHES); -REGISTER_SP(KH_DESTROYS); REGISTER_SP(KH_LOSSES); +REGISTER_SP(KH_DESTROYS); +REGISTER_SP(KH_PUSHES); +REGISTER_SP(KH_PICKUPS); REGISTER_SP(LMS_RANK); REGISTER_SP(LMS_LIVES); @@ -85,8 +57,31 @@ REGISTER_SP(LMS_LIVES); REGISTER_SP(NEXBALL_GOALS); REGISTER_SP(NEXBALL_FAULTS); -REGISTER_SP(ONS_TAKES); REGISTER_SP(ONS_CAPS); +REGISTER_SP(ONS_TAKES); + +REGISTER_SP(SCORE); +REGISTER_SP(KILLS); +REGISTER_SP(DEATHS); +REGISTER_SP(TEAMKILLS); +REGISTER_SP(SUICIDES); +REGISTER_SP(DMG); +REGISTER_SP(DMGTAKEN); + +REGISTER_SP(ELO); // not sortable +REGISTER_SP(FPS); // not sortable + +// fields not networked via the score system +REGISTER_SP(END); + +REGISTER_SP(PING); +REGISTER_SP(PL); +REGISTER_SP(NAME); +REGISTER_SP(SEPARATOR); + +REGISTER_SP(KDRATIO); // kills / deaths +REGISTER_SP(SUM); // kills - deaths +REGISTER_SP(FRAGS); // kills - suicides #endif @@ -124,6 +119,7 @@ const int SFL_NOT_SORTABLE = BIT(7); // don't sort by this field /** * Scoring priority (NOTE: PRIMARY is used for fraglimit) + * NOTE: SFL_SORT_PRIO_SECONDARY value must be lower than SFL_SORT_PRIO_PRIMARY's */ const int SFL_SORT_PRIO_SECONDARY = BIT(2); const int SFL_SORT_PRIO_PRIMARY = BIT(3); diff --git a/qcsrc/server/scores.qc b/qcsrc/server/scores.qc index bc4d8947c..5bac7240f 100644 --- a/qcsrc/server/scores.qc +++ b/qcsrc/server/scores.qc @@ -23,6 +23,8 @@ var .float scores_primary; var .float teamscores_primary; float scores_flags_primary; float teamscores_flags_primary; +var .float scores_secondary; +float scores_flags_secondary; vector ScoreField_Compare(entity t1, entity t2, .float field, float fieldflags, vector previous, bool strict) // returns: cmp value, best prio { @@ -145,13 +147,18 @@ float TeamScore_Compare(entity t1, entity t2, bool strict) { if(!t1 || !t2) return (!t2) - !t1; + // supporting MAX_TEAMSCORE > 2 requires keeping track of primary and secondary teamscore + if (MAX_TEAMSCORE > 2) + error("MAX_TEAMSCORE > 2 not supported"); + + // first compare primary, then others (don't check secondary flag since there are only 2 teamscores) vector result = '0 0 0'; - float i; - for(i = 0; i < MAX_TEAMSCORE; ++i) + int i = boolean(teamscores_primary && teamscores_primary == teamscores(1)); + result = ScoreField_Compare(t1, t2, teamscores(i), teamscores_flags(i), result, strict); + if (result.x == 0) { - var .float f; - f = teamscores(i); - result = ScoreField_Compare(t1, t2, f, teamscores_flags(i), result, strict); + i = (i + 1) % MAX_TEAMSCORE; + result = ScoreField_Compare(t1, t2, teamscores(i), teamscores_flags(i), result, strict); } if (result.x == 0 && strict) @@ -173,6 +180,11 @@ void ScoreInfo_SetLabel_PlayerScore(PlayerScoreField i, string label, float scor scores_primary = scores(i); scores_flags_primary = scoreflags; } + else if((scoreflags & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_SECONDARY) + { + scores_secondary = scores(i); + scores_flags_secondary = scoreflags; + } if(label != "") { PlayerStats_GameReport_AddEvent(strcat(PLAYERSTATS_TOTAL, label)); @@ -410,10 +422,22 @@ float PlayerScore_Compare(entity t1, entity t2, bool strict) if(!t1 || !t2) return (!t2) - !t1; vector result = '0 0 0'; - FOREACH(Scores, true, { - var .float f = scores(it); - result = ScoreField_Compare(t1, t2, f, scores_flags(it), result, strict); - }); + + result = ScoreField_Compare(t1, t2, scores_primary, scores_flags_primary, result, strict); + // NOTE: if (scores_secondary) doesn't work because it's a field pointer + if (result.x == 0 && scores_flags_secondary) + result = ScoreField_Compare(t1, t2, scores_secondary, scores_flags_secondary, result, strict); + + if (result.x == 0) + FOREACH(Scores, true, { + if (scores_flags(it) & SFL_SORT_PRIO_MASK) + continue; + if (scores_label(it) == "") + continue; + var .float f = scores(it); + result = ScoreField_Compare(t1, t2, f, scores_flags(it), result, strict); + if (result.x) break; + }); if (result.x == 0 && strict) result.x = t1.owner.playerid - t2.owner.playerid; -- 2.39.2