Networking Introduction

The GMC offers a powerful, Blueprint-exposed networking interface which primarily revolves around using a set of binding functions that seamlessly integrate custom data into the internal replication process with just a few clicks. Using one simple function call, bound data can be configured to support advanced network features such as client prediction and replay, move combining, lag compensation, interpolation, and more. This enables uncommonly fast iteration times on multiplayer features while requiring minimal knowledge about the netcode itself. It also removes a lot of error-prone intermediate steps that ordinarily need to be implemented by hand. In combination with the ability to prototype in Blueprint, the GMC introduces a level of speed, ease and robustness to writing multiplayer logic that you simply will not get with anything else currently available in Unreal, potentially saving you hundreds of hours of development time that would otherwise be spent reading the internal codebase, adding error-prone boilerplate, and debugging complex replication issues.

Prerequisites

You should be familiar with the basics of networking in Unreal Engine before proceeding. Refer to the Unreal Engine Documentation if you are unsure. You need to know the essential concepts and terminology outlined in the linked article to be able to follow any chapters on networking within this documentation.

Adding Replicated Logic

In general, any new movement code should only be added to the functions and events exposed by the GMC interface (e.g. those described in the previous Organic Movement Overview chapter). Logic implement in this context will automatically be predicted and executed on both client and server, and in most cases you can simply write the code like you would for a standalone game. There is no manual replication required on your part for any new movement logic that extends the GMC interface (do not send around RPCs in an attempt to network your code). So far, so easy – but there’s only so much you can do by merely adding new logic to the component. If you want to create anything of note, you will also have to add new data (i.e. variables) at some point to store information. Your new data might require replication, which in the GMC is achieved primarily by using network bindings (not by marking a variable as replicated in the Details panel).

Adding Network Bindings

The GMC provides network bindings for the most commonly used primitive and Unreal data types by default. You can view all available bindings by right-clicking in the event graph of the movement component and typing “General Movement Component Bind”. For some data types, different variations of bindings are available, e.g. float variables can be bound with full precision or as compressed values with 2 decimal places of precision. Binding functions are called exclusively from the BindReplicationData event. Once bound, a variable cannot be unbound. There are different options available in the form of function parameters, which let you control what should happen with the bound variable in a networking context. The order in which variables are bound does not matter. The following screenshot shows what utilizing binding functions looks like in practice.

As you can see, adding bindings is straightforward and virtually no work at all. Knowing when to use them and which settings to configure is the part that requires some understanding.

Binding Settings Explained

There are 4 categories of settings in total. The first one is called PredictionMode and determines how the variable will be synchronized between client and server. The settings in this category are combinations of the format [Authority]_[Sample]_[Validation]. Explanations of and possible values for each group follow.

  • [Authority]: Possible values are ServerAuth and ClientAuth. This determines whether the client or the server will have authority over this value. In general, we strive for server-authoritative gameplay to maintain a consistent world state for all players and to prevent cheating, so you will usually want to go with ServerAuth here. The only exception are variables that represent the player’s input (button presses, mouse movement, and so on), these have to be ClientAuth. At the very least, you must trust clients with their physical input on the keyboard, mouse, controller, etc., otherwise they could not move their pawns at all.

  • [Sample]: Possible values are Input, Output and InputOutput. This determines whether the input or output value of the variable will be synchronized (or both in the case of InputOutput, but that is rarely used in practice). We’ll go into more detail on this further down, but it is important to understand that Input in this context does not refer to the player’s input. Although it is often used for that purpose, Input refers to the value of the variable before the movement logic is executed. Output on the other hand refers to the transformed input value, i.e. the value of the variable after the movement logic was executed. You will usually want to choose Input here for client-authoritative variables that are set from your input action events, and Output for anything else.

  • [Validation]: Possible values are ClientValidated and ServerValidated. This determines who monitors whether the client value is still in sync or requires a correction. By definition, client-authoritative values cannot deviate so this setting is only available for ServerAuth variables. Don’t be misled by the word validation, client validation is not any less secure than server validation in this context. There are several implications for each setting, but in most cases you will want to choose ClientValidated here, which is easier on the client’s upload traffic.

The second category of settings is called CombineMode, and it determines how consecutive Input values will be combined to save bandwidth (this setting is not relevant for Output values). AlwaysCombine will not enqueue new data based on the value of the bound variable and is the most bandwidth-efficient mode. However, for ClientAuth_Input values that are coming from input action events, you will want to choose CombineIfUnchanged in most cases. You probably won’t need the Default setting.

The third category is called SimulationMode. This mode determines if and how values will be replicated to simulated proxies. Periodic will replicate the value at the configured net update frequency of the actor (conceptually at least, there are optimizations in place of course to avoid sending redundant data), PeriodicAndOnChange will additionally replicate on every change of the value. None will not replicate it at all. What you want to choose here depends on what the bound variable represents. With the default smoothing mode (interpolation) you usually only want to replicate variables that cause a visible side effect, e.g. trigger an animation. Use Periodic for most such values, and PeriodicAndOnChange only for values that change infrequently (important, otherwise you may run into bandwidth issues at some point).

The fourth and last category, Interpolation, is only relevant when SimulationMode is not None. This simply determines which function will be used when the value is interpolated. Numeric values support all interpolation functions, including custom ones. Discrete values like booleans only support NearestNeighbour, StartValue and TargetValue (if you choose another interpolation function for such values it will default to NearestNeighbour).

To deepen your understanding of the different binding settings, it can help to have a rough idea of where and when a particular setting becomes relevant in the scheme of things. The following diagram shows an extremely abstracted overview of the replication process. Do not take this chart as an indication of how the GMC works internally, it does not represent the actual flow of logic and displays a lot of gross oversimplifications. Its only purpose is to vaguely illustrate where the modes of a binding come into play. Click the image to enlarge.


Analysing the diagram, we can see that the replication process is centred around the concept of a Move. A Move is essentially just a container for the input and output values of a simulation at a particular point in time (meaning every Move has a timestamp associated with it). These Input and Output values are also what the [Sample] group of a binding’s prediction mode refers to. For a player-controlled pawn, you can set variables based on input action events and save information to the Input values of a Move by setting the appropriate prediction mode. As an example, if you have an input action Jump, you could set a bool variable PressedJump to true when the input event is triggered, and bind that variable as ClientAuth_Input. The value would then be saved as Input to the Move before it is executed. If you use organic movement, what is displayed as Execute in the diagram above would contain the logic shown as flowchart in the previous Organic Movement Overview chapter. That logic could then access the bound PressedJump variable safely in a networked context and perform movement based on it, e.g. if PressedJump == true -> ApplyUpwardImpulse. Similar to a mathematical function, the movement logic transforms the state of the pawn based on a set of input values. After execution, the new pawn state (location, rotation, etc.) is saved as Output. This way, a Move represents a relatively isolated process that can be recreated on another machine without having to send a huge amount of data. E.g. we can send the Input values of a Move to the server, and then the server just has to put those same values into the movement logic as well to (hopefully) get the same result as the client. We can also compare the Output values of a Move to verify that both objects are still in sync, and take the necessary steps for a client correction if there’s a deviation.

For player movement, you will usually follow the outlined process of setting and binding variables based on input events. However, I think it has become clear by now that the Input values of a Move are distinct from input action events and the player’s physical input on a device. You can do as much local processing as you want before you set the final variable that you are going to bind and synchronize, which can be any data type or even multiple variables. The bound data does not necessarily have to originate from the input actions of the player either. The GMC gives you a truly generic system for exchanging data between clients and the server in an organized manner. Since it is primarily an asset for player locomotion, the examples presented in this documentation will revolve around that use case. Nevertheless, once you really understand the underlying replication system, there are no restrictions on the gameplay features you can network by leveraging the GMC’s binding functionality.

Smoothed Listen Server Pawns

There is a special type of pawn not shown in the diagram, which are remotely controlled (i.e. client-owned) server pawns presented to the local player on a listen server. You can think of these pawns as having 2 states at the same time. One is the exact authoritative server state replicated to the clients, the other one is a smoothed visual state. The smoothed state only exists to improve the experience of the human player on a listen server, it does not exist on a dedicated server where there is no local player to observe it. Fortunately, you can ignore this distinction in most cases because the GMC abstracts smoothed listen server pawns to behave the same as simulated proxies. This means that if your simulated proxies look fine, smoothed listen server pawns will usually be in order as well and you won’t need to consider them separately.

Default Bindings

There are a handful of bindings already integrated into the plugin by default to make your life easier. These are values that are very commonly required by movement implementations, such as the actor’s velocity, location and rotation. You can still extensively configure these bindings by going to the Networking|ReplicationSettings category of the movement component. Additionally, if you are using organic movement, the collision shape and extent, as well as any movement modes, are also replicated out of the box.

Server-Authoritative Values

Based on what we discussed so far, you should now have a general idea about bindings and their applications. It hopefully seems reasonable to you at this point that you would bind a variable that represents the player’s physical input as ClientAuth_Input, or that you would replicate a variable that is used by the animation Blueprint by setting Periodic as simulation mode. However, unless you already have a very good understanding of client prediction and replay, it is probably not too obvious to you yet which variables would need to be bound as ServerAuth. Very generally, server-authoritative variables are those that will be policed to remain in sync. In other words, when you mark a variable as ServerAuth, the client value will be monitored for deviations from the authoritative server value, meaning these are the values that can trigger corrections/replays of the client state.

Explaining prediction and replay is out of the scope of this beginner guide. But luckily, there is an easy rule of thumb you can apply without knowing any further details about these concepts: variables that carry over information from one tick to the next usually need to be bound as ServerAuth. Another way to look at it is to ask yourself: does this variable absolutely need to exists? An example of variables that always carry over information from one tick to the next are accumulated values. For instance, if you add up consecutive delta time values as a way to measure time, you absolutely need a variable to save the accumulated value to, there’s no way around it. So you would often bind a variable like this as ServerAuth. On the other hand, if you had a bool IsOnGround, it may not be mandatory – you could simply trace downward whenever you need to know if the pawn is on the ground. This works because the location of the pawn is already synchronized, so the crux of the matter is that you can infer what you want to know from data that is already bound. Of course, it could be more efficient to remember IsOnGround and only do a trace when the pawn has moved from its previous location, but then IsOnGround would likely be carrying over information between ticks again and the variable would have to be bound. Binding variables typically increases network traffic, so in cases like this it is a matter of balancing performance and bandwidth usage.

Following this rule is a good way to ensure that your multiplayer logic is 100% “correct” and as accurate as it can be from a replication standpoint. However, in practice we generally don’t care so much about what is correct but rather what works well enough. So depending on the specifics of your implementation, some variables that would technically have to be bound as server-authoritative may, by and large, not make a difference and just waste bandwidth. These are often variables that are in effect only for a short period of time, and then reset to a default value. E.g., a timer that only runs for 200 ms every now and then, and is guaranteed to always be 0 when not active, may not be worth binding as ServerAuth. Even if, during the short window it is active, a deviation occurs (which is unlikely to begin with), the value will sync itself automatically to 0 again after the time is up on both client and server. On the other hand, something like a movement mode variable, which constantly affects a large portion of the logic, should always be bound as ServerAuth. You definitely don’t want to be stuck “swimming” on the client while the server value is “grounded”. With all that being said, it is advisable to be thorough with your bindings from the beginning, especially since you can always set the prediction mode for a variable to Local retroactively, should you later decide that it’s not worth being ServerAuth after all.

Conclusion

If you made it this far, your brain may be smoking by now. Don’t worry about it too much, while understanding all the ins and outs of the replication process can certainly help you with implementing more complex features, you can already do a lot by just following the simple, practical guidelines.

  • Bind variables that represent the player’s input as ClientAuth_Input for the prediction mode and CombineIfUnchanged for the combine mode.
  • Bind variables that carry over information between ticks as ServerAuth_Ouput_ClientValidated for the prediction mode (leave the combine mode as AlwaysCombine, it doesn’t matter in this case).
  • Bind variables that trigger animations or effects as Periodic or PeriodicAndOnChange (if they change infrequently) for the simulation mode. Otherwise set the simulation mode to None. For numeric values you usually set Linear as the interpolation function, and NearestNeighbour for any other values.