Multiplayer in Blueprints

Unreal Engine 4 provides a lot of multiplayer functionality out of the box, and it's easy set up a basic Blueprint game that works over a network. It's easy to dive in and start playing mutliplayer. Most of the logic to make basic multiplayer work is thanks to the built-in networking support in the Character class, and its CharacterMovementComponent, which the Third Person template project uses.

Gameplay framework review

To add multiplayer functionality to your game, it's important to understand the roles of the major gameplay classes that are provided by the engine and how they work together - and especially, how they work in a multiplayer context:

  • GameInstance

  • GameMode

  • GameState

  • Pawn (and Character, which inherits from Pawn)

  • PlayerController

  • PlayerState

See the Gameplay Framework documentation for more information - but at least keep in mind the following tips when designing your game for multiplayer are:

  • The GameMode object only exists on the server.

  • The GameState exists on the server and the clients, so the server can use replicated variables on the GameState to keep all clients up-to-date on data about the game.

  • A PlayerController exists on the server for every player connected to the game. On clients, only the PlayerControllers for players owned by that client exist. This means that PlayerControllers are not the best place to store replicated properties that all connected clients are interested in. Instead, use the PlayerState.

  • A PlayerState will exist for every player connected to the game on both the server and the clients. This class can be used for replicated properties that all clients, not just the owning client, are interested in, such as the individual player's current score.

  • Pawns (including Characters) will also exist on the server and on all clients, and can also contain replicated variables and events. The decision of whether to use the PlayerState or the Pawn for a certain variable or event will depend on the situation, but the main thing to keep in mind is that the PlayerState will persist for the entire time the player is connected, but a Pawn may not. For example, if a player character dies during gameplay, the Pawn he was controlling may be destroyed and a new one created when the player respawns.

Actor replication

replicates.png

The core of the networking technology in UE4 is actor replication. An actor with its "Replicates" flag set to true will automatically be synchronized from the server to clients who are connected to that server. An important point to understand is that actors are only replicated from the server to the clients - it's not possible to have an actor replicate from a client to the server. Of course, clients still need to be able to send data to the server, and they do this through replicated "Run on server" events.

See this How to Replicate Actors guide for a walkthrough of a concrete example, as well as the Actor Replication documentation.

Authority

For every actor in the world, one of the connected players is considered to have authority over that actor. For every actor that exists on the server, the server has authority over that actor - including all replicated actors. As a result, when the Has Authority function is run on a client, and the target is an actor that was replicated to him, it will return false. You can also use the Switch Has Authority convenience macro as a quick way to branch for different server and client behavior in replicated actors.

switch_has_authority.png

Variables

In the details panel of variables on your actors, there is a Replication drop-down that lets you control how your variables are replicated, if at all.

variable_replication.png

Option Description
None This is the default for new variables, and means the value will not be sent over the network to clients.
Replicated When the server replicates this actor, it will send this variable to clients. The value of the variable on the receiving client will update automatically, so that the next time it's accessed, it will reflect what the value was on the server. Of course, when playing over a real-world network, the updates will be delayed by an amount of time dependent on the network's latency. Remember that replicated variables only go in one direction, from the server to the client! To send data from a client to the server, see the "Events" section.
RepNotify The variable will be replicated as in the Replicated option, but in addition, an OnRep_ function will be created in your blueprint. This function will be called by the engine automatically on the client and the server whenever the value of this variable changes. You're free to implement this function however you'd like, as needed by your game. onrep.png

Many of the variables in the engine's built-in classes already have replication enabled, so that many features work automatically in a multiplayer context.

See this Replicating Variables guide for a walkthrough of a concrete example of variable replication, as well as the Property Replication documentation.

Spawning and destroying

When a replicated actor is spawned on the server, this is communicated to clients, and they will also automatically spawn a copy of that actor. But since, in general, replication doesn't occur from clients to the server, if a replicated actor is spawned on a client, that actor will only exist on the client that spawned it. Neither the server nor any other client will receive a copy of the actor. The spawning client will, however, have authority over the actor. This can still be useful for things like cosmetic actors that don't really have an effect on gameplay, but for actors that do have an effect on gameplay and should be replicated, it's best to make sure they are spawned on the server.

The situation is similar for destroying replicated actors: if the server destroys one, all clients will destroy their respective copies as well. Clients are free to destroy actors for which they have authority - that is, actors they have spawned themselves - since these are not replicated to other players and wouldn't have any affect on them. If a client tries to destroy an actor for which he is not the authority, the destroy request will be ignored. The key point here is the same for spawning actors: if you need to destroy a replicated actor, destroy it on the server.

Event replication

In Blueprints, in addition to replicating actors and their variables, you can also run events across the clients and the server.

See this Replicating Functions guide for a walkthrough of a concrete example, as well as the RPCs documentation.

You may also see the term RPC (Remote Procedure Call). If so, just be aware that replicated events in Blueprints essentially compile down to RPCs inside the engine - and this is what they're usually called in C++.

Ownership

An important concept to understand when working on multiplayer, and especially with replicated events, is which connection is considered to be the owner of a particular actor or component . For our purposes, know that "Run on server" events can only be invoked from actors (or their components) which the client owns. Usually, this means you can only send "Run on server" events from the following actors, or from a component of one of the actors:

  • The client's PlayerController itself,

  • A Pawn that the client's PlayerController possesses, or

  • The client's PlayerState.

Likewise, for a server sending "Run on owning client" events, those events should also be invoked on one of these actors. Otherwise, the server won't know which client to send the event to, and it will only run on the server!

Events

In the details panel of your custom events, you can set how the event is replicated, if at all.

event_replication.png

Option Description
Not Replicated This is the default, and means there will be no replication for this event. If it is invoked on a client, it will only run on that client, and if it is invoked on the server, it will only run on the server.
Multicast If a multicast event is invoked on the server, it will be replicated to all connected clients - regardless of which connection owns the target object. If a client invokes a multicast event, it will be treated as if it wasn't replicated, and it will only run on the client that invoked it.
Run on Server If this event is invoked from the server, it will only run on the server. If it's invoked from a client, with a target that the client owns, it will be replicated to and run on the server. "Run on Server" events are the primary method for clients to send data to the server.
Run on Owning Client If invoked from the server, this event will run on the client who owns the target actor. Since the server can own actors itself, a "Run on Owning Client" event may actually run on the server, despite its name. If invoked from a client, the event will be treated as if it isn't replicated, and it will only run on the client that invoked it.

The following tables illustrate how the different replication modes affect where an event is run, based on how it is invoked.

If the event is invoked from the server, given the target in the left-hand column, it will run on...

Not replicated Multicast Run on Server Run on Owning Client
Client-owned target Server Server and all clients Server Target's owning client
Server-owned target Server Server and all clients Server Server
Unowned target Server Server and all clients Server Server

If the event is invoked from a client, given the target in the left-hand column, it will run on...

Not replicated Multicast Run on Server Run on Owning Client
Target owned by invoking client Invoking client Invoking client Server Invoking client
Target owned by a different client Invoking client Invoking client Dropped Invoking client
Server-owned target Invoking client Invoking client Dropped Invoking client
Unowned target Invoking client Invoking client Dropped Invoking client

As you can see from the table above, any events that are invoked from a client and that are not set to Run on Server are treated as if they are not replicated.

Sending a replicated event from the client to the server is the only way to communicate information from a client to the server, since general actor replication is designed to be server-to-client only.

Also, note that multicast events can only be sent from the server. Because of Unreal's client-server model, a client isn't directly connected to any of the other clients, he's only connected to the server. Therefore, a client is unable to send a multicast event directly to the other clients, and must only communicate with the server. You can emulate this behavior, however, by using two replicated events: one Run on server event, and one Multicast event. The implementation of the Run on server event can perform validation, if desired, and then call the multicast event. The implementation of the multicast event would perform the logic that you'd like to run for all connected players. As an example that doesn't perform any validation at all, see the following image:

forward_multicast.png

Join-in-progress considerations

One thing to keep in mind when using replicated events to communicate game state changes is how they interact with a game that supports join-in-progress. If a player joins a game in progress, any replicated events that occurred before the join will not be executed for the new player. The takeaway here is that if you want your game to work well with join-in-progress, it's usually best to synchronize important gameplay data via replicated variables. A pattern that comes up pretty often is that a client performs some action in the world, notifies the server about the action via a "Run on server" event, and in the implementation of that event, the server updates some replicated variables based on the action. Then the other clients, who did not perform the action, still see the result of the action via the replicated variables. In addition, any clients who join-in-progress after the action has occurred will also see the correct state of the world, since they receive the most recent value of the replicated variables from the server. If the server had instead only sent an event, the join-in-progress players wouldn't know about the action that was performed!

Reliability

For any replicated event, you can choose whether it is Reliable or Unreliable.

Reliable events are guaranteed to reach their destination (assuming the ownership rules above are followed), but they introduce more bandwidth, and potentially latency, to meet this guarantee. Try to avoid sending reliable events too often, such as on every tick, since the engine's internal buffer of reliable events may overflow - when this happens, the associated player will be disconnected!

Unreliable events work as their name implies - they may not reach their destination, in case of packet loss on the network, or if the engine determines there is a lot of higher-priority traffic it needs to send, for example. As a result, unreliable events use less bandwidth than reliable events, and they can be called safely more often.