14 KiB
Leaderboard
Open Leaderboard in the main navigation to compare players across the fleet,
with one entry per GUID combining Black Ops I (T5) and Black Ops II (T6). Game
and map filters limit which matches contribute to each player's statistics and
rank. Choose a ranking, search a name or GUID, and share the page URL with its
filters intact. Results refresh while the page is visible.
Matches only appear in server/global history once they reach round 2.
Leaderboards, summaries, map options, profiles and player history include only
completed matches with a received game_end. Active and interrupted matches do
not contribute. A player must also be observed at round 2 or later; players who
left before a completed game's end retain their recorded stats.
This also excludes existing round 1 records. Early telemetry is retained so
qualifying games keep their start time, roster and cumulative counters.
Click a player's name to open their shareable profile at
/leaderboard/players/[guid]. Profiles combine Black Ops I (T5) and Black Ops II
(T6) records for the same GUID. Existing /leaderboard/players/[game]/[guid]
links redirect to the combined profile. Profiles show all ten lifetime statistics,
headshots as a percentage of kills, kills per down, average kills and observed
rounds per game, and completion rate. Each map has its own complete set of
records; map records and match history identify their game. Match history shows
individual counters, server, date and completion credit in pages of 25 matches
across both games. Map names link back to that map's leaderboard in its game.
Use Refresh stats to load the latest reports. Ratios with a zero denominator
display a dash. Lifetime statistics and per-map records always cover all recorded
maps across both games.
Opening a player from the leaderboard preserves the originating game, map, metric, search and page in the Leaderboard return link. The profile's Selected leaderboard controls initialize from that game/map/metric and show the player's rank within that competition, independent of the original search. These controls also filter match history; lifetime totals stay unchanged. History pagination retains the selection and return link. Map links preserve the selected ranking metric. A player without qualifying matches in a selection can still view their lifetime profile and choose another scope.
On phones, per-map records and match history use compact cards with the map, game, highest round and kills up front. Expand All stats and record runs or More match stats for the remaining counters and source evidence. Desktop profiles retain the complete tables; both views use the same history filters and pagination. History dates say First observed, since a missing start report can make the first recorded observation later than the actual game start.
Highest-round, best-game-kill and highest-score records link to the completed match that earned them on the leaderboard and in lifetime/per-map profile stats. Each source shows its map, game, completion time, server, and whether the match start was recorded. Run details shows when the player was first observed: at the recorded start, at a reported round, or unknown for older stored records. Presence is not proof of continuous survival. Equal personal bests link to the earliest recorded completion, then the lowest match ID when times tie.
Completed matches link to their own results page at /matches/[id] from global
Match History, server history, and player profiles. The page shows the recorded
map and server, final round, start/end times, duration when the start was observed,
player counts, and the full saved roster. Players missing from the final report
retain their earlier counters; players with no stats display dashes. Counters and
score are the highest reported values within the match, not necessarily its final
scoreboard. Active and interrupted matches remain listed without results links.
Match pages remain available after the original server is removed.
The leaderboard uses the existing telemetry events; no reporter change is required. The leaderboard and profiles identify a player by GUID, displaying the latest reported name across both games, regardless of game or map filters. Different names for the same GUID do not split their leaderboard entry or profile; identical names with different GUIDs remain separate. Stored player records remain keyed by game + GUID for telemetry ingestion; combining their identity requires no rekeying. The record-source upgrade automatically adds nullable participation-start fields; existing rows keep an unknown start instead of inferring one. GUIDs stay strings.
Recorded statistics
| Statistic | Meaning |
|---|---|
| Highest round | Highest round reported with that player present, including players who joined mid-game. |
| Total kills, headshots, revives, downs | Sum of each player's highest reported counter in each game. Round snapshots are cumulative, so they are never added together within a game. |
| Total rounds | Round progression during observed participation, added across games. A player observed at game start and then round 8 receives seven rounds. A player first seen at round 8 gets a highest-round record of 8, but zero total rounds; reaching round 9 then adds one. |
| Games played | Completed games in which a stats report at round 2 or later contains the player, even if they left before the end. Start-only and round 1 participation do not count. |
| Games completed | Games whose game_end roster contains the player. Disconnected players retain earlier stats without receiving completion credit. |
| Best game kills | Highest kill count recorded in any one game. |
| Highest reported score | Highest observed score balance. Spending points can lower the score, so this is not cumulative points earned. |
Every ranking sorts highest first, including downs (a count, not an efficiency rating). Equal values share a rank; name and GUID provide a stable display order. Searching preserves the player's rank for the selected game/map filters, or across both games when unfiltered. Summary cards describe the same selection, regardless of the search text. Player counts include each qualifying GUID once, including when they have records in both games. Summary rounds are player-rounds: four players progressing from game start to round 8 contribute 28. Highest-round records always use the round reached in a completed match, including the final round and players who joined mid-game.
Efficiency rankings are also available for Headshots / kills, Kills per down, Average kills, Average rounds, and Completion rate. Each requires at least five completed games in the selected game/map scope. Headshot rate also requires 100 kills; kills per down requires five downs. The board shows the numerator, denominator and game count beside each ratio. Ratios are computed from aggregate counters, not an average of individual match percentages. Completion rate is the share of those ended games whose final report contained the player; it is not a win rate. Active and interrupted games do not enter any denominator. Zero-denominator ratios remain unknown and are not ranked.
Qualification is applied before ranking, search and pagination. Summary cards still describe all players in the game/map selection, including those below the threshold. Profile metrics show their values and whether the player qualifies for the combined lifetime board; a scoped board can have a smaller sample.
Round totals require the player to appear in consecutive observations. If a report omits them, their return starts a new participation interval and the gap is not credited. The payload cannot tell whether a present player was alive, spectating, or absent between reports. Mid-game snapshots still contribute their reported kills and other counters, even when earlier participation is unknown.
Persistence and match boundaries
Match and player records live in SQLite alongside the rest of Electric Cherry. They persist across app restarts and server deletion, and are not subject to campaign history retention. The latest scoreboard and leaderboard update in the same transaction. Each match keeps player counters even after someone leaves.
A game_start opens a match; game_end completes it. A changed map, a lower round,
or a round report after a completed game can also establish a new match when the
start was missed. Superseded active matches remain in history as interrupted.
Repeated starts before any stats belong to the same match. Identical consecutive
payloads (ignoring receipt time and roster order) do not add records. Repeated
snapshots in a match cannot increase counters or rounds twice.
The first upgrade imports the latest stored full scoreboard from each server once. That provides the available counters and highest round, but not discarded earlier games or unobserved round progression. Old round-only snapshots have no player identity and cannot be imported. Tracking continues from future reports.
T6 selections sharing an engine map, such as Town Survival and TranZit, remain separate using the server's registered map variant. Unknown variants remain explicitly identified instead of being labeled as a known selection. A match retains the game/map identity recorded at ingestion even if the server is later reconfigured or removed.
The current protocol sends events in gameplay order and has no match ID, event ID, or source sequence. A late report from an older game cannot be reliably distinguished from a new game. Likewise, identical starts before any stats are indistinguishable from retries. Send reports once in order. Within a match, counter decreases use the previous high-water mark; if a reconnect resets a player's counters, subsequent activity may be undercounted until those counters pass their earlier maxima. Exact replay handling and counter-reset accounting would require additional reporter identity/ordering information.
Read API
GET /api/leaderboard accepts optional game (t5 or t6), map (the opaque
key returned in maps), metric (default highestRound), q (name/GUID search),
limit (1–100, default 50), and offset (default 0). It returns ranked entries,
available maps, the matching player total, pagination values, and summary.
Each entry represents one GUID and combines its qualifying matches within the
game/map filters. Entries have no game field; map options retain their game
identity. Both total and summary.players count unique GUIDs; total applies
the selected metric's qualification rules and player search, while the summary
covers all completed qualifying participation in the game/map scope.
Metric keys are highestRound, kills, roundsSurvived, headshots, revives,
downs, gamesPlayed, gamesCompleted, bestKills, bestScore, headshotRate,
killsPerDown, averageKills, averageRounds, and completionRate.
Efficiency values in entries are unrounded ratios (for example, 0.5 means 50%)
or null when their denominator is zero. UI percentages multiply by 100.
Entries also include records, keyed by highestRound, bestKills, and
bestScore, with the completed match ID, value, map/game/server, timing and
observed participation behind each personal best.
Query performance
Leaderboard reads materialize the selected completed participation once, reuse one player aggregate for ranking and summary totals, and reuse the ranked/search result for pagination and its matching count. Empty and out-of-range pages still return accurate totals. Record evidence is fetched only for players on the page. Exact player-rank reads share the ranking rules but skip unused fleet summaries and map lists. No response cache delays visibility of a newly completed game.
Run the deterministic, isolated benchmark with:
node scripts/benchmark-leaderboard.mjs --scenario all --baseline-ref eac9ad4 --runs 3 --json /tmp/leaderboard-benchmark.json
The script creates temporary SQLite databases, loads the actual query modules, checks complete-response parity against the selected Git revision, and reports timings, source hashes and query plans. It never opens the application database. The small fixture has 2,000 matches and 8,000 participation rows; the large fixture has 50,000 matches and 200,000 participation rows. Both include completed, active, interrupted and nonqualifying records.
On the local Intel i5-8279U / Node 25.9.0 / SQLite 3.49.2 test environment, three measured runs after warmup gave these median query times on the large fixture:
| Request | Before | After |
|---|---|---|
| Highest round, all games | 1,717 ms | 829 ms |
| Total kills, all games | 1,555 ms | 858 ms |
| One game | 899 ms | 491 ms |
| One map | 345 ms | 224 ms |
| Player search | 1,515 ms | 757 ms |
| Deep page | 1,421 ms | 752 ms |
| Headshot percentage | 1,444 ms | 760 ms |
| Exact player rank | 1,524 ms | 554 ms |
The small fixture's unfiltered request fell from 41 to 30 ms. All 150 additional small-fixture parity cases and 22 timed small/large request cases matched the baseline's complete responses, including ratios and record evidence. Timings include SQL preparation and evidence lookup, exclude HTTP/browser rendering, and use a warm filesystem cache with alternating implementation order. These are local synthetic measurements, not production latency guarantees. Queries still run synchronously, so larger histories remain a capacity consideration.
Validation for this change passed 1,019 unit tests, Svelte checking with no errors or warnings, and a production build. Isolated Firefox walkthroughs at 1440px and 390px checked completed-only totals, record links, efficiency qualification, scoped ranks/history, preserved navigation, empty scopes and mobile expansion.