Docs / Leaderboards & tournaments

Leaderboards & tournaments

Score tables with multiple scoring modes and time windows. Tournaments wrap leaderboards with seasonal resets, brackets, and prize distribution.

Leaderboard models

  • Monotonic — keeps the highest score submitted per player (e.g. “best lap”).
  • Cumulative — sums submissions (e.g. “total XP”).
  • Windowed — same as above but with a rolling time window (weekly / monthly) that resets automatically.

Submitting scores

Lua

game.leaderboard.submit("arena:weekly", player_id, kills)

Erlang

asobi_leaderboard:submit(<<"arena:weekly">>, PlayerId, Kills).

Reading

Lua

for _, e in ipairs(game.leaderboard.top("arena:weekly", 10)) do
    print(e.rank, e.player_id, e.score)
end
local my_rank = game.leaderboard.rank("arena:weekly", player_id)
local near    = game.leaderboard.around("arena:weekly", player_id, 5)

Erlang

{ok, Top}  = asobi_leaderboard:top(<<"arena:weekly">>, 10),
{ok, Rank} = asobi_leaderboard:rank(<<"arena:weekly">>, PlayerId),
{ok, Near} = asobi_leaderboard:around(<<"arena:weekly">>, PlayerId, 5).

REST

GET  /api/v1/leaderboards/:id                  Top N entries
GET  /api/v1/leaderboards/:id/around/:player   Entries around a player
POST /api/v1/leaderboards/:id                  Submit a score

Definitions

Register leaderboards in sys.config:

{asobi, [
    {leaderboards, #{
        <<"arena:weekly">> => #{
            mode    => monotonic,
            window  => {weekly, monday, 0},   %% reset Monday 00:00 UTC
            bucket  => <<"arena">>
        },
        <<"xp:lifetime">> => #{mode => cumulative}
    }}
]}

Tournaments

Tie a leaderboard to a season + bracket. Players join, submit scores during the window, and at close the tournament resolves brackets and distributes prizes.

GET  /api/v1/tournaments               List active tournaments
GET  /api/v1/tournaments/:id           Get tournament details
POST /api/v1/tournaments/:id/join      Join a tournament
{ok, TId} = asobi_tournament:create(#{
    leaderboard  => <<"arena:weekly">>,
    starts_at    => {{2026,4,22},{16,0,0}},
    ends_at      => {{2026,4,29},{16,0,0}},
    entry_fee    => #{currency => <<"gold">>, amount => 100},
    prize_pool   => #{<<"gold">> => 100000},
    distribution => [0.5, 0.3, 0.2]   %% top 3 split
}).

Seasons

Seasons wrap longer lifecycles (weekly competitive, monthly events). When a season ends, leaderboards tied to it reset and archive snapshots are persisted for history queries.

Where next?