This page looks best with JavaScript enabled

Networking with Unreal Engine 4: Client/Server Communication

 ·  ☕ 5 min read

Overview

In my last entry I covered what I think it’s the basis of the unreal’s replication system. But we only cover the server replicating data to the client. To send data from the client to the server we use Remote Procedure Calls (or just RPCs).

what’s an RPC?

RPCs (Remote Procedure Calls) are functions that are called locally, but executed remotely on another machine (separate from the calling machine).
RPC functions can be very useful and allow either the client or the server to send messages to each other over a network connection.
The primary use case for these features are to do unreliable gameplay events that are transient or cosmetic in nature. These could include events that do things such as play sounds, spawn particles, or do other temporary effects that are not crucial to the Actor functioning. Previously these types of events would often be replicated via Actor properties.

Client, Server & NetMulticast

To declare a function as an RPC, you simply need to add Server, Client, or NetMulticast keywords to the UFUNCTION declaration.
A big difference between normal variable replication is that RPCs are executed as soon as posible.

For example, this way we declare a function as an RPC that will be called on the server and executed in a client.

1
2
UFUNCTION( Client )
void Client_RPCFunction();

If declare a function as an RPC that will be called on the client but executed on the server.

1
2
UFUNCTION( Server )
void Server_RPCFunction();

Multicast RPCs are designed to be called from the server, and then executed on the server as well as all currently connected clients (if they’re executed from a client, it will be only executed in that client).

1
2
UFUNCTION( NetMulticast )
void Multicast_RPCFunction();

In the .cpp file the name of the RPC must end with _implementation. Also notice how we prepended the Client, Server, or Multicast keyword to the beginning of the functions. This is not a requirement, but more of a convention to keep track where are supposed to be executed the RPC.

Reliable vs Unreliable

Contrary to replicated variables, by default, RPCs are unreliable. This means that they not always are executed by the client or the server (can be due a lost package or an unrealiable network). In case you want to ensure the RPC is executed you can specify the Reliable keyword.

1
2
UFUNCTION( Client, Reliable )
void Client_RPCFunction();

Keep in mind, reliable RPCs are more bandwidth expensive compared to unreliable ones.

With Validation

If you are declaring RPCs in a C++ class, you have the ability to add validation functions to RPCs was added to serve as a choke point for detecting bad data/inputs. With this you can prevent the execution of an RPC if it’s detected that one of the paramenters were bad. But be careful, if a validation fails, it could notify the system to disconnect the client or server that initiated the RPC call.

To declare a validation function for an RPC, simply add the WithValidation keyword to the UFUNCTION declaration statement:

1
2
UFUNCTION( Server, WithValidation )
void Server_AddPlayerHealt( int32 AddHealth );

Then somewhere next to the implementation function, put the validate function:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
void Server_AddPlayerHealt_Implementation( int32 AddHealth )
{
    Health += AddHealth;
}

bool Server_AddPlayerHealt_Validate( int32 AddHealth )
{
    if ( AddHealth > MAX_ADD_HEALTH )
    {
        return false;      // This will disconnect the caller
    }
    return true;           // This will allow the RPC to be called
}

And that’s it, with this we can start sending data from the clients to the server and execute events in the server, one specific client or multiple clients at the same time. RPCs and variable replication allow us to implement online features for our games without having to implement our own network system, just focusing at sharing data between Clients and Server.

Share on

Jesús Mastache Caballero
WRITTEN BY
Jesús Mastache Caballero
Game Developer