Documentation

Cloud Code

RPCs in CloudBehaviours

Declare an RPC, call it from your game, and inject Cloud Code services into it.
Read time 4 minutesLast updated 14 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.
You write the procedure: a public method on your CloudBehaviour that runs in the cloud. Cloud Code generates the remote procedure call (RPC) for you: a matching method in the client bindings that your game calls to run it. Because the method body never runs on a player's device, it's the place to put validation, secret logic, and anything that awards or spends resources.
Note
Every public method in the cloud script is a network endpoint that any client can call, including a malicious one. For guidance on locking an RPC down, refer to Multiplayer game security in CloudBehaviours.

Write a method your game can call

Cloud Code generates an RPC for each public, non-static, non-generic method on the cloud class, except methods marked
[SyncView]
, which define per-player state views instead. The method can be synchronous or asynchronous (returning
Task
or
Task<T>
), and it can take parameters and return a value:
[StateScope(Scope.MultiplayerSession)]public class MatchState : CloudBehaviour{ public void EndTurn() { /* ... */ } public int SubmitScore(int score) { /* ... */ return score; } public async Task<string> PlayTurn(string move) { /* ... */ return "ok"; } // Private methods stay in the cloud private void ResetRound() { /* ... */ }}
Parameters and return values serialize as JSON, so use serializable types, such as primitives, strings, and plain C# classes. Parameters marked
[CloudCodeService]
are the exception: the runtime injects them, so they're never serialized and don't appear on the client. Refer to Inject Cloud Code services.
Concrete classes, structs, and enums that you define in the cloud assembly are regenerated in the client bindings, with only their public fields and properties. Refer to Model types crossing the client boundary. The following types cause a compile-time error instead:
  • Interfaces and abstract classes, because the runtime can't tell which concrete type to deserialize a value into.
  • Types that derive from a .NET framework type, such as a collection, or from a type injected with
    [CloudCodeService]
    .
  • Custom collection types. Use
    List<T>
    or an array instead.
  • Types with a public property that can be read but not assigned, such as a computed property or a property without a public setter.
  • Types declared in another assembly that references the Unity engine or Editor, because that assembly can't run in the cloud.

Call an RPC from your game

The generated client bindings contain an awaitable method for each RPC. Every client-side call is asynchronous, even when the cloud method is synchronous, because each call travels over the network:
public async Task PlayAsync(){ var result = await matchStateClient.PlayTurn("rock"); Debug.Log(result);}
Each RPC response also carries the caller's synchronized state as it stands after the method runs, and the bindings apply it before the call returns. A client that calls an RPC doesn't need to hydrate separately. In a
MultiplayerSession
scope, the other players get the update as a push instead, unless you control synchronization manually.

Inject Cloud Code services

To use a Cloud Code service inside an RPC, such as the generated interface for scheduling a timer or calling another CloudBehaviour, add it as a parameter marked with
[CloudCodeService]
. The runtime injects it, and it's stripped from the generated client method:
[StateScope(Scope.MultiplayerSession)]public class MatchState : CloudBehaviour{ public async Task StartTurn([CloudCodeService] IMatchState self) { await self.OnTurnTimeout().ScheduleAsync(TimeSpan.FromSeconds(30)); } [CloudCodeAccess(Access.Service)] public void OnTurnTimeout() { /* ... */ }}
On the client,
StartTurn
generates with no
self
parameter. The client never sees it.

Register the generated interface

A generated
I{Behaviour}
interface only resolves if your module registers it. In the module's
ICloudCodeSetup
, call the generated
Add{Behaviour}Client()
extension for each behaviour you inject:
using Unity.Services.CloudCode.Core;public class ModuleSetup : ICloudCodeSetup{ public void Setup(ICloudCodeConfig config) { config.AddMatchStateClient(); }}
If you inject an
I{Behaviour}
interface without registering it, the build fails with a generator error that names the missing
Add{Behaviour}Client()
call.
Note
Mark every injected service parameter with
[CloudCodeService]
. If a Cloud Code service or a generated
I{Behaviour}
interface parameter is missing the attribute, the build fails with
CCSG136
.
For the full timer scheduling pattern, refer to Timers in CloudBehaviours. For calling another behaviour's endpoint, refer to Cross-behaviour calls in CloudBehaviours.

Additional resources