Leaderboard
The Genies SDK offers a leaderboard tool that can save and load persistent data so adding a leaderboard to a project is easy.
Create a Leaderboard
To create a leaderboard, make sure you have your Experience connected in the Project Settings as shown in the Getting Started tutorial.
In the Project Settings window, open the Genies > Experience Settings section in the left sidebar. Expand the Leaderboard Settings and click the Create Leaderboard button. Fill out the needed information and click Submit.
The Leaderboard Type field can be CURRENTSCORE
or HIGHESTSCORE
.
The Current Score type will rank the player's current scores, even if they've had a higher score in the past.
The Highest Score type will rank the player's highest scores, even if their current score is lower.
Copy Leaderboard ID
Once the leaderboard is created, you can copy its ID which is needed by the API methods to save and load data from it.
The Project Settings window will only display 10 leaderboards even though you can create more. To see the rest of the leaderboard IDs you will need to use an approach similar to this example.
Genies Leaderboard SDK API
The API methods for the leaderboard SDK are all within the GeniesLeaderboardSdk
class.
These are all the API methods:
import { GeniesLeaderboardSdk } from "Genies.Leaderboard";
GeniesLeaderboardSdk.GetAllLeaderboardsWithPaginationAsync
GeniesLeaderboardSdk.GetCurrentUserRankAsync
GeniesLeaderboardSdk.GetLeaderboardTopUserRanksByGroupIdAsync
GeniesLeaderboardSdk.GetLeaderboardWithIdAsync
GeniesLeaderboardSdk.GetRanksAroundUserAsync
GeniesLeaderboardSdk.GetTopNRanksAsync
GeniesLeaderboardSdk.SubmitCurrentUserScoreAsync
Save to Leaderboard
Developers can update the leaderboard data for the current user. This requires the API method: SubmitCurrentUserScoreAsync(string leaderboardId, int amount, TypeEnum saveType);
The TypeEnum can be either DIRECT
to set the leaderboard score to the amount or INCREMENT
to add the score by the amount.
Load from Leaderboard
Developers can retrieve rankings for the current user, top users, and for scores around the current user.
These are the three main API methods for obtaining data from the leaderboard:
GetCurrentUserRankAsync(string leaderboardId)
: Retrieves the logged-in user rank.GetTopNRanks(string leaderboardId, int limit)
: Retrieves the top N players on the leaderboard.GetRanksAroundUser(string leaderboardId, int howMany, int userIndex)
: Retrieves ranks around the current user, fetching a number of ranks before and after the user's position. For example, ifhowMany = 50
users anduserIndex = 30
, then it should return 29 users before the user and 20 users after the user in the list.
These methods will return objects that contain properties with the user's ID, rank, and scores.
Leaderboard Sample Project
There is a leaderboard sample project available with an example implementation of the leaderboard SDK and a nice looking UI display.
In the Package Manager window, select the Genies Experience Sdk package. Then click the Samples section and click the Import button under the Leaderboards Sample.
How to Use
Once imported, open the LeaderboardSample scene. Select the LeaderboardManager object and fill in the Leaderboard Id property with your leaderboard ID.
Enter Play mode. After logging in, you should see two button to increase your score and see the leaderboard UI.
How it Works
There are three TypeScript files in this sample project that control the logic:
LeaderBoardManager.ts
: Manages high-level actions of the leaderboard such as button listeners and initializing the logic.LeaderboardView.ts
: The main leaderboard logic is contained here for fetching the data and then displaying it.LeaderboardViewEntry.ts
: A helper class to organize each leaderboard entry to display.
Examples
Display All Leaderboard IDs
This example will display all leaderboards which is useful if any leaderboard IDs are not visible from the Project Settings window.
import { GeniesExperienceSdk } from "Genies.Experience.Sdk";
import { GeniesLeaderboardSdk } from "Genies.Leaderboard";
import { MonoBehaviour } from "UnityEngine";
import { Leaderboard, LeaderboardGetResponse } from "Genies.SDKServices.Model";
export default class LeaderboardTest extends MonoBehaviour {
public experienceID: string;
private async Start(){
await GeniesExperienceSdk.InitializeAsync();
let leaderboards: LeaderboardGetResponse = await GeniesLeaderboardSdk.GetAllLeaderboardsWithPaginationAsync(this.experienceID);
leaderboards.Leaderboards.ForEach((lb: Leaderboard) => {
console.log("Leaderboard ID: " + lb.LeaderboardId + " Name: " + lb.Name);
});
}
}
You can find the Experience ID
inside the Workshop portal in the Experience page.
Display and Set Current User Score
This example will display the user score before and after the user's score is set to 100
.
import { GeniesExperienceSdk } from "Genies.Experience.Sdk";
import { GeniesLeaderboardSdk } from "Genies.Leaderboard";
import { TypeEnum } from "Genies.SDKServices.Model.LeaderboardSubmitUserScoreRequest";
import { MonoBehaviour } from "UnityEngine";
export default class LeaderboardTest extends MonoBehaviour {
public leaderboardId: string;
private async Start(){
await GeniesExperienceSdk.InitializeAsync();
await this.DisplayUserScore();
await GeniesLeaderboardSdk.SubmitCurrentUserScoreAsync(this.leaderboardId, 100, TypeEnum.DIRECT);
console.log("Score set to 100");
await this.DisplayUserScore();
}
private async DisplayUserScore() {
let userRank = await GeniesLeaderboardSdk.GetCurrentUserRankAsync(this.leaderboardId);
if (userRank != null) {
console.log("Current User Score: " + userRank.GameScore);
}
}
}
Display Top 3 Scores and User Neighbors
This example uses code from the Leaderboard Sample Project. It combines the top 3 scores and 50 scores around the current user into a list and then displays them in the console.
import { GeniesExperienceSdk } from "Genies.Experience.Sdk";
import { GeniesLeaderboardSdk } from "Genies.Leaderboard";
import { LeaderboardGetRanksResponse, LeaderboardGetTopNRanksResponse, LeaderboardUserRank } from "Genies.SDKServices.Model";
import { MonoBehaviour } from "UnityEngine";
export default class LeaderboardTest extends MonoBehaviour {
public leaderboardId: string;
private async Start(){
await GeniesExperienceSdk.InitializeAsync();
// Top 3 ranks for the podium
const topNRanks = await this.GetTopNScores(3);
// Ranks around the user (~20 above, ~30 below)
const ranksAroundUser = await this.GetUserScoresAroundRank();
// Combine them
let rawList = topNRanks.UserRanks != null ? topNRanks.UserRanks.ToArray() : [];
if (ranksAroundUser?.UserRanks) {
rawList = rawList.concat(ranksAroundUser.UserRanks.ToArray());
}
// Filter out invalid user ranks
const filteredList = rawList.filter((r) => this.IsValidToShowOnTheLeaderboard(r));
// Remove duplicates by rank
let finalList = filteredList.reduce((acc: LeaderboardUserRank[], rank) => {
if (!acc.find((x) => x.Rank == rank.Rank)) {
acc.push(rank);
}
return acc;
}, []);
// Sort by rank ascending
finalList = finalList.sort((a, b) => a.Rank - b.Rank);
//Display the final list in the console
for (const userRank of finalList) {
console.log(`Rank: ${userRank.Rank}, User: ${userRank.PrefUsername}, Score: ${userRank.GameScore}`);
}
}
private async GetTopNScores(limit: number = 10): Promise<LeaderboardGetTopNRanksResponse> {
return GeniesLeaderboardSdk.GetTopNRanksAsync(this.leaderboardId, limit);
}
private async GetUserScoresAroundRank(): Promise<LeaderboardGetRanksResponse | null> {
return GeniesLeaderboardSdk.GetRanksAroundUserAsync(this.leaderboardId, 50, 30);
}
private isNullOrWhitespace(str: string | null | undefined): boolean {
return !str || str.trim().length === 0;
}
private IsValidToShowOnTheLeaderboard(leaderboardUserRank: LeaderboardUserRank): boolean {
if (this.isNullOrWhitespace(leaderboardUserRank.UserId)) return false;
if (this.isNullOrWhitespace(leaderboardUserRank.PrefUsername)) return false;
return true;
}
}
Display Current User Profile Icon
This example will use the GeniesProfilesSdk
class to display the current user's profile image.
import { GeniesExperienceSdk } from "Genies.Experience.Sdk";
import { GeniesLeaderboardSdk } from "Genies.Leaderboard";
import { GeniesProfilesSdk, IconResolution } from "Genies.Profiles.Sdk";
import { Ref$1 } from "Genies.Refs";
import { LeaderboardUserRank } from "Genies.SDKServices.Model";
import { MonoBehaviour, Sprite } from "UnityEngine";
import { Image } from "UnityEngine.UI";
export default class LeaderboardTest extends MonoBehaviour {
public leaderboardId: string;
public userImage: Image;
private async Start(){
await GeniesExperienceSdk.InitializeAsync();
let userRank: LeaderboardUserRank = await GeniesLeaderboardSdk.GetCurrentUserRankAsync(this.leaderboardId);
if (userRank != null) {
const result: Ref$1<Sprite> = await GeniesProfilesSdk.LoadProfileIconAsync(
userRank.UserId,
IconResolution.Ultra
);
this.userImage.sprite = result.Item;
}
}
}