League and Division Leaderboards

This tutorial will demonstrate one way of creating Leaderboards that allocate users' entries based on what league and division they're placed in. Players will also be promoted and demoted depending on how well they did. By using Leaderboards, Events, Cloud Code, Schedulers, Segments, and player scriptData we'll create a system that is both editable and simple.

Registration and League Placement

When a player in your game registers, their league segment needs to be initialized and they need to be assigned a placement status before they're allocated a league.

First, we ensure that when a player sends a RegistrationRequest, we input the value placement in the segments object using a key value pair like this:

{
  "@class": ".RegistrationRequest",
  "displayName": "",
  "password": "",
  "segments": {"league":"placement"},
  "userName": ""
}

This will help your Cloud Code figure out what to do with a player when they finish a game:

Events and Modules

Modules

We need to create one module.

mod_DivisionPlacement

This module will allocate the player in a division in their chosen league. This will fire after the player has been placed in their league, when they're demoted and when they're promoted.

Cloud Code for mod_DivisionPlacement:

//Load player
var currentPlayer = Spark.loadPlayer(pID);
//While loop condition
var positioned = false;
//Loop counter
var loop = 1;
//Player's league
var league = currentPlayer.getSegmentValue("league");


//While loop will check if divisions have space for this player
while(positioned === false){
   //Load the division based on the loop counter and check if it has space
    var ldrName = "ldr_Global.division.".concat(loop.toString()).concat(".league.").concat(league);
    if(Spark.getLeaderboards().getLeaderboard(ldrName) !== null){
        //Check if there's less than 100 entries (100 players)
        if(Spark.getLeaderboards().getLeaderboard(ldrName).getEntryCount() < 100){
            currentPlayer.setScriptData("division", loop);
            positioned = true;

        }else{  
            //If division is full, look into the next one
            loop = loop + 1;
        }
    } else{
        //If the division doesn't exist, set it as the player's division
        currentPlayer.setScriptData("division", loop);
        positioned = true;
    }
}

Events

We'll need to create and configure three Events for this tutorial.

event_InputScore

This Event will be used to update the global Leaderboards and division specific Leaderboards. The player will post their score, league, divison, and the time posted which will help decide which Leaderboard their entry belongs to.

event_InputScore Attributes:

Name Shortcode Data Type Default Val Default Aggregation
score score Number Sum
league league String Grouped
division division Number Grouped
date date String ${format(now, "yyyy-MM")} Grouped

event_Placement

This event will transfer players from the 'placement' stage to a league and a division.

event_Placement Attributes:

Name Shortcode Data Type Default Val Default Aggregation
score score Number Used In Script

event_Placement Cloud Code:

//Get input Score value
var inputScore = Spark.getData().score;
//Get player ID
var pID = Spark.getPlayer().getPlayerId();

//Add score to player's placement score
var scriptScore = Spark.getPlayer().getScriptData("placementScore");
 //Check if score is valid
 if (scriptScore !== null){
     var score = scriptScore + inputScore;
     Spark.getPlayer().setScriptData("placementScore", score);
 }
 //If not valid, create it
 else{
     var score = inputScore;
     Spark.getPlayer().setScriptData("placementScore", score);
 }

 //Check how many placement games the player has attempted
 var attempts = Spark.getPlayer().getScriptData("placementAttempts");
 //Check if valid
 if(attempts !== null){
     //If 5 games have been played, check score and place player in the correct league
     if(attempts >= 5){
         if(score >= 3 && score <= 4){
            Spark.getPlayer().setSegmentValue("league", "silver")
         } else if(score >= 5){
            Spark.getPlayer().setSegmentValue("league", "gold")
         } else{
             Spark.getPlayer().setSegmentValue("league", "bronze")
         }
         //Sort division
         require("mod_DivisionPlacement");
     }
     //If player hasn't played 5, increment attempts
     else{
      Spark.getPlayer().setScriptData("placementAttempts", attempts+1);   
     }
     }
//If not valid, create a reference     
else{
    Spark.getPlayer().setScriptData("placementAttempts", 1);
}

event_EndGame

After every game all players will call this Event. This Event will:

event_EndGame Attributes:

Name Shortcode Data Type Default Val Default Aggregation
score score Number Used In Script

event_EndGame Cloud Code:

//Load variables
var league = Spark.getPlayer().getSegmentValue("league");
var score = Spark.getData().score;
var date = new Date;


//Check if player has been placed yet
if(league !== "placement"){

    if(Spark.getPlayer().getScriptData("division") === 0){
        require("mod_DivisionPlacement");
    }

    //If player is placed, send a score to be sorted in Leaderboard
    var date = new Date;
    var year = date.getFullYear();
    var month = date.getMonth();
    var request = new SparkRequests.LogEventRequest();

    request.eventKey = "event_InputScore";
    request.score = score;
    request.league = Spark.getPlayer().getSegmentValue("league");
    request.division = Spark.getPlayer().getScriptData("division");
    //Creating partition value with the format YYYY-MM for monthly periods
    request.date = year.toString() + "-" + ("0" + (month+1).toString()).slice(-2);

    request.Send();

} else{
    //If player hasn't been placed, update their placement details
    var request = new SparkRequests.LogEventRequest();

    request.eventKey = "event_Placement";
    request.score = score;

    request.Send();

}

Leaderboards

Global League Leaderboard

This Leaderboard will contain all entries for one league. For example, Bronze entries will be comparable and listed in one Leaderboard regardless of division.

Global League Leaderboard Fields:

Running Total Collector Filter type Filter Value Group
Input Score event_InputScore.score.all * Sum
Input Score event_InputScore.date.all * Partition
Input Score event_InputScore.league.all = bronze Maximum

Notes:

Division Specific Leaderboard

This Leaderboard is configured to keep track of division specific entries so players can compare their record with players in their division.

Division Specific Leaderboard Fields:

Running Total Collector Filter type Filter Value Group
Input Score event_InputScore.score.all * Sum
Input Score event_InputScore.division.all * Partition
Input Score event_InputScore.league.all * parition

Note:

Schedule

Using GS Daily for Promotions and Demotions

At the end of the month we want our players to be demoted and promoted based on how well they did. Once their league is changed they need to be placed in an available league.

The GS Daily script can be found under Cloud Code>System>Every Day. The script runs every day. You can use it to create schedule logic. In this example, we check if the day is the first of the month and, if it is, then we run our logic to promote the top 10 and demote the bottom 10 from every league.

GS Daily Script Cloud Code:

var today = new Date;


if(today.getDate() === 1){

    //Load league Leaderboards
    var bronzeLDR = Spark.getLeaderboards().getLeaderboard("bronze");
    var silverLDR = Spark.getLeaderboards().getLeaderboard("silver");
    var goldLDR = Spark.getLeaderboards().getLeaderboard("gold");;

    //Loads top 10 entries, forget top league because they can't promote
    var bronzeLDR_TOP = bronzeLDR.getEntries(10, 0);
    var silverLDR_TOP = silverLDR.getEntries(10, 0);

    //Loads bottom 10 entries, forget bottom league because they can't demote
    var silverLDR_BOT = silverLDRgetEntries(10, silverLDR.getEntryCount() - 10);
    var goldLDR_BOT = silverLDR.getEntries(10, goldLDR.getEntryCount() - 10);

    //Go through top entries and promote their players
    while(bronzeLDR_TOP.hasNext()){
        var pID = bronzeLDR_TOP.next().getUserId()
        Spark.loadPlayer(pID).setSegmentValue("league", "silver");
    }
    while(silverLDR_TOP.hasNext()){
        var pID = silverLDR_TOP.next().getUserId()
        Spark.loadPlayer(pID).setSegmentValue("league", "gold");
    }

    //Go through bottom entries and demote their players
    while(silverLDR_BOT.hasNext()){
        var pID = silverLDR_BOT.next().getUserId();
        Spark.loadPlayer(pID).setSegmentValue("league", "bronze");

    }
    while(goldLDR_BOT.hasNext()){
        var pID = goldLDR_BOT.next().getUserId();
        Spark.loadPlayer(pID).setSegmentValue("league", "silver");
    }

}
Did this page help you? Please enter your feedback below. For questions about using this part of the platform, please contact support here