ユースケースサンプル: シーズンの終わりにゲーム内通貨で上位プレイヤーに報酬を与える

ユースケースサンプルでは、シーズンの終わりにゲーム内通貨で上位プレイヤーに報酬を与える方法を示します。Leaderboards サービス によって発行される reset イベントを使用し、上位プレイヤーに Economy のゲーム内通貨でゲーム内報酬を与えます。

前提条件

最初に、必要なアクセスロールでサービスアカウントを作成し、UGS CLI を設定する必要があります。

サービスアカウントを使用した認証

Scheduling および Triggers サービスを呼び出す前に、サービスアカウントを使用して認証を使用する必要があります。

  1. Unity Dashboard Admin Portal に移動します。
  2. Service Accounts (サービスアカウント) を選択します。
  3. Create Service Account (サービスアカウントの作成) を選択し、サービスアカウントの名前を入力します。
  4. Create (作成) を選択します。
  5. Add project role (プロジェクトロールの追加) を選択します。
  6. 以下のロールをサービスアカウントに追加します。
    • Scheduler 設定編集者
    • Scheduler 設定閲覧者
    • Triggers 設定編集者
    • Triggers 設定閲覧者
    • Unity 環境閲覧者
  7. Create Key (キーの作成) を選択してキーを作成します。
  8. base64 エンコードを使用して Key ID (キー ID) と Secret Key (秘密鍵) をエンコードします。形式は "key_id:secret_key" です。この値をメモしておきます。

詳細については、Authentication を参照してください。

UGS CLI の設定

以下のステップに従って、UGS CLI の使用を準備します。

  1. UGS CLI をインストール します。

  2. プロジェクト ID と環境を以下のように設定します。
    ugs config set project-id <your-project-id>
    ugs config set environment-name <your-environment-name>

  3. 前に作成したサービスアカウントを使用して認証します。認証の取得 を参照してください。

Leaderboards と Economy の設定

上位プレイヤーにゲーム内通貨でゲーム内報酬を与えるスクリプトまたはモジュールエンドポイントを定義します。

Leaderboards の設定

このサンプルに従うには、リーダーボードを作成する必要があります。

UGS CLI を使用して、以下の leaderboard.lb ファイルをデプロイできます。リーダーボードを昇順のソート順で定義し、ベストスコアを保持します。

ファイル名はリーダーボード ID に対応します。

{
  "$schema": "https://ugs-config-schemas.unity3d.com/v1/leaderboards.schema.json",
  "SortOrder": "asc",
  "UpdateType": "keepBest",
  "Name": "leaderboard"
}

UGS CLI ツールを使用してファイルをデプロイします。

ugs deploy leaderboard.lb

リーダーボードを作成したので、そこにスコアを追加できます。

任意: リーダーボードへのスコアの追加

以下の Cloud Code スクリプトを実行して、Unity Dashboard からリーダーボードにスコアを追加できます。すべてのテスト実行でプレイヤー ID トークンを再生成して、新しいプレイヤーのスコアを生成してください。

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 });
  }
};

Economy の設定

このサンプルに従うには、上位プレイヤーにゲーム内報酬を与えることのできるゲーム内通貨を作成する必要があります。

  1. Unity Dashboard に移動します。
  2. 左のナビゲーションメニューで、LiveOps > Economy を選択します。
  3. Configuration (設定) セクションを選択します。
  4. Add Resource (リソースの追加) を選択します。
  5. キー名に coin を入力します。
  6. リソースタイプに Currency (通貨) を選択します。
  7. 初期および最大残高を設定します。
  8. Create (作成) を選択します。
  9. Publish (公開) を選択します。

これで、上位プレイヤーにゲーム内報酬を与えることのできるゲーム内通貨を作成できました。

reset イベントを調べる

リーダーボードがリセットされると、Leaderboards サービスにより reset が発行されます。イベントペイロードは以下のようになります。

{
  "leaderboardId": "string",
  "leaderboardVersionId": "string"
}

イベントペイロードは、パラメーターとして Cloud Code に渡されます。

詳細については、Leaderboards: リセット を参照してください。

Cloud Code の設定

Cloud Code モジュールまたはスクリプトを作成して、リーダーボードがリセットされたときにゲーム内通貨で上位プレイヤーに報酬を与えるためのロジックを定義する必要があります。

Cloud Code C# モジュール

Economy および Leaderboards Client SDK を使用して、Economy および Leaderboards サービスを操作できます。

文字列引数 leaderboardId を持つ関数を使用して LeaderboardsEconomySample モジュールを定義します。

C#

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 LeaderboardsEconomySample;

public class LeaderboardsEconomySample
{
    private const string CoinsKey = "COIN";
    private const int Amount = 10;

    private static ILogger<LeaderboardsEconomySample> _logger;

    public LeaderboardsEconomySample(ILogger<LeaderboardsEconomySample> logger)
    {
        _logger = logger;
    }

    [CloudCodeFunction("RewardTopPlayers")]
    public async Task RewardTopPlayers(IExecutionContext ctx, IGameApiClient gameApiClient, string leaderboardId)
    {
        var top5Players = await GetTop5(ctx, gameApiClient, leaderboardId);
        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;
            }
        }
    }


    [CloudCodeFunction("GetTopPlayers")]
    public async Task<List<LeaderboardEntry>> GetTop5(IExecutionContext ctx, IGameApiClient gameApiClient, string leaderboardId)
    {
        try
        {
            var results = await gameApiClient.Leaderboards.GetLeaderboardScoresAsync(ctx, ctx.ServiceToken, new Guid(ctx.ProjectId),
                leaderboardId, null, 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());
        }
    }
}

モジュールをデプロイします。

モジュールのデプロイ方法を学習するには、Hello World のデプロイ を参照してください。

ノート: UGS CLI を使用してモジュールをデプロイする場合は、Cloud Code Editor の追加のサービスアカウントロールを忘れずに追加してください。

Cloud Code JavaScript スクリプト

Cloud Code スクリプトを作成することで、同じ結果を実現できます。

以下のようなコンテンツで必須の文字列引数 amount を設定して、LeaderboardsEconomySample スクリプトを作成します。

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.getLeaderboardScores(context.projectId, params.leaderboardId, 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);
};

スクリプトを公開します。

スクリプトのデプロイ方法を学習するには、Hello World のデプロイ を参照してください。

ノート: UGS CLI を使用してスクリプトをデプロイする場合は、追加のサービスアカウントロール (Cloud Code Script PublisherCloud Code Editor) を忘れずに追加してください。

トリガーの設定

Cloud Code リソースをスケジュールに接続するには、トリガーを作成します。トリガーは、イベントが発生したとき、例えばリーダーボードがリセットされるたびに、Cloud Code スクリプトまたはモジュールを実行します。

Cloud Code スクリプトを作成した場合は、以下の設定で triggers-config.tr ファイルを作成します。

{
  "Configs": [
    {
      "Name": "reward-leaderboard",
      "EventType": "com.unity.services.leaderboards.reset.v1",
      "ActionUrn": "urn:ugs:cloud-code:LeaderboardsEconomySample",
      "ActionType": "cloud-code"
    }
  ]
}

Cloud Code モジュールを作成した場合は、以下の設定で triggers-config.tr ファイルを作成します。

{
  "Configs": [
    {
      "Name": "reward-leaderboard",
      "EventType": "com.unity.services.leaderboards.reset.v1",
      "ActionUrn": "urn:ugs:cloud-code:LeaderboardsEconomySample/RewardTopPlayers",
      "ActionType": "cloud-code"
    }
  ]
}

UGS CLI ツールを使用して設定をデプロイします。

ugs deploy triggers-config.tr

以下のようなレスポンスが表示されます。

Deployed:
    triggers-config.tr

これで、リーダーボードがリセットされたときに Cloud Code スクリプトまたはモジュールを実行するトリガーが設定されました。

結果の検証

結果を検証するには、リセットする前にリーダーボードからプレイヤー ID をメモしておきます。

  1. Unity Dashboard に移動します。
  2. LiveOps > Leaderboards を選択します。
  3. Overview (概要) セクションを選択します。
  4. leaderboard リーダーボードを選択します。
  5. Entries (エントリー) タブを選択します。
  6. 上位プレイヤー ID の 1 つを書き留めます。

リーダーボードをリセットします。Unity Dashboard のリーダーボードページで Reset Leaderboard (リーダーボードのリセット) ボタンを選択することにより、これを行うことができます。

プレイヤーが 10 コインの報酬を受け取ったことを確認するには、以下のステップに従います。

  1. 左のナビゲーションメニューで、LiveOps > Player Management を選択します。
  2. 検索フィールドで、前に書き留めておいたプレイヤー ID を入力し、Find player (プレイヤーを検索) を選択します。
  3. Economy > Currencies (通貨) セクションに移動します。
  4. プレイヤーが 10 コインの報酬を受け取ったことが表示されます。

ゲームロジックに準拠するようにリーダーボードのリセットを設定する方法については、リセット を参照してください。