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.

  1. Navigate to the Unity Cloud Dashboard.
  2. Select Administration > Service Accounts.
  3. Select the New button and enter a name and description for the service account.
  4. Select Create.

Add Product roles and create a key:

  1. Select Manage product roles.
  2. 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.
  3. Select Save.
  4. Select Add Key.
  5. 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:

  1. Install the UGS CLI.

  2. 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>

  3. 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:

  1. Navigate to the Unity Cloud Dashboard.
  2. Select Products > Leaderboards.
  3. Select the Overview section.
  4. Select the leaderboard leaderboard.
  5. Select the Entries tab.
  6. Note down one of the top player IDs.

Then, reset the leaderboard:

  1. Navigate to the Unity Cloud Dashboard.
  2. Select Products > Leaderboards.
  3. Select the Overview section.
  4. Select the leaderboard leaderboard.
  5. Select Reset Leaderboard .
  6. Enable Archive current scores.

To validate that the player has been rewarded with 10 coins, follow the steps below:

  1. Select Products > Player Management.
  2. In the search field, enter the player ID you noted down earlier and select Find Player.
  3. 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.