V1 Migration Guide

If you have a project made with GMCv1 that you want to convert to use GMCv2, you need to follow this guide. But first, make sure that you have safely backed up your project before converting, so you’ll be able to restore it in case anything goes wrong – you have been warned.

Adding Core Redirects

The module name as well as the C++ class names have changed in the new version, so you need to add some core redirects to your project to keep your existing Blueprints. Copy and paste the following lines into the DefaultEngine.ini of your project (the file can be found in the folder named Config).

+ClassRedirects=(OldName="/Script/GeneralMovement.GenMovementReplicationComponent", NewName="/Script/GMCCore.GMC_ReplicationCmp")
+ClassRedirects=(OldName="/Script/GeneralMovement.GenMovementComponent", NewName="/Script/GMCCore.GMC_MovementUtilityCmp")
+ClassRedirects=(OldName="/Script/GeneralMovement.GenOrganicMovementComponent", NewName="/Script/GMCCore.GMC_OrganicMovementCmp")
+ClassRedirects=(OldName="/Script/GeneralMovement.GenGoldSrcMovementComponent", NewName="/Script/GMCCore.GMC_GoldSrcMovementCmp")
+ClassRedirects=(OldName="/Script/GeneralMovement.GenPawn", NewName="/Script/GMCCore.GMC_Pawn")
+ClassRedirects=(OldName="/Script/GeneralMovement.GenPlayerController", NewName="/Script/GMCCore.GMC_PlayerController")
+ClassRedirects=(OldName="/Script/GeneralMovement.SteamGameInstance", NewName="/Script/GMCSteam.SteamGameInstance")
+ClassRedirects=(OldName="/Script/GeneralMovement.MainMenu", NewName="/Script/GMCSteam.MainMenu")
+ClassRedirects=(OldName="/Script/GeneralMovement.PauseMenu", NewName="/Script/GMCSteam.PauseMenu")
+ClassRedirects=(OldName="/Script/GeneralMovement.ServerListEntry", NewName="/Script/GMCSteam.ServerListEntry")

If you have C++ classes that inherit from GMC classes you must rename the parent classes according to the new names above as well in your source files.

Additionally, open the .uproject file of your project with a text editor and rename the plugin from GeneralMovement to GMC.

You should now be able to launch your project again without any load errors (I am specifically talking about load errors only at this point, not compilations errors). If you do get load errors close the editor again without saving anything and ask for help in the Discord by posting your log file, which can be found in the Saved\Logs folder of your project directory (called <your project name>.log).

If everything’s in order and you didn’t get any load errors after opening your project, right-click the Content folder of your project in the editor and select Resave All. After all assets have been successfully resaved you can remove the core redirects you have added to your project’s DefaultEngine.ini again if you want.

At this point your Blueprints have been upgraded successfully but you still need to fix any compilation errors that you may have (either in your Blueprints or in your C++ classes).

Upgrading The Network Bindings

In GMCv2, there’s no longer a distinction between input flags and generic data. Unlike v1, where you had to explicitly specify your input flags by name to the movement component, in v2, you simply follow Unreal Engine’s standard workflow for setting up input actions and then bind the final data you want to send to the server. If you’re unsure about configuring Enhanced Input, refer to the Official Documentation or any other tutorial of your choice. The v2 bindings have evolved significantly, offering a wealth of additional options, and you’ll need to replace your existing bindings with the new ones.

Converting Input Bindings

If you’ve been using organic movement, your first step is to create input actions for directional and view input. For GoldSrc movement, you should also add actions for sprinting, jumping, and crouching. If you just need standard implementations you can simply copy the input actions from the GMC demo characters into your project. Afterward assign your newly created or copied input actions within the movement component of your actor Blueprint under the Movement|Input category. Remember that you’ll also need to create and configure an input mapping context for your actions to trigger (this should be covered in the Enhanced Input documentation you’re referring to).

With this setup, the standard input for organic/GoldSrc movement should be ready to go. Next, you’ll need to convert any custom input actions you may be using. To illustrate this process, I’ll demonstrate how to convert a simple sprint input from v1 to v2.

In v1, a sprint input binding would look something like this:

In v2, you invoke the input action event as usual. However, at some point, you’ll need to assign a value to the variable you intend to bind. The actual binding process in v2 is quite similar to how non-input flags were bound in v1. The most direct equivalent of binding the sprint action in v2 would be this:

By using this binding approach, your existing logic should function as before in v1 (conceptually at least), because it synchronizes the same input value: when the button is pressed, the value becomes true; when the button is released, the value becomes false. In v1, you didn’t have much flexibility in that regard, but in v2, you can execute custom logic before setting the value. The value also doesn’t necessarily have to be a boolean anymore, it can be any data type for which a binding is available.

It’s important to note that the value will be replicated as client-auth. This means the client will send the value to the server, and the server will trust that value. The way the input is configured here can be considered the safest approach because it only transmits the minimum required information. At the very least, the server must trust the client’s information regarding whether a button is pressed or not (otherwise the client couldn’t do anything at all in the game). Any additional processing you implement potentially reduces the security of your game, as it requires the server to trust the client with more information. However, the level of risk depends on the specific processing you do and your game’s mechanics. Ultimately, it’s a judgment call you must make, as sometimes it can be more convenient, from a programming perspective, to perform additional input processing directly on the client.

Converting Generic Bindings

I’ll provide a list of fundamental equivalencies that you need to know to convert your bindings:

  • A binding in v1 with Replicate AP / Replay checked should have ServerAuth Output ClientValidated as the prediction mode and AlwaysCombine as the combine mode in v2.

  • A binding in v1 with Replicate SP checked should use Periodic Output as the simulation mode, or PeriodicAndOnChange Output if Force Update On Change was also checked in v1. It’s worth reiterating that using Force Update On Change can consume much bandwidth if misused and should only be enabled for values that change infrequently, primarily booleans that are only toggled intermittently. If you keep the interpolation mode set to Nearest Neighbour you’ll get the same behavior as in v1. However, you can also set it to Linear to automatically perform linear interpolation on values replicated to simulated pawns. This eliminates the need for manual interpolation of custom replicated variables, as was required in v1.

  • The BindFloat/BindDouble functions now have multiple replacements to choose from. If you don’t require full precision, you can utilize the BindCompressedSinglePrecisionFloat/BindCompressedDoublePrecisionFloat functions. These functions replicate values with two decimal places of precision and are significantly more bandwidth-efficient. However, only use them if you really don’t need more than two decimal places. For certain use cases, such as timers involving delta time, you may require greater precision, in which case you can use the BindSinglePrecisionFloat/BindDoublePrecisionFloat functions to replicate values with full precision. In Blueprint, single-precision floats cannot be created anymore, but you may still not need the extra double precision. In such cases you can use the BindTruncatedDoublePrecisionFloat function which lets you replicate double precision floats with single precision, utilizing only 32 bits instead of 64 bits.

  • When binding floats, it’s crucial to use the appropriate binding function for the float type that you have. Floats created in Blueprint always have double precision (they are actually what’s called as a double in C++). Single-precision floats can still be inherited from C++ classes, and hovering over the variable/pin in Blueprint will display the actual type, either Float (single-precision) or Float (double-precision). The key point to remember is that if it says Float (single-precision), you must use the binding function with SinglePrecisionFloat in its name. But if it says Float (double-precision), you must use the binding function with DoublePrecisionFloat in its name.

  • Binding functions for other types should be easy to find and straightforward to replace. They may have slightly different names. For instance, BindVector is now called BindCompressedVector, but the behavior remains the same because vectors were already compressed for replication in v1.

To give an example on how to replace a binding, consider the MaxDesiredSpeed variable of the organic movement component bound as follows in v1:

Since it’s inherited as a single-precision float from C++ and bound for replay, and not replicated for simulation, with no need for precision beyond two decimal places, you would bind it in v2 like this:

Another example with a bool variable that triggers a jump animation:

The v2 binding for this boolean would be:

Fixing Compilation Errors

While many changes have been made to the interface, transitioning to v2 is often just a matter of replacing some renamed functions or events. In some cases, specific logic may need to be rewritten slightly differently, but major overhauls are not typically required. One noteworthy change is the absence of input modes in v2, and the replication component no longer has any knowledge of the input vector (or any other type of input for that matter). There is no longer a GetMoveInputVector function in v2. For organic movement, a RawInputVector variable is introduced and bound, which is in world space and transformed into an AbsoluteZ vector locally. You can still utilize the GetProcessedInputVector function to effectively get the same behavior as before. In case you’ve been using GetMoveRotationInput, you will need to create a new binding for that yourself.

If you can’t figure out how to port a particular piece of code to v2 your best option is to ask for help in the Discord.

Other Changes

  • GenGameState no longer exists. For time synchronization to function on the client you need to add an actor of type GMC_WorldTimeReplicator to your level. Simply create a Blueprint based on GMC_WorldTimeReplicator and place it within your level. Be aware that since the old GenGameState class no longer exists, references to it will be cleared in your project, so you may need to reassign the default game state class for certain Blueprints (e.g. in the game mode).

  • The movement component itself no longer needs to be set to replicate, only the owning actor needs to be replicated.

  • There are no network presets anymore, the default settings work in any (reasonable) network environment. GMCv2 automatically adjusts to the individual connection quality of each client in real time.

  • You can optionally place an actor of type GMC_Aggregator in your level. This actor automatically collects and ticks all GMC-relevant actors and components in the correct and most efficient order, eliminating the need for expensive prerequisite tick management and calls to functions like GetAllActorsOfClass. Additionally, it may optimize cache usage if your level contains many different ticking actors/components. To enable the aggregator, simply create a Blueprint based on GMC_Aggregator and place it somewhere within your level.