# クロスプレイヤーデータの操作

> Access and modify data for multiple players simultaneously with Cloud Code scripts.

Cloud Code スクリプトを使用して、一度に複数のプレイヤーのデータにアクセスして変更できます。

これにより、以下のようなさまざまなユースケースが解放されます。

* Cloud Save で一度に複数のプレイヤーのプレイヤーデータを更新します。
* 一度に複数のプレイヤーの Economy 残高を更新します。

> **Note:**
>
> **ノート:** 乱用のリスクを軽減するために、すべてのプレイヤーではなく特定のユーザーだけが、クロスプレイヤーデータを操作するスクリプトを呼び出せることを確認します。特定のスクリプトへのアクセスを制限するには、[アクセス制御](./access-control.md) を使用できます。

## プレイヤー ID の取得##retrieve-player-ids

複数のプレイヤーを操作するには、最初に UGS サービスを呼び出してプレイヤー ID を取得する必要があります。

プレイヤー ID を取得するには、Cloud Code JavaScripts SDK を使用できます。詳細については、[Cloud Code JavaScript SDK](https://cloud-code-sdk-documentation.cloud.unity3d.com/) を参照してください。

サービスの REST API ディレクトリを使用することもできます。プレイヤー ID を取得するために使用できるサービスには、[Leaderboards](/leaderboards.md)、[Lobby](/lobby.md)、[Friends](/friends.md) が含まれます。

### Leaderboards の使用##use-leaderboards

最初に、[リーダーボードを作成](/leaderboards/get-started.md) する必要があります。

例えば、リーダーボードから上位 5 人のプレイヤーを取得し、その ID を保存できます。以下のスクリプトは、リーダーボード ID を取り込み、上位 5 人のプレイヤーのスコアのリストを返します。

#### JavaScript##javascript

```javascript
const { LeaderboardsApi } = require("@unity-services/leaderboards-1.1");

module.exports = async ({ params, context, logger }) => {
  const leaderboardsApi = new LeaderboardsApi(context);
  let result;

  try {
    result = await leaderboardsApi.getLeaderboardScores(context.projectId, params.leaderboardId, 0, 5);
    return result.data.results;
  } catch (err) {
    logger.error("Failed to retrieve players from the leaderboard", {"error.message": err.message}, {"leaderboardId" : params.leaderboardId});
    throw err;
  }
};

// Uncomment the code below to enable the inline parameter definition
// - Requires Cloud Code JS dev environment setup with NodeJS (https://docs.unity3d.com/Packages/com.unity.services.cloudcode@latest/index.html?subfolder=/manual/Authoring/javascript_project.html)
//
// module.exports.params = {
//   leaderboardId: { type: "String", required: true },
// };
```

レスポンスは以下のようになります。

```json
{
    "output": [
        {
            "playerId": "wYI5NW5gEVvR3PBmYXEzFS1JvSz3",
            "playerName": "IncredibleGleamingPelican#3",
            "rank": 0,
            "score": 44.0
        },
        {
            "playerId": "ryuAA3ZX23aRHN5ZJClC1Z5BrpVb",
            "playerName": "EffectiveBindingBlackberry#9",
            "rank": 1,
            "score": 1.0
        }
    ]
}
```

### Lobby の使用##use-lobby

最初に、[ロビーを作成](/lobby/get-started.md) する必要があります。

現在ロビー内にいるプレイヤーのリストを取得し、その ID を使用してデータを操作できます。

スクリプトはロビー ID をパラメーターとして受け取ります。

#### JavaScript##javascript

```javascript
const { LobbyApi } = require("@unity-services/lobby-1.2");

module.exports = async ({ params, context, logger }) => {
  const lobbyApi = new LobbyApi(context);

  try {
    // Get and return the lobby.
    const getResponse = await lobbyApi.getLobby(params.lobbyId, "cloud-code");
    return getResponse.data.players;

  } catch (err) {
    logger.error("Failed to retrieve players from the Lobby", {"error.message": err.message}, {"lobbyId" : params.lobbyId});
    throw err;
  }
};

// Uncomment the code below to enable the inline parameter definition
// - Requires Cloud Code JS dev environment setup with NodeJS (https://docs.unity3d.com/Packages/com.unity.services.cloudcode@latest/index.html?subfolder=/manual/Authoring/javascript_project.html)
//
// module.exports.params = {
//   lobbyId: { type: "String", required: true },
// };
```

レスポンスは以下のようになります。

```json
{
    "output": [
        {
            "allocationId": null,
            "connectionInfo": null,
            "data": null,
            "id": "Z96pNb4wfgdaMLqMQfWpwXEclaRR",
            "joined": "2023-09-08T11:02:18.13Z",
            "lastUpdated": "2023-09-08T11:02:18.13Z"
        }
    ]
}
```

### Friends の使用##use-friends

Friends を使用するには、関係を作成する必要があります。詳細については、[Friends のドキュメント](/friends.md) を参照してください。

プレイヤーの友達のリストを取得し、その ID を使用してデータを操作できます。以下のサンプルは、プレイヤーが友達リクエストを送信したプレイヤー ID のリストを取得する方法を示します。

#### 任意 - 友達リクエストの送信##optional---send-a-friend-request

ヘルパースクリプトを使用して、プレイヤーに友達リクエストを送信できます。スクリプトはプレイヤー ID をパラメーターとして受け取ります。

[Unity Dashboard](https://cloud.unity3d.com/) でこのサンプルをテストするには、2 つの異なるプレイヤーとして認証された 2 つの異なるブラウザータブでスクリプトを実行します。1 つのタブでは最初のプレイヤーの ID でスクリプトを実行し、別のタブでは 2 番目のプレイヤーの ID でスクリプトを実行します。

##### JavaScript##javascript

```javascript
const { RelationshipsApi } = require("@unity-services/friends-1.0");


module.exports = async ({ params, context, logger }) => {
  const relationshipsApi = new RelationshipsApi({ accessToken: context.accessToken });

  try {
    const payload = {
      type: "FRIEND_REQUEST",
      members: [{ id: params.playerId }]
    };

    const createRes = await relationshipsApi.createRelationship(true, true, payload);
    logger.info(`New relationship initiated: ${JSON.stringify(createRes.data)}`)
  } catch (err) {
    // The call will fail if the friend request has already been sent
    logger.error("Error while sending a friend request", { "error.message": err.message });
  }

  try {
    const list = await relationshipsApi.getRelationships(10, 0, true, true, ["FRIEND_REQUEST", "FRIEND"]);
    logger.info(`Retrieved relationships: ${JSON.stringify(list.data)}`)
  } catch (err) {
    logger.error("Error while retrieving relationships", { "error.message": err.message });
  }
}

// Uncomment the code below to enable the inline parameter definition
// - Requires Cloud Code JS dev environment setup with NodeJS (https://docs.unity3d.com/Packages/com.unity.services.cloudcode@latest/index.html?subfolder=/manual/Authoring/javascript_project.html)
//
// module.exports.params = {
//   playerId: { type: "String", required: true },
// };
```

#### 友達のリストの取得##retrieve-a-list-of-friends

以下のスクリプトは、プレイヤーが友達リクエストを送信したプレイヤー ID のリストを取得します。

##### JavaScript##javascript

```javascript
const { RelationshipsApi } = require("@unity-services/friends-1.0");

module.exports = async ({ params, context, logger }) => {
  const relationshipsApi = new RelationshipsApi({ accessToken: context.accessToken });

  try {
    const list = await relationshipsApi.getRelationships(10, 0, true, true, ["FRIEND_REQUEST", "FRIEND"]);
    logger.info(`Retrieved relationships: ${JSON.stringify(list.data)}`)
    return list.data[0].members;
  } catch (err) {
    logger.error("Error while retrieving relationships", { "error.message": err.message });
  }
}
```

レスポンスは以下のようになります。

```json
{
    "output": [
        {
            "created": "2023-09-18T14:46:34.74Z",
            "expires": null,
            "id": "5774e898-a078-4f92-9f0a-4c9beeb6d1bb",
            "members": [
                {
                    "id": "0gvQingjjBwpZhkUJfeoKnFUkD4T"
                }
            ],
            "type": "FRIEND_REQUEST"
        }
    ]
}
```

## プレイヤーデータの操作##interact-with-player-data

プレイヤー ID のリストを入手したら、それらを使用して、UGS サービスを通じてプレイヤーデータを更新できます。

以下のサンプルは、[Cloud Save](/cloud-save.md) と [Economy](/economy.md) サービスを使用してプレイヤーデータを操作する方法を示します。

### Cloud Code としての認証##authenticate-as-cloud-code

クロスプレイヤーデータを操作するには、Cloud Code として認証する必要があります。これは、クライアントの作成時に `accessToken` のかわりに `serviceToken` を使用して行うことができます。

```csharp
const cloudSaveApi = new DataApi(context);
```

> **Note:**
>
> **ノート:** `context` オブジェクトをクライアントに渡すと、デフォルトで `serviceToken` を使用してクライアントが認証されます。

`ServiceToken` をサポートするサービスのリストについては [サービスとアクセストークンのサポート](./token-support.md) の説明を確認してください。

### Cloud Save を使用した上位 5 人のプレイヤーデータの更新##update-top-5-player-data-using-cloud-save

プレイヤーデータを操作する 1 つの方法は、プレイヤー ID のリストを Cloud Save に渡すことです。

サンプル内のスクリプトは、リーダーボード ID をパラメーターとして受け取ります。

以下のサンプルは、リーダーボードから取得した上位 5 人のプレイヤーについて、Cloud Save で値を設定する方法を示します。サンプルが動作するためには、以下のステップに従います。

1. [Leaderboards サービス](/leaderboards/get-started.md) を使用してリーダーボードを作成します。
2. リーダーボードに一部のプレイヤースコアを載せます。

新しいスクリプトを作成し、以下のコードを追加します。

#### JavaScript##javascript

```javascript
const { LeaderboardsApi } = require("@unity-services/leaderboards-1.1");
const { DataApi } = require("@unity-services/cloud-save-1.4");


module.exports = async ({ params, context, logger }) => {
  const leaderboardsApi = new LeaderboardsApi(context);
  const cloudSaveApi = new DataApi(context);

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

  if (result.len != 0) {
    // Set Cloud Save data for every player
    const promises = result.data.results.map(async (score) => {
      try {

        await cloudSaveApi.setItem(context.projectId, score.playerId, {
          key: "ReachedTop5",
          value: true,
        });

      } catch (err) {
        logger.error("Failed to update Cloud Save data", {"error.message": err.message}, {"affectedPlayerId" : score.playerId});
        return;
      }
    });

    await Promise.all(promises);
  }
};

// Uncomment the code below to enable the inline parameter definition
// - Requires Cloud Code JS dev environment setup with NodeJS (https://docs.unity3d.com/Packages/com.unity.services.cloudcode@latest/index.html?subfolder=/manual/Authoring/javascript_project.html)
//
// module.exports.params = {
//   leaderboardId: { type: "String", required: true },
// };
```

スクリプトは、リーダーボード内のすべてのプレイヤーのキーと値のペアを設定します。これを検証するために、Unity Dashboard で **Player Management** サービスに移動し、上位プレイヤーの Cloud Save データを調べることができます。

### Economy を使用してロビー内のすべてのプレイヤーに報酬を与える##reward-all-players-in-the-lobby-using-economy

プレイヤーの残高を操作するには、プレイヤー ID のリストを Economy API に渡します。

以下のサンプルは、ロビーから取得したプレイヤーのリストについて、通貨の残高を増やす方法を示します。モジュール関数は、ロビー ID、通貨 ID、および残高を増やす金額をパラメーターとして受け取ります。

サンプルが動作するためには、以下のステップに従います。

1. [Lobby サービス](/lobby/create-a-lobby.md) を使用してロビーを作成します。
2. ロビーにプレイヤーを配置します。
3. Economy サービスで通貨を [作成](/economy/add-currency.md) および [公開](/economy/publication.md) します。

新しいスクリプトを作成し、以下のコードを追加します。

#### JavaScript##javascript

```javascript
const { LobbyApi } = require("@unity-services/lobby-1.2");
const { CurrenciesApi, ConfigurationApi } = require("@unity-services/economy-2.4");

module.exports = async ({ params, context, logger }) => {
  const lobbyApi = new LobbyApi(context);

  let result;
  try {
    // Get and return the lobby.
    result = await lobbyApi.getLobby(params.lobbyId, "cloud-code");

  } catch (err) {
    logger.error("Failed to retrieve players from the Lobby", {"error.message": err.message}, {"lobbyId" : params.lobbyId});
    throw err;
  }

  const currenciesApi = new CurrenciesApi(context);
  const configApi = new ConfigurationApi(context);

  if (result.len != 0) {
    // Reward currency to every player
    const promises = result.data.players.map(async (player) => {
      try {
        // Retrieve the player config to get the configAssignmentHash.
        // This is needed to ensure the currency is synced
        var config = await configApi.getPlayerConfiguration({
          playerId: player.id,
          projectId: context.projectId,
        });


        await currenciesApi.incrementPlayerCurrencyBalance({
          currencyId: params.currencyId,
          playerId: player.id,
          projectId: context.projectId,
          configAssignmentHash: config.data.metadata.configAssignmentHash,
          currencyModifyBalanceRequest: { amount: params.amount }
        });

      } catch (err) {
        logger.error("Failed to increment currency", {"error.message": err.message}, {"currencyId" : params.currencyId});
        throw err;
      }
    });

    await Promise.all(promises);
  }
};

// Uncomment the code below to enable the inline parameter definition
// - Requires Cloud Code JS dev environment setup with NodeJS (https://docs.unity3d.com/Packages/com.unity.services.cloudcode@latest/index.html?subfolder=/manual/Authoring/javascript_project.html)
//
// module.exports.params = {
//   lobbyId: { type: "String", required: true },
//   currencyId: { type: "String", required: true },
//   amount: { type: "Numeric", required: true },
// };
```

スクリプトは、ロビー内のすべてのプレイヤーの通貨の残高を増やします。

検証するために、[Unity Dashboard](https://cloud.unity.com) で **Player Management** サービスに移動し、プレイヤーの残高を調べることができます。
