6 - Remote Procedure Calls
Overview
Remote Procedure Calls, or RPCs, are one of most common features of any network library and its intuitive mapping to regular methods makes it an easy first choice when trying to bring multiple clients together in a shared world, unfortunately it is often not the best choice.
RPCs can be problematic in a tick based state synchronization library like Fusion, because they are not tied to a specific tick and will execute at different times on different clients. But maybe more importantly, they are not part of the network state, so any player that connects or re-connects after an RPC was sent, or just didn't receive it because it was sent unreliably, will never see the consequences of it.
In most cases state synchronization itself is sufficient to keep players aligned, and adding an OnChange listener to a networked property can handle most transitional cases where the application cares about a change in state and not just the actual state itself.
Still, there are use-cases where RPCs are a good choice, here are a few examples:
- Sending a taunt message or other volatile non gameplay interaction between players.
- Purchasing gear from an in-game shop where exact timing is not important, and the direct result of the RPC call (deduction of funds and adding to inventory) are only important to the player that made the call. (I.e. don't use an RPC to equip said purchase)
- Setting initial player properties like name, color, skin. (I.e. anything that is a direct result of "rare" input from the player. Basically any player input that you would not want to have in the per-tick Input struct)
- Launching a game (voting on gamemode, map, or just indicating to the host that a player is ready).
Consult the Manual for an in-depth description of this topic
Fusion RPCs
In the few cases where RPCs are the right option, Fusion does make it very simple. Just tag a conventional method on any NetworkBehaviour
with the RPC attribute and indicate who may call the method as well as who shall receive the call. Make sure the method has "RPC" as prefix or postfix (no particular capitalization) and you are ready to call it.
The goal in this small example is to send a "Hello Mate!" message to all other players when pressing the R
key.
Calling the RPC
Before adding the RPC itself, the input handling needs to be extended. As the RPC call is the actual networked message, there is no need to extend the input struct. Also, as RPCs are not tick aligned anyways, there is no need to use Fusions input handling, so open Player.cs
and add:
C#
private void Update()
{
if (Object.HasInputAuthority && Input.GetKeyDown(KeyCode.R))
{
RPC_SendMessage("Hey Mate!");
}
}
Note the check for Object.HasInputAuthority
- this is because this code runs on all clients, but only the client that controls this player should call the RPC.
RPC Implementation
While still in Player.cs
, also add the RPC body itself. It gets tagged with the [Rpc]
attribute and the method name begins with "RPC". Like this:
C#
private Text _messages;
[Rpc(RpcSources.InputAuthority, RpcTargets.All)]
public void RPC_SendMessage(string message, RpcInfo info = default)
{
if (_messages == null)
_messages = FindObjectOfType<Text>();
if(info.IsInvokeLocal)
message = $"You said: {message}\n";
else
message = $"Some other player said: {message}\n";
_messages.text += message;
}
The RPCSources.InputAuthority
and RPCTargets.All
parameters tell Fusion to only let clients with Input Authority over the Player call this method but execute it on all clients.
The code itself simply searches for any Text field in the scene and appends the message to that, so in order to test this go ahead and add a text component:
GameObject > UI > Text
Change the size of the text field to fill the whole screen so it will be easier to read the text.
Back to top