Leaderboard System
A complete leaderboard stack — deterministic ranking, pluggable storage and a themeable UI — configurable end to end without writing a line of code.
What the system is for
Most Unity leaderboards start as a sorted list saved to PlayerPrefs and grow into a liability the moment a designer asks for "best time per player" or "top 100 across all platforms." Tie-breaking, retention policy and the UI that displays the ranking are usually improvised independently, and none of them survive the day someone wants to swap a local list for an online board.
Serenity's Leaderboard system treats ranking as a first-class business concern instead of a UI afterthought. ILeaderboardService submits entries, ranks them with the same tie semantics as a SQL RANK() query, and hands the result to a themeable view that any menu can open with zero code — while the storage backend behind it can be a local file, a database or an HTTP service without a single line of gameplay code changing.
The Unity problem
Building a leaderboard "properly" usually means solving three unrelated problems at once: how entries are ranked and deduplicated, where the ranked data lives, and how the UI renders and refreshes it. Teams that improvise all three end up with ranking rules embedded in UI code, no shared tie-breaking logic, and a save format that only works with PlayerPrefs.
The result shows up late: a board that ranks ties inconsistently between two menus, a "top 100" that silently caps at whatever PlayerPrefs can hold, or a UI that has to be rebuilt from scratch the day the project needs an online board instead of a local one.
How Serenity approaches it
Serenity exposes leaderboard behavior through ILeaderboardService, with SubmitAsync, GetTopAsync, GetPlayerRankAsync, GetAroundPlayerAsync and ClearAsync. Each board is described by a LeaderboardDefinition — sort direction, BestPerPlayer or FullHistory retention, and a MaxEntries cap — and ranking runs through a deterministic LeaderboardRanker with documented SQL RANK() tie semantics. Every submission or clear operation raises LeaderboardEntrySubmittedSignal or LeaderboardClearedSignal through the event dispatcher.
Storage is pluggable through the generic IStructuredStore persistence contract shared with the rest of Serenity's structured data: PlayerPrefs for device-local boards, human-readable JSON files, an embedded SQLite database, your own HTTP service, or a direct Postgres, MySQL or MongoDB connection. LeaderboardBackendFactory never throws — a misconfigured backend logs a warning and falls back to PlayerPrefs instead of breaking the game.
How it fits into Serenity
The Leaderboard aggregate keeps ranking engine-agnostic in the Business core — ILeaderboardService, LeaderboardDefinition, LeaderboardRanker and the signals live independent of Unity. The Unity layer adds UnityLeaderboardSettings for authoring boards, UnityLeaderboardScoreBridge to connect the Score system to submissions with a device-id or custom player identity, and LeaderboardBackendFactory to resolve the configured backend.
On top of the core sits UnityLeaderboardViewDefinition, a first-class view registered with the ViewRouter: Top-N or around-player display, configurable entry count and value formats including M:SS and H:MM:SS time, reachable from any menu option or via ShowLeaderboardSignal with zero code. The LeaderboardTemplate theme slot ships in all 8 bundled themes, so a board renders in the active theme's visual language without a custom prefab.
Practical workflow
- Define a board with LeaderboardDefinition — sort direction, BestPerPlayer or FullHistory retention and a MaxEntries cap.
- Submit scores through ILeaderboardService.SubmitAsync, or wire UnityLeaderboardScoreBridge to submit automatically whenever the Score system reports a new value.
- Query ranked results with GetTopAsync, GetPlayerRankAsync or GetAroundPlayerAsync to build custom UI, or let UnityLeaderboardViewDefinition render them for you.
- Register the view with the ViewRouter and open it from any menu option or by dispatching ShowLeaderboardSignal — no scene wiring required.
- Or skip the manual steps entirely and run Create Leaderboard: pick a preset, pick the score to track, pick where the data lives, and optionally get a ready-to-navigate leaderboard screen.
What you get
- Leaderboard service ILeaderboardService with SubmitAsync, GetTopAsync, GetPlayerRankAsync, GetAroundPlayerAsync and ClearAsync
- Deterministic LeaderboardRanker with documented SQL RANK() tie semantics
- Per-board LeaderboardDefinition with BestPerPlayer or FullHistory retention and a MaxEntries cap
- Signals LeaderboardEntrySubmittedSignal and LeaderboardClearedSignal dispatched through the event dispatcher
- Pluggable storage through IStructuredStore — PlayerPrefs, LocalFile JSON, embedded SQLite, HTTP or direct Postgres/MySQL/MongoDB
- Themeable UnityLeaderboardViewDefinition with Top-N or around-player display and M:SS/H:MM:SS time formats
- UnityLeaderboardScoreBridge connecting the Score system to submissions with device-id or custom player identity
- Five-step Create Leaderboard wizard with full rollback on failure
When to use this
- Games that need a high-score or best-time table without hand-writing ranking, storage and UI three times.
- Projects that want to start with a local leaderboard and move to an online one later without rewriting gameplay code.
- Teams that want a leaderboard screen wired into an existing menu without a programmer touching a scene.
- Codebases that already use the Score system and want submissions to happen automatically, coordinated with Persistence and UI Themes.
Related systems
Use Serenity when you want a leaderboard that ranks correctly by default, stores data wherever your project needs it, and shows up on screen without a bespoke UI build.
English
Español
Català