Event Leaderboards #

Timed leaderboard event used in Candy Crush Saga by King
Timed leaderboard event used in Candy Crush Saga by King

Event leaderboards are a high-level feature of Hiro, built on top of the Nakama leaderboards feature, that enable you to add timed and scored events, which are a great way to add competitive elements to your game. These events can optionally have an associated cost to participate.

Timed event leaderboards allow users to play against a bucket of opponents for the duration of the event. This bucket of opponents is generated on request and the duration is configured via a CRON expression. At the end of the event rewards are distributed based on a range of ranks.

Scored event leaderboards allow users to play against a bucket of opponents and “race” towards a defined target score. If the target score is achieved within the defined range of rewards, the user is a winner.

When the range of ranks for rewards is achieved by the specified number of users, the opponents for all of those users can be “rerolled”. The rerolled opponents can be played again to race for rewards. This can happen up to a maximum number of configurable rerolls. At the end of the duration of the event no more rerolls can be made and the event ends.

For both types of event the bucket of opponents generated for each user is individual to that user and can be specified up to a maximum of 100 players.

Customization parameters #

The following JSON represents the customization parameters you can use to configure the default user experience for the leaderboard system.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
{
  "events": {
    "leaderboard_id1": {
      "name": "Chef Tournament",
      "description": "Play a tournament against other chefs for great rewards!",
      "operator": "set",
      "sort": "desc",
      "start_time": 0,
      "end_time": 0,
      "reset": "0 0 */3 * *", // At 12:00 AM, every 3 days.
      "score_target": 0,
      "max_reroll_count": 0,
      "bucket_size": 50,
      "resource_id": "",
      "cost": {
        "currencies": {
          "coins": 0
        }
      },
      "reward_ranges": [
        {
          "rank_start": 1,
          "rank_end": 1,
          "reward": {
            "currencies": {
              "gems": 100
            }
          }
        }
      ],
      "reward_ranges_team": [
        {
          "rank_start": 1,
          "rank_end": 1,
          "reward": {
            "currencies": {
              "gems": 100
            }
          }
        }
      ]
    }
  }
}

The JSON schema defines an events object which must contain an individual object for each leaderboard you wish to define in the system. You can configure as few or as many energy types as needed for your desired gameplay.

Each leaderboard is keyed by id and may define the following:

PropertySubpropertyDescription
nameThe name of this leaderboard.
descriptionThe description of this leaderboard.
operatorThe leaderboard operation (e.g. set, best, incr, or decr).
sortThe leaderboard sort type (e.g. asc or desc).
start_timeThe start time (as a UNIX timestamp) of this leaderboard.
end_timeThe end time (as a UNIX timestamp) of this leaderboard.
resetThe reset schedule of this leaderboard expressed as a CRON expression.
score_targetAn optional score target a user must reach for the leaderboard event to be considered won.
max_reroll_countThe maximum amount of times a user can reroll their score.
bucket_sizeThe size of the bucket of users when using bucketed leaderboards.
resource_idA string hint for the client (e.g. addressable field).
costAn object that defines the entry cost for this leaderboard.
currenciesA string:int dictionary of currencies and quantities the user should receive as a reward.
reward_rangesAn array of objects that define the various rewards available to players based on their final rank in the leaderboard.
rank_startThe first rank included in the reward range.
rank_endThe last rank included in the reward range.
rewardAn object that defines what rewards the players will receive. See schema below for properties.
reward_ranges_teamAn array of objects that define the various rewards available to players who participate in a team based on the team’s final rank in the leaderboard.
rank_startThe first rank included in the reward range.
rank_endThe last rank included in the reward range.
rewardAn object that defines what rewards the players will receive. See schema below for properties.

The rewards properties above (reward_ranges, reward_ranges_team) have the additional sub-properties:

PropertyDescription
currenciesA string:int dictionary of currencies and quantities the user will receive for the given rank range.

Initializing the event leaderboards system #

The event leaderboards system relies on the Nakama System which must be passed in as dependency via the constructor. You can also pass an array of event leaderboard Ids for which you would like to retrieve the initial leaderboard records for.

1
2
var eventLeaderboardsSystem = new EventLeaderboardsSystem(nakamaSystem, new [] { "<leaderboardId>" });
systems.Add(eventLeaderboardsSystem);

Subscribing to changes in the event leaderboards system #

You can listen for changes in the event leaderboards system so that you can respond appropriately, such as updating the UI, by implementing the appropriate interface.

1
2
3
4
5
var disposer = SystemObserver<EventLeaderboardsSystem>.Create(eventLeaderboardsSystem, system => {
  Instance.Logger.Info($"System updated.");

  // Update UI elements etc as necessary here...
});

Refreshing the leaderboards system #

To ensure the event leaderboards system has the latest information from Nakama you can refresh it.

1
await eventLeaderboardsSystem.RefreshAsync();

You can also refresh an individual event leaderboard by passing it’s ID and optionally a cursor.

1
await eventLeaderboardsSystem.RefreshAsync("<leaderboardId>", "<optionalCursor>");

Listing event leaderboards #

You can list all event leaderboards for the user.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
foreach (var leaderboardKvp in eventLeaderboardsSystem.EventLeaderboards)
{
    var id = leaderboardKvp.Key;
    var leaderboard = leaderboardKvp.Value;
    Debug.Log($"Leaderboard {id} - {leaderboard.Name}. Current rank: {leaderboard.Rank}");

    if (leaderboard.CanClaim)
    {
        Debug.Log("You are eligible to claim your reward.");
    }
}

Getting an individual event leaderboard #

You can get an individual event leaderboard, including it’s records and information on it’s rewards.

1
var leaderboard = await eventLeaderboardsSystem.GetEventAsync("<leaderboardId>");

Submitting an event leaderboard score #

You can submit an event leaderboard score for the user.

1
2
3
var score = 100;

await eventLeaderboardsSystem.WriteEventScoreAsync("<leaderboardId", score);

Claiming rewards #

You can claim event leaderboard rewards for the user.

1
await eventLeaderboardsSystem.ClaimEventRewardsAsync("<leaderboardId>");

Joining or re-rolling an event leaderboard #

You can join or re-roll an event leaderboard as a user. A re-roll would occur when a user has previously joined an event leaderboard and claimed their reward but would now like to re-join again for another chance at claiming a reward.

1
await eventLeaderboardsSystem.JoinOrRerollEventAsync("<leaderboardId>");