Interact with cross-player data
Access and modify data for multiple players at once with Cloud Code modules.
Read time 6 minutesLast updated 18 hours ago
You can use Cloud Code modules 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.
- Send a push notification to multiple players at once.
- Update Economy balances for multiple players at once.
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 C# SDKs in theCom.Unity.Services.CloudCode.ApisUse 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 module below takes in a leaderboard ID and returns a list of top five players' scores:Call theusing 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.Leaderboards.Model;namespace CrossPlayerData;public class CrossPlayerData{ private readonly ILogger<CrossPlayerData> _logger; public CrossPlayerData(ILogger<CrossPlayerData> logger) { _logger = logger; } [CloudCodeFunction("GetTopPlayers")] public async Task<List<LeaderboardEntry>> GetTopPlayers(IExecutionContext ctx, IGameApiClient gameApiClient, string leaderboardId) { ApiResponse<LeaderboardScoresPage> response; try { response = await gameApiClient.Leaderboards.GetLeaderboardScoresAsync(ctx, ctx.ServiceToken, new Guid(ctx.ProjectId), leaderboardId, null, 5); return response.Data.Results; } catch (ApiException e) { _logger.LogError("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()); } }}
GetTopPlayers{ "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:Call theusing 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.Lobby.Model;namespace CrossPlayerData;public class CrossPlayerData{ private readonly ILogger<CrossPlayerData> _logger; public CrossPlayerData(ILogger<CrossPlayerData> logger) { _logger = logger; } [CloudCodeFunction("GetLobbyPlayers")] public async Task<List<Player>> GetLobby(IExecutionContext ctx, IGameApiClient gameApiClient, string lobbyId) { ApiResponse<Lobby> response; try { response = await gameApiClient.Lobby.GetLobbyAsync(ctx, ctx.ServiceToken, lobbyId, "cloud-code"); return response.Data.Players; } catch (ApiException e) { _logger.LogError("Failed to get players from lobby: {LobbyId}. Error: {Error}", lobbyId, e.Message); throw new Exception ($"Failed to get players from lobby: {lobbyId}. Error: {e.Message}"); } } public class ModuleConfig : ICloudCodeSetup { public void Setup(ICloudCodeConfig config) { config.Dependencies.AddSingleton(GameApiClient.Create()); } }}
GetLobbyPlayers{ "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:
Call theusing Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Logging;using Unity.Services.CloudCode.Apis;using Unity.Services.CloudCode.Core;using Unity.Services.Friends.Model;namespace CrossPlayerData;public class CrossPlayerData{ private readonly ILogger<CrossPlayerData> _logger; public CrossPlayerData(IExecutionContext ctx, ILogger<CrossPlayerData> logger) { _logger = logger; } [CloudCodeFunction("SendFriendRequest")] public async Task SendFriendRequest(IExecutionContext ctx, IGameApiClient gameApiClient, string playerId) { try { await gameApiClient.FriendsRelationshipsApi.CreateRelationshipAsync( ctx, ctx.AccessToken, false, false, new AddRelationshipRequest(RelationshipType.FRIENDREQUEST, new List<MemberIdentity> { new(id : playerId) })); } catch (Exception e) { _logger.LogError("Failed to send a friend request to playerId: {playerId}. Error: {Error}", playerId, e.Message); throw new Exception("Failed to send a friend request to playerId: " + playerId + ". Error: " + e.Message); } } [CloudCodeFunction("GetRelationships")] public async Task<List<Relationship>> GetRelationships(IExecutionContext ctx, IGameApiClient gameApiClient) { try { var res = await gameApiClient.FriendsRelationshipsApi.GetRelationshipsAsync(ctx, ctx.AccessToken, 10, 0, false, false); return res.Data; } catch (Exception e) { _logger.LogError("Failed to get relationships for playerId: {playerId}. Error: {Error}", ctx.PlayerId, e.Message); throw new Exception("Failed to get relationships for playerId: " + ctx.PlayerId + ". Error: " + e.Message); } } public class ModuleConfig : ICloudCodeSetup { public void Setup(ICloudCodeConfig config) { config.Dependencies.AddSingleton(GameApiClient.Create()); } }}
GetRelationships{ "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. To authenticate as Cloud Code, use theServiceTokenAccessTokenRefer to Authentication for more information and check Service and access token support for a list of services that support theawait gameApiClient.CloudSaveData.SetItemAsync(ctx, ctx.ServiceToken, ctx.ProjectId, player.PlayerId, new SetItemBody("ReachedTop5", true));
ServiceTokenUpdate 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 module function in the sample takes a leaderboard ID as a parameter. The sample below shows how to record a value for reaching top 5 in Cloud Save for a list of top 5 players retrieved from a leaderboard. To ensure the sample works, follow the steps below:- Create a leaderboard using the Leaderboards service.
- Have some player scores on the leaderboard.
Theusing 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.CloudSave.Model;using Unity.Services.Leaderboards.Model;namespace CrossPlayerData;public class CrossPlayerData{ private readonly ILogger<CrossPlayerData> _logger; public CrossPlayerData(ILogger<CrossPlayerData> logger) { _logger = logger; } [CloudCodeFunction("GetTopPlayers")] public async Task<List<LeaderboardEntry>> GetTopPlayers(IExecutionContext ctx, IGameApiClient gameApiClient, string leaderboardId) { ApiResponse<LeaderboardScoresPage> response; try { response = await gameApiClient.Leaderboards.GetLeaderboardScoresAsync(ctx, ctx.ServiceToken, new Guid(ctx.ProjectId), leaderboardId, null, 5); return response.Data.Results; } catch (ApiException e) { _logger.LogError("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}"); } } [CloudCodeFunction("UpdateTopPlayerData")] public async Task UpdateTopPlayerData(IExecutionContext ctx, IGameApiClient gameApiClient, string leaderboardId) { var players = GetTopPlayers(ctx, gameApiClient, leaderboardId); foreach (var player in players.Result) { try { await gameApiClient.CloudSaveData.SetItemAsync(ctx, ctx.ServiceToken, ctx.ProjectId, player.PlayerId, new SetItemBody("ReachedTop5", true)); _logger.LogInformation("Updated data for playerId {playerId}", player.PlayerId); } catch (Exception e) { _logger.LogError("Failed to update data for playerId {playerId}. Error: {Error}", player.PlayerId, e.Message); throw new Exception ($"Failed to update data for playerId: {player.PlayerId}. Error: {e.Message}"); } } } public class ModuleConfig : ICloudCodeSetup { public void Setup(ICloudCodeConfig config) { config.Dependencies.AddSingleton(GameApiClient.Create()); } }}
UpdateTopPlayerDataReward 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:- Create a lobby using the Lobby service.
- Have a player in the lobby.
- Create and publish a currency in the Economy service.
Theusing 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.Lobby.Model;public class CrossPlayerData{ private readonly ILogger<CrossPlayerData> _logger; public CrossPlayerData(ILogger<CrossPlayerData> logger) { _logger = logger; } [CloudCodeFunction("GetLobbyPlayers")] public async Task<List<Player>> GetLobby(IExecutionContext ctx, IGameApiClient gameApiClient, string lobbyId) { ApiResponse<Lobby> response; try { response = await gameApiClient.Lobby.GetLobbyAsync(ctx, ctx.ServiceToken, lobbyId, "cloud-code"); return response.Data.Players; } catch (Exception e) { _logger.LogError("Failed to get players from lobby: {LobbyId}. Error: {Error}", lobbyId, e.Message); throw new Exception ($"Failed to get players from lobby: {lobbyId}. Error: {e.Message}"); } } [CloudCodeFunction("RewardLobbyPlayers")] public async Task RewardLobbyPlayers(IExecutionContext ctx, IGameApiClient gameApiClient, string lobbyId, string currencyId, int amount) { var players = GetLobby(ctx, gameApiClient, lobbyId); foreach (var player in players.Result) { try { await gameApiClient.EconomyCurrencies.IncrementPlayerCurrencyBalanceAsync(ctx, ctx.ServiceToken, ctx.ProjectId, player.Id, currencyId, new CurrencyModifyBalanceRequest(currencyId, amount)); _logger.LogInformation("Incremented balance for playerId {playerId} by {amount}", player.Id, amount); } catch (Exception e) { _logger.LogError("Failed to increment {currencyId} balance for playerId {playerId}. Error: {Error}", currencyId, player.Id, e.Message); throw new Exception($"Failed to increment {currencyId} balance for playerId {player.Id}. Error: {e.Message}"); } } } public class ModuleConfig : ICloudCodeSetup { public void Setup(ICloudCodeConfig config) { config.Dependencies.AddSingleton(GameApiClient.Create()); } }}
RewardLobbyPlayers