Documentation

Cloud Code

Per-player state views in CloudBehaviours

Define a tailored, per-player slice of your CloudBehaviour's state, such as a private hand in a card game.
Read time 3 minutesLast updated 16 days ago

Important
This page describes an experimental feature that might change significantly before release. It's not recommended to use or rely on experimental features in production environments due to potential instability.
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 it to every player. A
[SyncView]
method defines the tailored view each player is allowed to see, and Cloud Code builds and keeps each player's view in sync automatically.
Important
A
[SyncView]
controls which data each player receives. It doesn't restrict who can call your endpoints or change state. For access control, refer to Multiplayer game security in CloudBehaviours.

Define a per-player view

Mark a method
[SyncView("name")]
. The method is the state on the wire: Cloud Code calls it once per recipient, with that player's ID, and generates a read-only property named
name
with the method's return type:
[StateScope(Scope.MultiplayerSession)]public class CardGame : CloudBehaviour{ [CloudCodeSerializeProperty] private Dictionary<string, List<Card>> _hands = new(); // Every hand, persisted and cloud-only [SyncView("Hand")] internal List<Card> ProjectHand(string playerId) => _hands.TryGetValue(playerId, out var hand) ? hand : new List<Card>();}
The client sees
public List<Card> Hand { get; private set; }
, holding only that player's cards. The unfiltered dictionary never leaves the cloud.

Requirements

A
[SyncView]
method has the following requirements:
  • The method takes a single
    string
    parameter, the viewer's player ID, and returns the value that player sees. It can't return
    void
    . The return type becomes the type of the generated client property. For example,
    List<Card> ProjectHand(string playerId)
    generates
    List<Card> Hand
    on the client.
  • The method must be synchronous and non-generic.
  • The method must be
    public
    or
    internal
    . A private
    [SyncView]
    method fails the build with
    CCSG142
    . A
    [SyncView]
    method never becomes an RPC, even when it's public.
  • Name the view after what it returns, such as
    "Hand"
    , not after the method, such as
    "ProjectHand"
    .
  • Keep the method free of side effects. It runs once per recipient on every synchronization, so it must not alter state in any way.
  • Hide a value as empty or absent, not as a stand-in such as
    0
    . Otherwise a player can't tell a hidden value from a real one.
The following example shows a sealed-bid auction, where each player sees only their own bid. A bid of
0
is valid, so replacing the other players' bids with
0
would make them look like real bids. Leave them out instead:
[StateScope(Scope.MultiplayerSession)]public class AuctionGame : CloudBehaviour{ [CloudCodeSerializeProperty] private Dictionary<string, int> _bids = new(); // Every sealed bid, cloud-only [SyncView("Bids")] internal Dictionary<string, int> ProjectBids(string playerId) => _bids.Where(bid => bid.Key == playerId) // Other players' bids are absent, not 0 .ToDictionary(bid => bid.Key, bid => bid.Value);}

Send to specific players

A per-player view applies to synchronized state only. An event always pushes to everyone in the scope. To send private data to one player, use
Push.SendPlayerMessageAsync
instead of an event. Refer to Push channels in CloudBehaviours.

Additional resources