Use case sample: Reward top players with in-game currency at the end of season
This use case sample demonstrates how to reward your top players with in-game currency at the end of a season. The sample uses the reset
event emitted by the Leaderboards service, and rewards the top players with in-game currency in Economy.
Prerequisites
First, you need to create a service account with the required access roles and configure the UGS CLI.
Authenticate using a Service Account
Before you can call the Triggers service, you need to authenticate with a service account.
- Navigate to the Unity Cloud Dashboard.
- Select Administration > Service Accounts.
- Select the New button and enter a name and description for the service account.
- Select Create.
Add Product roles and create a key:
- Select Manage product roles.
- Add the following roles to the Service Account:
- From the LiveOps dropdown, select the following roles:
- Triggers Configuration Editor
- Triggers Configuration Viewer
- Economy Resource Editor
- Economy Resource Viewer
- Leaderboards Admin
- Leaderboards Viewer
- If you're deploying a Cloud Code module, add the following roles:
- Cloud Code Editor
- Cloud Code Viewer
- If you're deploying a Cloud Code script, add the following roles:
- Cloud Code Editor
- Cloud Code Viewer
- Cloud Code Publisher
- From the Admin dropdown, select Unity Environments Viewer.
- From the LiveOps dropdown, select the following roles:
- Select Save.
- Select Add Key.
- Encode the Key ID and Secret key using base64 encoding. The format is “key_id:secret_key”. Note this value down.
For more information, refer to Authentication.
Configure the UGS CLI
Follow the steps below to get started with the UGS CLI:
Use the following to configure your Project ID and Environment:
ugs config set project-id <your-project-id>
ugs config set environment-name <your-environment-name>
Use the service account you authenticated earlier to authenticate. Refer to Get Authenticated.
Examine the reset
event
The Leaderboards service emits a reset
when a leaderboard is reset. The event payload looks like this:
{
"leaderboardId": "string",
"leaderboardVersionId": "string"
}
The event payload passes on to Cloud Code as parameters.
Refer to the Leaderboards Reset event for more information.
Create deployment files
This sample implements by deploying configuration files for each service with the UGS CLI.
To implement the use case sample, you need to set up the following files:
COIN.ecc
: Contains the Economy currency configuration.leaderboard.lb
: Contains the Leaderboards configuration.triggers-config.tr
: Contains the Triggers configuration.- A Cloud Code module or script to define logic for rewarding your top players with in-game currency when the leaderboard is reset.
Create a folder called reward-top-players
to store all the files.
You can deploy them all at once.
Set up Economy
To reward your top players with in-game currency, you need to create a virtual currency in Economy.
Create a Economy config file using the UGS CLI:
ugs economy currency new-file COIN.ecc
Add the following content to the COIN.ecc
file:
{
"$schema": "https://ugs-config-schemas.unity3d.com/v1/economy/economy-currency.schema.json",
"initial": 0,
"name": "Coin"
}
The configuration defines a virtual currency and the name Coin
.
The file name corresponds to the currency ID.
Set up Leaderboards
Create a Leaderboard config file using the UGS CLI:
ugs leaderboards new-file leaderboard.lb
Add the following content to the leaderboard.lb
file:
{
"$schema": "https://ugs-config-schemas.unity3d.com/v1/leaderboards.schema.json",
"SortOrder": "asc",
"UpdateType": "keepBest",
"Name": "leaderboard"
}
The configuration defines a leaderboard with ascending sort order and keeps the best score. The file name corresponds to the leaderboard ID.
Set up Cloud Code
You need to create either a Cloud Code module or script to define logic for rewarding your top players with in-game currency when the leaderboard is reset.
Cloud Code C# module
You can use the Economy and Leaderboards Client SDKs to interact with the Economy and Leaderboards services.
Create a new Cloud Code module using the UGS CLI:
ugs cc m new-file RewardTopPlayers RewardTopPlayers
Then, add the following contents to the sample solution. Create a module function with a string argument leaderboardId
:
C#
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Unity.Services.CloudCode.Apis;
using Unity.Services.CloudCode.Core;
using Unity.Services.CloudCode.Shared;
using Unity.Services.Economy.Model;
using Unity.Services.Leaderboards.Model;
namespace RewardTopPlayers;
public class RewardTopPlayers
{
private const string CoinsKey = "COIN";
private const int Amount = 10;
private readonly ILogger<RewardTopPlayers> _logger;
public RewardTopPlayers(ILogger<RewardTopPlayers> logger)
{
_logger = logger;
}
[CloudCodeFunction("IssueReward")]
public async Task Reward(IExecutionContext ctx, IGameApiClient gameApiClient, string leaderboardId, string leaderboardVersionId)
{
var top5Players = await GetTop5(ctx, gameApiClient, leaderboardId, leaderboardVersionId);
foreach (var score in top5Players)
{
try
{
// Retrieve the player's configuration to ensure currency configuration is synced
var configResponse = await gameApiClient.EconomyConfiguration.GetPlayerConfigurationAsync(ctx, ctx.ServiceToken, ctx.ProjectId, score.PlayerId);
var res = await gameApiClient.EconomyCurrencies.IncrementPlayerCurrencyBalanceAsync(ctx, ctx.ServiceToken, ctx.ProjectId,
score.PlayerId,
CoinsKey, new CurrencyModifyBalanceRequest(amount: Amount), configResponse.Data.Metadata.ConfigAssignmentHash);
_logger.LogInformation("Incremented balance for playerId {playerId} by {amount}", score.PlayerId, Amount);
}
catch (ApiException e)
{
_logger.LogError(e, "Failed to increment balance for playerId {playerId}. Error: {Error}", score.PlayerId, e.Message);
throw;
}
}
}
public async Task<List<LeaderboardEntry>> GetTop5(IExecutionContext ctx, IGameApiClient gameApiClient, string leaderboardId, string leaderboardVersionId)
{
try
{
var results = await gameApiClient.Leaderboards.GetLeaderboardVersionScoresAsync(ctx, ctx.ServiceToken, new Guid(ctx.ProjectId),
leaderboardId, leaderboardVersionId, 0, 5);
return results.Data.Results;
}
catch (ApiException e)
{
_logger.LogError(e, "Failed to get top players for leaderboard: {LeaderboardId}. Error: {Error}", leaderboardId, e.Message);
throw new Exception($"Failed to get top players for leaderboard: {leaderboardId}. Error: {e.Message}");
}
}
public class ModuleConfig : ICloudCodeSetup
{
public void Setup(ICloudCodeConfig config)
{
config.Dependencies.AddSingleton(GameApiClient.Create());
}
}
}
Cloud Code JavaScript script
You can achieve the same outcome by creating a Cloud Code script.
Create a new Cloud Code script using the UGS CLI:
ugs cc s new-file RewardTopPlayers.js
Then, add the following contents to the sample script file:
JavaScript
const axios = require("axios");
const { CurrenciesApi, ConfigurationApi } = require("@unity-services/economy-2.4");
const { LeaderboardsApi } = require("@unity-services/leaderboards-1.1");
module.exports = async ({ params, context, logger }) => {
// Get top 5 players from the Leaderboard
const leaderboardsApi = new LeaderboardsApi(context);
const cointAmount = 10;
let result;
try {
result = await leaderboardsApi.getLeaderboardVersionScores(context.projectId, params.leaderboardId, params.leaderboardVersionId, 0, 5);
} catch (err) {
logger.error("Failed to retrieve players from the leaderboard", { "error.message": err.message }, { "leaderboardId": params.leaderboardId });
throw err;
}
const currencyId = "COIN";
const currenciesApi = new CurrenciesApi(context);
const configApi = new ConfigurationApi(context);
// Reward currency to every player
const promises = result.data.results.map(async (score) => {
try {
// Retrieve the player config to get the configAssignmentHash.
// This is needed to ensure the currency is synced
var config = await configApi.getPlayerConfiguration({
playerId: score.playerId,
projectId: context.projectId,
});
await currenciesApi.incrementPlayerCurrencyBalance({
currencyId,
playerId: score.playerId,
projectId: context.projectId,
configAssignmentHash: config.data.metadata.configAssignmentHash,
currencyModifyBalanceRequest: { amount: cointAmount },
});
} catch (err) {
logger.error("Failed to increment currency for player", { "error.message": err.message }, { "affectedPlayerId": score.playerId });
return;
}
});
await Promise.all(promises);
};
Set up Triggers
To connect your Cloud Code resource to the schedule, create a trigger. The trigger executes the Cloud Code script or module when the event fires, for example, when the leaderboard resets.
ugs tr new-file triggers-config.tr
If you created a Cloud Code module, use the following configuration:
{
"$schema": "https://ugs-config-schemas.unity3d.com/v1/triggers.schema.json",
"Configs": [
{
"Name": "reward-leaderboard",
"EventType": "com.unity.services.leaderboards.reset.v1",
"ActionUrn": "urn:ugs:cloud-code:RewardTopPlayers/IssueReward",
"ActionType": "cloud-code"
}
]
}
If you created a Cloud Code script, use the following configuration:
{
"$schema": "https://ugs-config-schemas.unity3d.com/v1/triggers.schema.json",
"Configs": [
{
"Name": "reward-leaderboard",
"EventType": "com.unity.services.leaderboards.reset.v1",
"ActionUrn": "urn:ugs:cloud-code:RewardTopPlayers",
"ActionType": "cloud-code"
}
]
}
Deploy the configuration files
You should have the following files in your reward-top-players
folder:
COIN.ecc
- Contains the Economy currency configuration.leaderboard.lb
- Contains the Leaderboard configuration.triggers-config.tr
- Contains the Trigger configuration.
And one of the following:
RewardTopPlayers.sln
folder - Contains the Cloud Code module.RewardTopPlayers.js
- Contains the Cloud Code script.
You can deploy them all at once using the UGS CLI:
ugs deploy .
Optional: Add scores to the leaderboard
You can run the following Cloud Code script to add scores to the leaderboard from the Unity Cloud Dashboard. Make sure to regenerate the Player ID token on every test run to add a new player.
JavaScript
const { LeaderboardsApi } = require("@unity-services/leaderboards-1.1");
const _ = require("lodash-4.17");
module.exports = async ({ params, context, logger }) => {
const leaderboardsApi = new LeaderboardsApi({ accessToken: context.accessToken });
const leaderboardID = "leaderboard";
var randomScore = _.random(1, 100);
try {
await leaderboardsApi.addLeaderboardPlayerScore(context.projectId, leaderboardID, context.playerId, { score: randomScore });
} catch (err) {
logger.error("Failed to add score to the leaderboard", { "error.message": err.message });
}
};
This allows you to add scores to the leaderboard and test the use case sample.
Validate the result
To validate the result, note down a player ID from the leaderboard before it's reset:
- Navigate to the Unity Cloud Dashboard.
- Select Products > Leaderboards.
- Select the Overview section.
- Select the
leaderboard
leaderboard. - Select the Entries tab.
- Note down one of the top player IDs.
Then, reset the leaderboard:
- Navigate to the Unity Cloud Dashboard.
- Select Products > Leaderboards.
- Select the Overview section.
- Select the
leaderboard
leaderboard. - Select Reset Leaderboard .
- Enable Archive current scores.
To validate that the player has been rewarded with 10 coins, follow the steps below:
- Select Products > Player Management.
- In the search field, enter the player ID you noted down earlier and select Find Player.
- Navigate to the Economy > Currencies section. If successful, you can find that the player has been rewarded with 10 coins.
To learn more about how to configure your leaderboard resets to compliment your game logic, refer to Resets.