Per-player state views in CloudBehaviours
Define a tailored, per-player subset of your CloudBehaviour's state, such as each player's own hand in a card game.
Read time 3 minutesLast updated 12 days ago
A CloudBehaviour holds the full state of your game, such as every player's hand in a card game. You usually don't want to send all of the state to every player. A method defines the tailored view that each player receives. Cloud Code builds each player's view and keeps it up to date automatically.
[SyncView]Define a per-player view
Mark a method . Cloud Code calls the method once per recipient, with that player's ID, and sends the return value as part of that player's state. The Unity Editor also generates a client property named with the method's return type.
[SyncView("name")]nameThe following example defines a per-player view of a card hand:
[StateScope(Scope.MultiplayerSession)]public class CardGame : CloudBehaviour{ // Store every hand. This field persists and stays in the cloud. [CloudCodeSerializeProperty] private Dictionary<string, List<Card>> _hands = new(); [SyncView("Hand")] internal List<Card> ProjectHand(string playerId) => _hands.TryGetValue(playerId, out var hand) ? hand : new List<Card>();}
The client bindings expose , which holds only that player's cards. The unfiltered dictionary never leaves the cloud.
public List<Card> Hand { get; private set; }Requirements
A method has the following requirements:
[SyncView]- The method takes a single parameter, the viewer's player ID, and returns the value that player receives. The method can't return
string. The return type becomes the type of the generated client property. For example,voidgeneratesList<Card> ProjectHand(string playerId)on the client.List<Card> Hand - The method is synchronous and non-generic.
- The method is or
public. A privateinternalmethod fails the build with[SyncView]. ACCSG142method never becomes an RPC, even when it's public.[SyncView]
The build doesn't check the following, but follow them so the view behaves as players expect:
- Name the view after what the method returns, not after the method. For example, use , not
[SyncView("Hand")]. The view name becomes the name of the property in the client bindings.[SyncView("ProjectHand")] - Don't change state in the method. The method runs once per recipient on every synchronization, so any state change repeats for every player.
Hide values from other players
Represent a hidden value as empty or absent, not as a stand-in value such as . Otherwise, a player can't tell a hidden value from a real one.
0The following example shows a sealed-bid auction, where each player receives only their own bid. A bid of is valid, so a in place of another player's bid looks like a real bid. Leave the other players' bids out instead:
00[StateScope(Scope.MultiplayerSession)]public class AuctionGame : CloudBehaviour{ // Store every sealed bid in the cloud only. [CloudCodeSerializeProperty] private Dictionary<string, int> _bids = new(); // Leave out other players' bids instead of setting them to 0. [SyncView("Bids")] internal Dictionary<string, int> ProjectBids(string playerId) => _bids.Where(bid => bid.Key == playerId) .ToDictionary(bid => bid.Key, bid => bid.Value);}
Send player-specific data to one player
A per-player view applies to synchronized state only. An event always pushes to everyone in the scope. To send player-specific data to one player, use instead of an event. Refer to Push channels in CloudBehaviours.
Push.SendPlayerMessageAsync