Skip to main content
An RPC (Remote Procedure Call) is a function that, when called, is also called remotely on other clients. RPCs let you trigger gameplay logic across the network without manually sending messages.

Basic example

Without an RPC, a sound played when a button is pressed is only heard locally:
void OnPressed()
{
    Sound.FromWorld( "bing", WorldPosition );
}
Add [Rpc.Broadcast] to make everyone hear it:
void OnPressed()
{
    PlayOpenEffects();
}

[Rpc.Broadcast]
public void PlayOpenEffects()
{
    Sound.FromWorld( "bing", WorldPosition );
}

RPC types

Calls the function on every connected client, including the caller. Use this for effects and events that all players should experience.
[Rpc.Broadcast]
public void PlayOpenEffects()
{
    Sound.FromWorld( "bing", WorldPosition );
}
Calls the function only on the owner of the networked object. If the object has no owner, it falls back to the host. Use this to send instructions to the player who owns a specific object.
[Rpc.Owner]
public void NotifyOwner( string message )
{
    Log.Info( $"You are the owner: {message}" );
}
Calls the function only on the host. Use this when a client needs to ask the host to perform an authoritative action.
[Rpc.Host]
public void RequestSpawn()
{
    // Only the host executes this
    var go = PlayerPrefab.Clone( SpawnPoint.Transform.World );
    go.NetworkSpawn( Rpc.Caller );
}

Static RPCs

Static methods can also be RPCs. A static RPC does not need to exist on a Component:
[Rpc.Broadcast]
public static void PlaySoundAllClients( string soundName, Vector3 position )
{
    Sound.Play( soundName, position );
}

Passing arguments

Pass arguments to an RPC like any normal method call:
void OnPressed()
{
    PlayOpenEffects( "bing", WorldPosition );
}

[Rpc.Broadcast]
public void PlayOpenEffects( string soundName, Vector3 position )
{
    Sound.FromWorld( soundName, position );
}
Supported argument types are the same as [Sync] properties: unmanaged value types, string, GameObject, Component, and GameResource.

Flags

Customize RPC delivery behaviour with flags:
[Rpc.Broadcast( NetFlags.Unreliable | NetFlag.OwnerOnly )]
public static void PlaySoundAllClients( string soundName, Vector3 position )
{
    // ...
}
FlagDescription
NetFlags.UnreliableSent unreliably — may not arrive and may arrive out of order. Fast and cheap. Suitable for position updates and visual effects.
NetFlags.Reliable(Default) Sent reliably — retried until received. Slower and more expensive. Use for chat messages and important events.
NetFlags.SendImmediateNot grouped with other messages; sent immediately. Useful for real-time streaming such as voice data.
NetFlags.DiscardOnDelayDrop the message if it cannot be sent quickly. Only applies to unreliable messages.
NetFlag.HostOnlyOnly the host can call this RPC.
NetFlag.OwnerOnlyOnly the owner of the object can call this RPC.

Filtering recipients

Restrict which clients receive a [Rpc.Broadcast] call using Rpc.FilterExclude or Rpc.FilterInclude:
// Send to everyone except players named "Harry"
using ( Rpc.FilterExclude( c => c.DisplayName == "Harry" ) )
{
    PlayOpenEffects( "bing", WorldPosition );
}

// Send only to players named "Garry"
using ( Rpc.FilterInclude( c => c.DisplayName == "Garry" ) )
{
    PlayOpenEffects( "bing", WorldPosition );
}

Caller information

Check which connection triggered the RPC using Rpc.Caller:
[Rpc.Broadcast]
public void PlayOpenEffects( string soundName, Vector3 position )
{
    if ( !Rpc.Caller.IsHost ) return;

    Log.Info( $"{Rpc.Caller.DisplayName} with the steamid {Rpc.Caller.SteamId} played open effects!" );
    Sound.FromWorld( soundName, position );
}

Network events

React to players joining and leaving by implementing Component.INetworkListener on a component placed in the scene.
public sealed class GameNetworkManager : Component, Component.INetworkListener
{
    [Property] public GameObject PlayerPrefab { get; set; }
    [Property] public GameObject SpawnPoint { get; set; }

    /// <summary>
    /// Called on the host when a player successfully joins (including the local player).
    /// </summary>
    public void OnActive( Connection connection )
    {
        var player = PlayerPrefab.Clone( SpawnPoint.Transform.World );

        var nameTag = player.Components.Get<NameTagPanel>( FindMode.EverythingInSelfAndDescendants );
        if ( nameTag is not null )
        {
            nameTag.Name = connection.DisplayName;
        }

        player.NetworkSpawn( connection );
    }
}

INetworkListener methods

MethodDescription
OnConnectedThe client has connected. They are about to start handshaking, load the game, and download required packages.
OnDisconnectedThe client has disconnected.
OnActiveThe client has completed the handshake and is fully in the game. The loading screen closes after this call.

INetworkSpawn

Implement Component.INetworkSpawn to react when a networked object spawns:
MethodDescription
OnNetworkSpawnCalled when this object is spawned on the network.