RPCs in CloudBehaviours
Declare a remote procedure call (RPC), call it from your game, and inject services into it.
Read time 4 minutesLast updated 12 days ago
A remote procedure call (RPC) is a public method on a CloudBehaviour that runs in the cloud and that your game calls through the client bindings. The Unity Editor generates a matching method in the client bindings for each RPC. The method body never runs on a player's device, so put validation, secret logic, and anything that awards or spends resources in the method body.
Write a method your game can call
The Editor generates an RPC for each public, non-static, non-generic method on the cloud class. Methods marked are the exception, because they 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>The following example declares three methods that your game can call, and one private method that stays in the cloud:
[StateScope(Scope.MultiplayerSession)]public class MatchState : CloudBehaviour{ public void EndTurn() { // Add your turn logic here. } public int SubmitScore(int score) { // Add your scoring logic here. return score; } public async Task<string> PlayTurn(string move) { // Add your move logic here. return "ok"; } // Private methods stay in the cloud. private void ResetRound() { // Add your reset logic here. }}
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 these parameters, so Cloud Code never serializes them, and they don't appear on the client. Refer to Inject services into an RPC.
[CloudCodeService]The Editor generates a data-only copy of concrete classes, structs, and enums that you define in the cloud assembly, 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 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 the Unity 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 goes 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 after the method runs. The client bindings apply that state before the call returns, so a client that calls an RPC doesn't need a separate hydration. In a scope, the other players receive the update as a push instead, unless you control synchronization manually.
MultiplayerSessionInject services into an RPC
To use a service inside an RPC, add the service as a parameter marked with . For example, inject the generated interface to schedule a timer or call another CloudBehaviour. The runtime injects the service, and the Editor removes the parameter 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() { // Add your timeout logic here. }}
The generated client method has no parameter.
StartTurnselfRegister the generated interface
A generated interface resolves only if your module registers it. In the module's , call the generated extension method for each CloudBehaviour interface 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. To call another CloudBehaviour's endpoint, refer to Cross-behaviour calls in CloudBehaviours.