This is the actual template to specialize when wanting to override functions.


Inheritance Hierarchy









#include "NetworkPredictionCues.h"


template<typename ModelDef>
struct FNetworkPredictionDriver : public FNetworkPredictionDriverBase< ModelDef >


The "driver" represents the UE4 side of the NetworkPrediction System. Typically the driver will be an Unreal Actor or ActorComponent. This driver class is defined in the ModelDef (your version of FNetworkPredictionModelDef). For example, AActor or AMyPawn class. While the Simulation class is agnostic to all of this, the driver is responsible for specifying exactly how things should work, generating input and handling output from the system.

Its worth pointing out that a new ModelDef with a new Driver class is only required when you want to actually change behavior at the driver level. For example, if you define a ModelDef {MySimulation, AMyPawn_Base} you can still use this ModelDef with both AMyPawn_Player, AMyPawn_AI. You would only need to create a ModelDef {MySimulation, AMyPawn_Player} if your player class wanted to customize Driver calls for example. (And even then: making the Driver functions virtual on AMyPawn_Base would be enough, at the cost of virtual function calls).

FNetworkPredictionDriver is how calls to the driver are made. FNetworkPredictionDriverBase is a default implementation that will be used. You can customize any of these calls by specializing FNetworkPredictionDriver to your ModelDef type. If you do this, you should inherit from FNetworkPredictionDriverBase<YourModelDef> or FNetworkPredictionDriver<ParentModelDef> if you are extending an existing ModelDef. (otherwise you will need to implement every required function yourself).

The default implementations can be broken down into a few categories:

Simple stuff like ::GetDebugString() - we provide generic implemenations for AActor and UActorComponent. In general you won't need to implement these yourself unless you want to include extra information in the debug string that the system prints to logs.

Calls that get forwarded to the Driver itself. For example ::InitializeSimulationState(FSyncState*, FAuxState*). We can't provide a generic implementation because the state type is defined by the user. We forward this to the Driver because that is ultimately where the initial simulation state is seeded from. Defining InitializeSimulationState on the Driver itself is the simplest way of doing this and will make the most sense to anyone looking at the Driver class.

However there may be cases when this is not an option. For example if you want to create a Simulation in this system that can be driven by an AActor. You wouldn't want to modify AActor itself to implement InitializeSimulationState. In those cases, you can specialize FNetworkPredictionDriver<YourModelDef>::InitializeSimulationState(AActor*, FSyncState*, FAuxState*) and implement it there.

Calls that get forwarded to the underlying StateTypes. For example ::ShouldReconcile(FSyncState*, FSyncState*). The default implementation for these calls will get forwarded to member functions on the state type itself. This allows the user struct to define the default behavior while still giving the Driver type the option to override.

High level goals: maximize non-intrusive extendability, shield users from templated boiler plate where possible.

Help shape the future of Unreal Engine documentation! Tell us how we're doing so we can serve you better.
Take our survey