Unreal Engine and network replication

The Unreal Engine features its own model of network communication. Hexode is a multiplayer game by essence and I will try to explain in this post how it has been implemented so far.

To understand the network replication model, one has to first grasp the object model of UE and the notion of authority. Comming from Unity3D, the object model of UE was completely alien to me as there is no such thing in Unity3D. In the latter, everything is a gameobject and you may attach any component (with some restrictions and dependencies between certain components) and any script. It also means that you may organize the code as you so desire and define how each object is being (or not) replicated.

This is not the philosophy of the Unreal Engine.

The Unreal Engine differentiates between Actors (Something that is part of the level like a character or a skysphere or the hexagonal board of a previous post), Pawns (Actors that can be “possessed” by a Controller, a human or an AI), GameMode, GameState, PlayerState, etc.

When you create a Blueprint or a C++ class you may inherit one of those types. Each of these objects has a default authority which tells, in a multiplayer environment, which instance of the game is the reference. For Actors, Pawns, PlayerState and Gamestate, the default authority is the server. GameMode only exists on the server and is thus not replicated at all. All those objects may replicate variables and function calls from the server authority to the other clients. This is not a two-way communication, which is probably what is the most difficult to conceive at first, at least to me. For the PlayerController, things are a little bit different. The authority is still the server but each client has ROLE_AutonoumousProxy for its own PlayerController, which allows to “take decision” and replicate function calls on the server to change the state of the object.

Mostly every object has its authority on the server. In other words, the server can be considered as the reference for everything under its authority. Likewise, the clients are responsible for the PlayerController and the UI. The PlayerController is used in Hexode to submit move orders for the tokens on the board. The Unreal Engine model is quite logic in the end and it forces you to keep things simple.

Replication from server to client

In Hexode, the class AHexToken represents a token that can be put on the board. Tokens are used to represent the space ships. For the moment though, I use place holders graphics to test the gameplay. Each token is replicated from the server (which has the authority because Token is an Actor) to the other clients. What is replicated is actually the HexCoordinate U and V. Simple. In this case, since the coordinates of the token are defined in C++, I chose to implement the replication in code as well, instead of within the Blueprint. The highlighted lines show what needs to be done. Be warned that you may need to restart the editor in order for the changes to take effect. Recompiling the code and hot reloading were not sufficient in my case as there were no replication happening before a hard restart. I don’t know if it is a bug or an edge case.

Each machine then updates the transform’s position of the actor every single frame. This is actually not a really good design because the tokens are not moving most of the time. A solution to prevent unnecessary execution of that routine may be to use a function callback triggered only when the coordinates are replicated. I haven’t figured out yet how to integrate this with Blueprint. I may be forced to move the whole logic for updating the location from Blueprint to C++.

hex_token_move

Communication from client to server

Communicating from client to server is less obvious. I chose to use a Blueprint implementation for that part. To submit movement orders for tokens, the player controller (the client has partial authority) replicates a function call on the server only by sending an event “OnAddOrder” to the player state (the server is the authority). “OnAddOrder” is a custom event defined within the EventGraph of the player state. The event is set to replicate and the “reliable” option is checked, which basically means you are guaranteed that the replication will occur. This event only runs on the server. In certain types of games, a FPS for example, you may want to execute such methods also on each client to make predictions of the state, mainly to hide lag. For a turn based game, this is probably not necessary.

player_controller_replication_blueprint

player_state_add_order

I am not 100% satisfied with the implementation of movement orders. Blueprint lacks hash tables and I am forced to emulate the behaviour with 2 arrays: one array to store the reference to the Token and the other to store the destination coordinate. This is a bit messy. I think I may need to create a custom MoveOrder USTRUCT.

Some tips

Replication is definitely not trivial and it is hard to debug. Fortunately there is a feature in the editor to launch several instances of the game and setup the connections automatically.

multiple_network_instances

Think twice about what you replicate, in which direction and how often. Every replication does not have to be reliable. Just remember that everything has a cost and don’t use bandwidth when there is no need.

If you want to have networking capabilities in your game, don’t wait to late before testing it because it has a huge impact on the design. For example, you may be tempted to put gameplay logic within your player controller as a shortcut, and then be in a situation where it is impossible to replicate properly to the server and the other clients. So be sure to understand the object model of UE and to understand the notion of authority. That’s about the most constructive advice I could give.

 

The dev.

Leave a Reply

Your email address will not be published. Required fields are marked *