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

> Reward your top players with in-game currency at the end of a season using Triggers.

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

## 前提条件##prerequisites

最初に、必要なアクセスロールでサービスアカウントを作成し、[UGS CLI](https://services.docs.unity.com/guides/ugs-cli/latest/general/get-started/install-the-cli/) を設定する必要があります。

### サービスアカウントを使用した認証##authenticate-using-a-service-account

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

1. [Unity Dashboard](https://cloud.unity.com) に移動します。
2. **Administration** (管理) > **Service Accounts** (サービスアカウント) を選択します。
3. **New** (新規) ボタンを選択し、サービスアカウントの名前と説明を入力します。
4. **Create** (作成) を選択します。

製品ロールを追加し、キーを作成します。

1. **Manage product roles** (製品ロールの管理) を選択します。
2. 以下のロールをサービスアカウントに追加します。
   * LiveOps ドロップダウンから、以下のロールを選択します。
     * **Triggers 設定編集者**
     * **Triggers 設定閲覧者**
     * **Economy Resource Editor** (Economy リソース編集者)
     * **Economy Resource Viewer** (Economy リソース閲覧者)
     * **Leaderboards Admin** (Leaderboards 管理者)
     * **Leaderboards Viewer** (Leaderboards 閲覧者)
     * Cloud Code モジュールをデプロイしている場合は、以下のロールを追加します。
       * **Cloud Code 編集者**
       * **Cloud Code 閲覧者**
     * Cloud Code スクリプトをデプロイしている場合は、以下のロールを追加します。
       * **Cloud Code 編集者**
       * **Cloud Code 閲覧者**
       * **Cloud Code パブリッシャー**
   * Admin (管理者) ドロップダウンから **Unity Environments Viewer** (Unity 環境閲覧者) を選択します。
3. **Save** (保存) を選択します。
4. **Add Key** (キーの追加) を選択します。
5. base64 エンコードを使用して **Key ID** (キー ID) と **Secret key** (秘密鍵) をエンコードします。形式は "key\_id:secret\_key" です。この値をメモしておきます。

詳細については、[Authentication](../../authentication) を参照してください。

### UGS CLI の設定##configure-the-ugs-cli

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

1. [UGS CLI をインストール](https://services.docs.unity.com/guides/ugs-cli/latest/general/get-started/install-the-cli/) します。

2. 以下を使用して、プロジェクト ID と環境を設定します。
   `ugs config set project-id <your-project-id>`
   `ugs config set environment-name <your-environment-name>`

3. 以前に認証したサービスアカウントを使用して認証します。[認証の取得](https://services.docs.unity.com/guides/ugs-cli/latest/general/get-started/get-authenticated/) を参照してください。

## `reset` イベントを調べる##examine-the-reset-event

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

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

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

詳細については、Leaderboards の [リセット イベント](/triggers/manage-events/supported-ugs-events.md#reset) を参照してください。

## デプロイファイルの作成##create-deployment-files

このサンプルは、各サービスの設定ファイルを UGS CLI を使用してデプロイすることで実装されます。

ユースケースサンプルを実装するには、以下のファイルを設定する必要があります。

* `COIN.ecc`: Economy の通貨設定が含まれます。
* `leaderboard.lb`: Leaderboards の設定が含まれます。
* `triggers-config.tr`: Triggers の設定が含まれます。
* リーダーボードがリセットされたときにゲーム内通貨で上位プレイヤーに報酬を与えるためのロジックを定義する、Cloud Code モジュールまたはスクリプト。

すべてのファイルを格納するために `reward-top-players` というフォルダーを作成します。すべて一度にデプロイできます。

### Economy の設定##set-up-economy

上位プレイヤーにゲーム内通貨で報酬を与えるには、Economy でゲーム内通貨を作成する必要があります。

UGS CLI を使用して Economy の設定ファイルを作成します。

```bash
ugs economy currency new-file COIN.ecc
```

以下の内容を `COIN.ecc` ファイルに追加します。

```json
{
  "$schema": "https://ugs-config-schemas.unity3d.com/v1/economy/economy-currency.schema.json",
  "initial": 0,
  "name": "Coin"
}
```

この設定では、ゲーム内通貨が定義され、`Coin` と名付けられます。ファイル名は通貨 ID に対応します。

### Leaderboards の設定##set-up-leaderboards

UGS CLI を使用して Leaderboard の設定ファイルを作成します。

```bash
ugs leaderboards new-file leaderboard.lb
```

以下の内容を `leaderboard.lb` ファイルに追加します。

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

この設定では、昇順のリーダーボードが定義され、ベストスコアが保持されます。ファイル名はリーダーボード ID に対応します。

### Cloud Code の設定##set-up-cloud-code

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

#### Cloud Code C# モジュール##cloud-code-c-module

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

UGS CLI を使用して新しい Cloud Code モジュールを作成します。

```bash
ugs cc m new-file RewardTopPlayers RewardTopPlayers
```

次に、以下の内容をサンプルソリューションに追加します。文字列引数 `leaderboardId` を指定してモジュール関数を作成します。

```csharp
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 スクリプト##cloud-code-javascript-script

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

UGS CLI を使用して新しい Cloud Code スクリプトを作成します。

```bash
ugs cc s new-file RewardTopPlayers.js
```

次に、以下の内容をサンプルスクリプトファイルに追加します。

##### JavaScript##javascript

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

### Triggers の設定##set-up-triggers

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

```bash
ugs tr new-file triggers-config.tr
```

Cloud Code モジュールを作成した場合は、以下の設定を使用します。

```json
{
  "$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"
    }
  ]
}
```

Cloud Code スクリプトを作成した場合は、以下の設定を使用します。

```json
{
  "$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

`reward-top-players` フォルダーに以下のファイルがあるはずです。

* `COIN.ecc` - Economy の通貨設定が含まれます。
* `leaderboard.lb` - Leaderboards の設定が含まれます。
* `triggers-config.tr` - Triggers の設定が含まれます。

さらに、以下の 1 つ:

* `RewardTopPlayers.sln` フォルダー - Cloud Code モジュールが含まれます。
* `RewardTopPlayers.js` - Cloud Code スクリプトが含まれます。

UGS CLI を使用してすべて一度にデプロイできます。

```bash
ugs deploy .
```

## 任意: リーダーボードへのスコアの追加##optional:-add-scores-to-the-leaderboard

以下の Cloud Code スクリプトを実行して、[Unity Dashboard](https://dashboard.unity3d.com/) からリーダーボードにスコアを追加できます。すべてのテスト実行でプレイヤー ID トークンを再生成して、新しいプレイヤーを追加します。


**Frame:**
![](/api/media?file=/cloud-code/media/images/cloud-code-generate-button.png)

### JavaScript##javascript

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

これを使用して、スコアをリーダーボードに追加し、ユースケースサンプルをテストすることができます。

## 結果の検証##validate-the-result

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

1. [Unity Dashboard](https://cloud.unity.com) に移動します。
2. **Products** (製品) > **Leaderboards** を選択します。
3. **Overview** (概要) セクションを選択します。
4. `leaderboard` リーダーボードを選択します。
5. **Entries** (エントリー) タブを選択します。
6. 上位プレイヤー ID の 1 つを書き留めます。

その後、リーダーボードをリセットします。

1. [Unity Dashboard](https://cloud.unity.com) に移動します。
2. **Products** (製品) > **Leaderboards** を選択します。
3. **Overview** (概要) セクションを選択します。
4. `leaderboard` リーダーボードを選択します。
5. **Reset Leaderboard** (リーダーボードのリセット) を選択します。
6. **Archive current scores** (現在のスコアのアーカイブ) を有効にします。

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

1. **Products** (製品) > **Player Management** (プレイヤー管理) を選択します。
2. 検索フィールドで、前に書き留めておいたプレイヤー ID を入力し、**Find player** (プレイヤーを検索) を選択します。
3. **Economy** > **Currencies** (通貨) セクションに移動します。成功した場合、プレイヤーが 10 コインの報酬を受け取ったことが表示されます。

ゲームロジックに準拠するようにリーダーボードのリセットを設定する方法については、[リセット](/leaderboards/concepts/resets.md) を参照してください。
