DeveloperGuidePart02RemoteProcedureCalls

Introduction to Alteruna Remote Procedure Calls.

What are Remote Procedure Calls?

Remote Procedure Calls within Alteruna Multiplayer allow you to register and execute functions on other
clients within the same room. These functions can be executed on a specific client,
or any number of clients within the room.

How do I use RPCs?

The recommended way to use RPCs is through AttributesSync:
mark a method with [SynchronizableMethod], then call it on other clients with InvokeRemoteMethod or BroadcastRemoteMethod.

InvokeRemoteMethod vs BroadcastRemoteMethod

Both methods do the same underlying thing: run a [SynchronizableMethod] on other clients in the room.
The difference is who receives the call:
  • BroadcastRemoteMethod always sends to everyone in the room, including yourself. There is no way to
exclude anyone, so it is the simplest option when you want every client (yourself included) to react.
  • InvokeRemoteMethod lets you choose who receives it: a single user, a list of users, or everyone.
Its default target is UserId.All, which means everyone except yourself. Pass UserId.AllInclusive
instead if you also want it to run locally.
As a rule of thumb: use BroadcastRemoteMethod for "notify everyone, including me" events (e.g. playing a
sound or effect that should also happen on your own client), and use InvokeRemoteMethod when you need to
target specific user(s), or you are already handling the local reaction yourself and only want to tell
everyone else.
Here is a simple audio sync script that uses InvokeRemoteMethod. When Play() runs, it plays the sound on
every other client, and calls PlayRemote() directly to also play it locally (since the default target of
InvokeRemoteMethod excludes the caller):

C#
public class PlayAudioSync : AttributesSync
{
       public AudioSource MyAudioSource;

       public void Play()
       {
           // Invoke on all other clients (default target is UserId.All, i.e. everyone but us).
           InvokeRemoteMethod();

           // InvokeRemoteMethod above does not include us, so call PlayRemote() directly to also play it locally.
           PlayRemote();
       }

       [SynchronizableMethod]
       private void PlayRemote()
       {
           MyAudioSource.Play();
       }
   }
The same result can be achieved with BroadcastRemoteMethod, which always includes the caller, so there is no need to call PlayRemote() separately:

C#
public class PlayAudioSyncBroadcast : AttributesSync
{
       public AudioSource MyAudioSource;

       public void Play()
       {
           // BroadcastRemoteMethod always includes the caller, so PlayRemote() also runs on this client.
           BroadcastRemoteMethod();
       }

       [SynchronizableMethod]
       private void PlayRemote()
       {
           MyAudioSource.Play();
       }
   }
In the case that you want to pass arguments to a SynchronizableMethod, or target a specific user,
do the following:
C#
public class MyAttributesSync : AttributesSync
   {
       public void SendRpc()
       {
           // 0 is the method ID of MyReceiver (it's the only SynchronizableMethod here, so its ID is 0).
           // We could use nameof(MyReceiver) instead of 0, but that is slower - see GetMethodAttributeId below.
           // UserId.All targets every other client; pass a specific user's ID instead to target only them.
           InvokeRemoteMethod(0, UserId.All, "Hello, World!", 16.0f);
       }

       [SynchronizableMethod]
       private void MyReceiver(string foo, float bar)
       {
           Debug.Log(foo);
           Debug.Log(bar);
       }
}

Improving performance with GetMethodAttributeId

Calling InvokeRemoteMethod or BroadcastRemoteMethod with a method name (a string) works, but it has to look
through all of the object's [SynchronizableMethod]s to find the one with that name every time it is called.
If you are calling the same method often, look up its numeric ID once with GetMethodAttributeId and reuse it -
calling by ID skips the name lookup entirely.
C#
public class MessageAll : AttributesSync
   {
       private int _messageMethodId;

       private void Start()
       {
           // Look up the method's ID once, for example on Start.
           _messageMethodId = GetMethodAttributeId(nameof(Message));
       }

       public void SendMessage(string msg)
       {
           // Invoke using the cached ID instead of the method name - faster if called frequently.
           BroadcastRemoteMethod(_messageMethodId, msg);
       }

       [SynchronizableMethod]
       private void Message(string msg)
       {
           Debug.Log(msg);
       }
}

← Back | Next →

See Also