League play can be used to provide an even more engaging social and competitive gameplay experience.
A league functions as a set of linked leaderboards where each leaderboard represents a particular “tier” of your league’s hierarchy. At the beginning of the league “season”, all players start in the first (bottom) tier. A desired play period is implemented during which players compete against all others in their specific tier. At the end of each play period, a certain set of players at the top of the leaderboard are promoted to the next tier and a certain set at the bottom of the leaderboard are relegated to a lower tier.
Players receive rewards at the end of each play period. The amount and kind of reward is determined by their tier and ranking within it, helping to drive player competition and engagement throughout the league duration.
Leagues can be customized to suit your particular game and needs. The rewards given are dependent on your game’s economy, and you may decide to have players pay an entry fee to join the league. You can create an unlimited number of player tiers, using any promotion and relegation logic desired. This could be the creation of promotion and relegation zones on each leaderboard based on percentages (or other metrics), or a defined number of players (e.g top and bottom 10) to be promoted and relegated after each play period.
For our example below, we use a two tiered league where the top three players after each weekly play period are promoted, and the bottom three players each week are relegated. The in-game currency rewards double in value between the bottom and top tiers of the league.
Create tier leaderboards
Here we create two linked leaderboards for our league, one each for the lower and top tier, that will reset every week.
// Server
// Create the two tiers of leaderboards
let bottomTierId = "bottom-tier";
let topTierId = "top-tier";
let authoritative = true;
let sortOrder = nkruntime.SortOrder.DESCENDING;
let operator = nkruntime.Operator.INCREMENTAL;
let resetSchedule = "0 0 * * 1";
let metadata = {};
nk.leaderboardCreate(bottomTierId, authoritative, sortOrder, operator, resetSchedule, metadata);
nk.leaderboardCreate(topTierId, authoritative, sortOrder, operator, resetSchedule, metadata);
Promotion and relegation
After each weekly play period ends, we promote the top three players from the lower tier to the top tier. Correspondingly, we also relegate the bottom three players from the top tier to the lower one.
Keep in mind that at the beginning all players are in the bottom tier, so we must first check that there are sufficient players advanced to the top tier before performing any relegation.
// Server
// Register leaderboard reset function to handle promotions and relegations
let leaderboardReset: nkruntime.LeaderboardResetFunction = function (ctx: nkruntime.Context, logger: nkruntime.Logger, nk: nkruntime, leaderboard: nkruntime.Leaderboard, reset: number) {
// We're only interested in our top/bottom tier leaderboards so return if it isn't them
if (leaderboard.id !== topTierId && leaderboard.id !== bottomTierId) {
return;
}
// Get all leaderboard records (assuming the tier has no more than 10,000 players)
let result = nk.leaderboardRecordsList(leaderboard.id, null, 10000, null, reset);
// If leaderboard is top tier and has 10 or more players, relegate bottom 3 players
if (leaderboard.id === topTierId && result.records.length >= 10) {
// Relegate record owner by copying their record into the bottom tier and deleting their current top tier record
result.records.slice(result.records.length-3).forEach(function (r) {
nk.leaderboardRecordWrite(bottomTierId, r.ownerId, r.username, r.score, r.subscore, null, null);
nk.leaderboardRecordDelete(topTierId, r.ownerId);
});
}
// If leaderboard is bottom tier and has 10 or more players, promote top 3 players
if (leaderboard.id === topTierId && result.records.length >= 10) {
// Promote record owner by copying their record into the top tier and deleting their current bottom tier record
result.records.slice(0, 3).forEach(function (r) {
nk.leaderboardRecordWrite(topTierId, r.ownerId, r.username, r.score, r.subscore, null, null);
nk.leaderboardRecordDelete(bottomTierId, r.ownerId);
});
}
};
initializer.registerLeaderboardReset(leaderboardReset);
Rewards
Also at the conclusion of each weekly play period, we distribute rewards to all players inline with their tier and respective ranking within it.
// Server
// Register leaderboard reset function to handle promotions and relegations
let leaderboardReset: nkruntime.LeaderboardResetFunction = function (ctx: nkruntime.Context, logger: nkruntime.Logger, nk: nkruntime, leaderboard: nkruntime.Leaderboard, reset: number) {
// Relegation/Promotion code as above...
// Distribute rewards based on player's tier
let walletUpdates : nkruntime.WalletUpdate[];
result.records.forEach(function (r) {
let reward = 100;
// Increase reward for top tier players
if (leaderboard.id === topTierId) {
reward = 500;
}
walletUpdates.push({
userId: r.ownerId,
changeset: { coins: reward},
metadata: {}
})
});
nk.walletsUpdate(walletUpdates, true);
};