Files
electric-cherry/docs/leaderboard.md
T

91 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Leaderboard
Open **Leaderboard** in the main navigation to compare players across the fleet,
or filter by game and map. Choose a ranking, search a name or GUID, and share the
page URL with its filters intact. Results refresh while the page is visible.
Active games contribute as soon as a round report arrives.
Click a player's name to open their shareable profile at
`/leaderboard/players/[game]/[guid]`. 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; match history shows individual counters, server, date and completion
credit in pages of 25 games. Map names link back to that map's leaderboard.
Use **Refresh stats** to load the latest reports. Ratios with a zero denominator
display a dash. Profiles always cover all recorded maps for that game and player.
The leaderboard uses the existing three telemetry events; no reporter change is
required. Each player is identified by **game + GUID**, with their latest reported
name displayed. Different names for the same GUID do not split their records;
identical names with different GUIDs remain separate. 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 | Games in which at least one stats report contains the player. A start-only roster does not count yet. |
| 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 within the selected game/map. Summary
cards describe that game/map, regardless of the search text. Summary rounds are
player-rounds: four players progressing from game start to round 8 contribute 28.
Highest-round records always use the round reached, including the final round
and players who joined mid-game.
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
rollout 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`.
Metric keys are `highestRound`, `kills`, `roundsSurvived`, `headshots`, `revives`,
`downs`, `gamesPlayed`, `gamesCompleted`, `bestKills`, and `bestScore`.