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
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.
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 , which define per-player state views instead. The method can be synchronous or asynchronous (returning or ), and it can take parameters and return a value:
[SyncView]TaskTask<T>[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 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.
[CloudCodeService]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 or an array instead.
List<T> - 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 scope, the other players get the update as a push instead, unless you control synchronization manually.
MultiplayerSessionInject 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 . The runtime injects it, and it's stripped from the generated client method:
[CloudCodeService][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, generates with no parameter. The client never sees it.
StartTurnselfRegister the generated interface
A generated interface only resolves if your module registers it. In the module's , call the generated extension for each behaviour you inject:
I{Behaviour}ICloudCodeSetupAdd{Behaviour}Client()using Unity.Services.CloudCode.Core;public class ModuleSetup : ICloudCodeSetup{ public void Setup(ICloudCodeConfig config) { config.AddMatchStateClient(); }}
If you inject an interface without registering it, the build fails with a generator error that names the missing call.
I{Behaviour}Add{Behaviour}Client()For the full timer scheduling pattern, refer to Timers in CloudBehaviours. For calling another behaviour's endpoint, refer to Cross-behaviour calls in CloudBehaviours.