Documentation menu

Statistics & leaderboards

Increment a stat once and get daily, weekly, monthly and lifetime leaderboards for free. The hub keeps the rolling windows.

You write one line when something happens. The hub keeps four rolling leaderboards from it - daily, weekly, monthly and lifetime - and hands them all back on every increment.

OnWin.java
// A win happened. One call, every window moves at once.
hive.player()
    .incrementStatistic(player.uuid(), "wins", "skywars", 1)
    .thenAccept(now -> {
      // now: { DAILY: 3, WEEKLY: 11, MONTHLY: 40, LIFETIME: 512 }
      player.sendMessage("Win #" + now.get("LIFETIME"));
    });

That single +1 updated four windows at once. No cron jobs, no nightly rollups, no “reset the weekly board” task. You never schedule anything:

PeriodCountsResets
DAILYtoday (UTC)midnight UTC
WEEKLYthis weekMonday
MONTHLYthis monththe 1st
LIFETIMEall timenever

Scoped to your game

A stat lives under its game mode, so "wins" in "skywars" and "wins" in "bedwars" are different numbers that never touch each other. Same stat name, separate boards, zero coordination between games.

Reading them back

getStatistic(name, period) pulls a single window - the weekly board, the lifetime total, whatever you need:

Stats.java
// "This week's top players" is one read.
hive.player()
    .getStatistics(player.uuid(), "skywars")
    .thenAccept(stats -> {
      StatisticValue weekly = stats.getStatistic("wins", PeriodType.WEEKLY);
      long wins = weekly != null ? weekly.getValue() : 0;
    });

Each StatisticValue carries its periodType, the periodStart it belongs to, the value, and when it was last updated - so a leaderboard is just “read this stat, this period, top N.”

Stat or namespace? Counters you want ranked or counted over time → incrementStatistic. Structured state that’s just yours → namespaces. Don’t hand-roll a leaderboard in a JSON blob - that’s what stats are for.

Next