Interact with cross-player data

You can use Cloud Code scripts to access and modify data for multiple players at once.

This unlocks a variety of use cases, such as to:

  • Update the player data in Cloud Save for multiple players at once.
  • Update Economy balances for multiple players at once.

Note: To reduce risk of abuse, ensure that only specific users can call scripts that interact with cross-player data instead of all players. To restrict access to particular scripts, you can use Access Control.

Retrieve player IDs

To interact with multiple players, you need call to UGS services to retrieve the player IDs first.

To get the player IDs, you can use the Cloud Code JavaScripts SDKs. Refer to Cloud Code JavaScript SDKs for more information.

You can also use a service's REST API directly. Services that you can use to get player IDs include Leaderboards, Lobby, and Friends.

Use Leaderboards

First, you need to create a Leaderboard.

For example, you can retrieve the top five players from a leaderboard and save their IDs. The script below takes in a leaderboard ID and returns a list of top five players' scores:

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@2.5/manual/Authoring/javascript_project.html)
//
// module.exports.params = {
//   leaderboardId: { type: "String", required: true },
// };

The response looks similar to below:

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

Use Lobby

First, you need to create a Lobby.

You can retrieve a list of players that are currently in the Lobby, and use their IDs to interact with their data.

The script takes in a Lobby ID as a parameter:

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@2.5/manual/Authoring/javascript_project.html)
//
// module.exports.params = {
//   lobbyId: { type: "String", required: true },
// };

The response looks similar to below:

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

Use Friends

To use Friends, you need to create a relationship. For more information, see the Friends documentation.

You can then retrieve a list of friends for a player, and use their IDs to interact with their data. The sample below shows how you can retrieve a list of player IDs that a player has sent friend requests to:

Optional - Send a friend request

You can use the helper script to send a friend request to a player. The script takes in a player ID as a parameter.

To test this sample in the Unity Cloud Dashboard, run the script in two different browser tabs authenticated as two different players. In one tab, run a script with the first player's ID, and run a script with the second player's ID in another tab.

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@2.5/manual/Authoring/javascript_project.html)
//
// module.exports.params = {
//   playerId: { type: "String", required: true },
// };

Retrieve a list of friends

The script below retrieves a list of player IDs that a player has sent friend requests to:

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

The response looks similar to below:

{
    "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

Once you have a list of player IDs, you can use them to update player data through UGS services.

The samples below show how to use the Cloud Save and Economy services to interact with player data.

Authenticate as Cloud Code

To interact with cross-player data, you need to authenticate as Cloud Code. This can be done by using the serviceToken instead of the accessToken when creating the client:

const cloudSaveApi = new DataApi(context);

Note: Passing in the context object to the client will authenticate the client using the serviceToken by default.

Check Service and access token support for a list of services that support the ServiceToken.

Update top 5 player data using Cloud Save

One way to interact with player data is to pass in a list of player IDs to Cloud Save.

The script in the sample takes a leaderboard ID as a parameter.

The sample below shows how you can set a value in Cloud Save for top five players retrieved from a leaderboard. To ensure the sample works, follow the steps below:

  1. Create a leaderboard using the Leaderboards service.
  2. Have some player scores on the leaderboard.

Create a new script and add the following code:

JavaScript

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


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@2.5/manual/Authoring/javascript_project.html)
//
// module.exports.params = {
//   leaderboardId: { type: "String", required: true },
// };

The script sets a key-value pair for all players in the leaderboard. To verify this, you can navigate to the Player Management service in the Unity Cloud Dashboard and inspect the Cloud Save data for the top players.

Reward all players in the Lobby using Economy

To interact with player balances, you can pass in a list of player IDs to the Economy API.

The sample below shows how to increment the balance of a currency for a list of players retrieved from a lobby. The module function takes in a lobby ID, currency ID, and an amount to increment the balance by as parameters.

To ensure the sample works, follow the steps below:

  1. Create a lobby using the Lobby service.
  2. Have a player in the lobby.
  3. Create and publish a currency in the Economy service.

Create a new script and add the following code:

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@2.5/manual/Authoring/javascript_project.html)
//
// module.exports.params = {
//   lobbyId: { type: "String", required: true },
//   currencyId: { type: "String", required: true },
//   amount: { type: "Numeric", required: true },
// };

The script increments the balance of the currency for all players in the lobby.

To verify, you can navigate to the Player Management service in the Unity Cloud Dashboard and inspect the balances for your players.