Common Errors

In this part of the guide, you’ll find a selection of common errors that GMC beginners like to make. If you experience an issue, you should read through this section first to see if any of the items apply to you.

You are not adjusting the mesh offset with the collision size.
You have improperly bound float variables.
You are modifying the pawn state outside of predicted functions.
You are reading non-synchronized values in your movement code.
You are using latent nodes in your movement code.
You are trying to replicate data yourself instead of using the binding functions.
You are not considering the pre-processing logic for the input vector.
You are not handling external state modifications for client-owned listen server pawns correctly.
You are not handling movement mode changes correctly.
You are not handling the client owned pawns on a listen server correctly.
You are mistaking the extrapolation of simulated pawns for a network error.
You are not considering the based movement configuration.
Your logic relies on bone transforms.
You forgot to call a parent function.
You are rotating the pawn around the pitch or roll axis with organic movement.



You are not adjusting the mesh offset with the collision size.

This error most commonly occurs when implementing a crouch functionality. The half height of the collision is reduced at run time and the mesh goes through the floor as a result. This issue stems from the fact the mesh has a certain relative location to the collision component it is attached to, and it will retain that relative location until you manually change it. For example, the default UE character mesh fits well into a capsule with a half height of 90 units, and setting the Z location offset of the mesh to -90 units aligns it with the low end of the capsule. If you now reduce the half height of the capsule to 50 units for example, the collision size decreases but the mesh still keeps the same offset of -90 units (which is too much for the new capsule size). You have to manually readjust the relative location of the mesh when you change the collision size, and you have to do it for the locally controlled pawn as well as simulated pawns. With the values from the example we just talked about, we could use a simple mapping of the half height to the relative Z location of the mesh to keep it aligned with the collision, as shown in the following screenshots.




You have improperly bound float variables.

If your float variables do not seem to replicate or behave unexpectedly, you have likely used a binding function that takes the wrong float size. 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. Another common error when binding float variables is related to compression. E.g. if you bind float variable with BindCompressedDoublePrecisionFloat, you will only get 2 decimal places of precision for that bound variable, so your logic should really not need more than those 2 decimal places to function correctly. A timer variable would be a bad choice to bind like this usually, because even at low frame rates the time differences between two frames will require more than 2 decimal places to be tracked correctly.



You are modifying the pawn state outside of predicted functions.

If you are experiencing rubberbanding or stutter of the client-controlled pawn in a network environment, you may be modifying the pawn state outside of the replication interface of the GMC. Any functions exposed by the movement component (such as those discussed in the Organic Movement Overview chapter) will run on the client and the server automatically and the output state will be kept in sync. But if you modify the pawn state somewhere else (e.g. apply a rotation in the animation Blueprint), that will almost certainly cause corrections of the client. In general, try to keep all the movement logic contained within the GMC-exposed functions, movement related code you add in other places should be purely visual and only run locally.



You are reading non-synchronized values in your movement code.

If you move the pawn based on a variable that has a different value on client and server, you’ll likely get a different result and thus cause a correction of the client. You should avoid relying on any external, non-synchronized data in your movement code (e.g. animation state). Variables that are bound appropriately (as outlined in the Networking Introduction), as well as any state values replicated by default (velocity, location, rotation, etc.), are synchronized by the GMC and can be used without restriction. For non-bound variables you should ensure that their values are the same across client and server for a particular move before reading them. Keep in mind that it is not always possible to guarantee synchronization. For example, there are events that cannot be predicted by the client, which is often the case when they originate from the actions of another player (hitstun, knockback, etc.). This means that in some situations you may have to take the correction, or find a way to make it less noticeable.



You are using latent nodes in your movement code.

Latent nodes (e.g. Delay) utilize internal timers to trigger exec pins at a deferred point in time. This makes them unsuitable for prediction, and you should therefore generally not use any latent actions in your movement code. You can identify latent nodes by the clock symbol in the top right corner of the node, but other nodes such as Timeline also fall into this category. The only exception to this rule is the GMC Play Montage node, which is guaranteed to work correctly in a predicted context.



You are trying to replicate data yourself instead of using the binding functions.

You can view a GMC binding as an additional way of replicating data in Unreal, besides the various forms of RPCs and the standard variable replication that are in the engine by default. When you bind a variable with the GMC, it will be synchronized across the network in an organized and context-sensitive manner according to the settings you have configured on the binding node (which are explained in the Networking Introduction). You should not additionally send the bound variable around via RPC or set it to replicate, that will almost certainly get you into trouble. RPCs and the standard variable replication also have their place when developing with the GMC of course, but for anything that should be predicted and replayed, and/or is directly related to the movement logic, you must use the GMC’s binding functionality exclusively.



You are not considering the pre-processing logic for the input vector.

If you use organic movement component and assign the built-in input action binding for directional input, it will be added as the raw input direction (X = forward/backward, Y = right/left, Z = up/down). When PreProcessInputVector is called during the movement logic (see the Organic Movement Overview chapter for more information), the raw input vector is transformed by the yaw of the control rotation, so forward will be in the direction of the player view. You can also leave the default input action binding exposed by the organic movement component blank and call the input action manually. This way you can implement custom logic and add the directional input yourself – just remember that PreProcessInputVector will still run on the input vector as part of the movement logic, so you may want to override the function to disable the default transformation and/or implement additional functionality.



You are not handling external state modifications for client-owned listen server pawns correctly.

There is an important difference to consider between the client-owned pawns on a listen server and a dedicated server. On a listen server, the client pawns are smoothed by default because there’s usually a local listen server player that can see those pawns, so we don’t want them to look choppy – they effectively behave the same as a simulated proxy on the client and can mostly be treated in the same way. On a dedicated server this is not the case, because there’s no local player that could see them (so visuals don’t matter). By the way, if you want to see the non-smoothed version of a client-owned pawn on a listen server, you can disable SmoothRemoteListenServerPawn in the movement component (category Networking|Server). The fact that remotely controlled listen server pawns are smoothed for visual display means we maintain two different states simultaneously for the same pawn: one state that represents the client’s current state exactly and one that is smoothed (i.e. interpolated and therefore not exactly the same as the client state). When the client movement is executed on the server the exact client state is loaded. In other words, while you are inside most GMC functions in the movement component (MovementUpdate, etc.) you don’t have to worry about the smoothed state of the simulating pawn and can apply any state changes as usual. However, when we are not simulating the client movement on the server the smoothed state is in operation (which is most of the time). This means that if you want to manipulate the state of the pawn externally, you have to load the exact client state manually (because only that state is the actual authoritative representation) and only then you can apply changes to the pawn state – otherwise any changes made will be to the smoothed state which will just be overwritten with new interpolated values on the next update, and doesn’t matter anyway from a replication standpoint (the exact client state is the important one). In practice, you do this by wrapping your logic inside two calls of SV_SwapServerState. For example, if you want to change the state of a client-owned listen server pawn inside the actor Blueprint, it would look something like this:


The SV_SwapServerState function does nothing if the pawn it is being called on is not a smoothed listen server pawn. This means that you don’t have to branch on the net mode, just put the function where it’s needed and it will apply the required change if applicable (otherwise it will do nothing and therefore also won’t break anything).



You are not handling movement mode changes correctly.

For the MovementUpdate event of the organic movement component, movement mode changes from grounded to airborne are handled automatically. E.g. if you add upward Z velocity within MovementUpdate, the pawn will always go airborne on the next frame. You can also configure MaxGroundedVelocityZ to handle this particular case, but the easiest way to ensure that the pawn will always leave the ground when you perform a custom action outside of the MovementUpdate event is to set the ReceivedUpwardForce flag.

Another case where you will have to implement additional logic for a change in the movement mode is when you create custom ones. If you merely set a new movement mode without any additional provisions, it will just be overwritten by the default ones in the next frame. You have to add conditions to UpdateMovementModeDynamic or UpdateMovementModeStatic that determine exactly in which cases the pawn should switch to your custom movement mode, and when the default ones should apply. Refer to the Organic Movement Overview chapter for more information on these functions.



You are not handling the client owned pawns on a listen server correctly.

When you are modifying the server state of a remotely controlled pawn outside of the GMC, there’s an important difference to consider between listen and dedicated servers. On a listen server, the client pawns are smoothed by default because there’s usually a local listen server player that can see those pawns, so we don’t want them to look choppy – they effectively behave the same as a simulated proxy on the client and can mostly be treated in the same way. On a dedicated server, this is not the case because there’s no local player that could see them (so visuals don’t matter). By the way, if you want to see how a client owned pawn will look on a dedicated server while running a listen server, you can disable SmoothRemoteListenServerPawn in the Server section of the movement component’s networking category. Back to the issue at hand, the fact that remotely controlled listen server pawns are smoothed for visual display means we maintain two different states at a time for the same pawn: one state that represents the client’s current state exactly, and one that is smoothed (i.e. interpolated and therefore not exactly the same as the client state). When the client movement is executed on the server, the exact client state is loaded. In other words, while you are inside most GMC functions in the movement component (MovementUpdate, etc.), you don’t have to worry about the smoothed state of the simulating pawn and can apply any state changes as usual. However, when we are not simulating the client movement on the server, the smoothed state is in operation (which is most of the time). The implication is that if you want to manipulate the state of the pawn outside of the GMC, you have to load the exact client state manually (because only that state is the actual authoritative representation), and only then you can apply changes to the pawn state. Otherwise any changes made will merely be to the smoothed state, which will be overwritten with new interpolated values on the next update and doesn’t matter anyway from a replication standpoint (the exact client state is the important one). In practice, you do this by wrapping your logic inside two calls of SV_SwapServerState. For example, if you want to change the state of a client owned listen server pawn inside the actor Blueprint, it would look something like this:

The SV_SwapServerState function does nothing if the pawn it is being called on is not a smoothed listen server pawn. This means that you don’t have to branch on the net mode, just put the function where it’s needed and it will apply the required change if applicable; otherwise it will do nothing and therefore also won’t break anything.



You are mistaking the extrapolation of simulated pawns for a network error.

By default, extrapolation happens only when no recent enough state data is available for simulated pawns (due to bad network conditions). The default extrapolation mode simulates the movement locally based on the last received set of player inputs. This makes it look very smooth and hides the fact that we are currently not working with up-to-date information rather well, which makes it ideal for covering up short lag spikes. If the connection does not recover for an extended period of time though, the local simulation and the actual server state will drift apart very noticeably. This is often misinterpreted as a networking issue, when the real cause is usually just a simple misconfiguration of some sort. You can always check whether a pawn is currently being extrapolated by using the console command gmc.LogExtrapolation 1. Since the default settings automatically adjust to the quality of the current connection, you shouldn’t run into this issue normally, except if you forget to place an actor of type AGMC_WorldTimeReplicator in the map.



You are not considering the based movement configuration.

If your characters are sticking to or following along with other objects in a way you don’t want them to, or if client pawns are moved to seemingly random locations in the world, you should check the based movement settings of the organic movement component, which can be found under the Movement|Operation|BasedMovement category. By default, the based movement source is set to Relative, which shifts the reference point of the movement logic to the object the pawn is currently based on. This has the advantage that it works without requiring any particular setup in a lot of cases. However, it also necessitates that the base can be addressed over the network. This may not always be the case by default, e.g. for non-replicated objects spawned at runtime. If you are experiencing the aforementioned problem of pawns suddenly being located at obscure coordinates, the cause is likely that the replicated base reference cannot be resolved on the client. Please refer to the Unreal Engine Documentation for more information on this particular topic, it is not a GMC-specific issue. You can achieve more fine-grained control over which objects can be a base for the pawn by overriding the TraceForActorBase function. Components contained in the hit result that is returned from this function will be considered as a potential base for the pawn. If you do not need based movement at all you can circumvent any potential issues by simply setting the based movement source to None.



Your logic relies on bone transforms.

The poses of skeletal meshes components are not synchronized between client and server. This implies that you should not rely on bone transforms for any kind for replicated functionality, and also that your skeletal mesh must not have collision enabled in a way that interferes with the kinematic movement of the pawn. Remember that you usually do not want to run animations at all on a dedicated server, so in the vast majority of cases the skeletal mesh pose should be purely visual and gameplay logic should not depend on it.



You forgot to call a parent function.

This one is pretty self-explanatory. Always call the parent implementation of any function/event that you override unless you are certain that you don’t need/want it. You can do this by right-clicking the node and selecting Add Call to Parent Function. Also remember to connect the output pins of the original node to the input pins of the parent node.



You are rotating the pawn around the pitch or roll axis with organic movement.

The organic movement component supports all collision shapes but it does not support arbitrary rotations. Like Unreal’s default character movement, it’s written with the assumption that the collision shape, regardless of which one you use, only rotates around the yaw axis (the horizontal capsule is its own collision shape class, it’s not just a default capsule component that’s rotated 90 degrees). Rotations around the pitch or roll axis will break the movement – how noticeably it breaks depends on the specific situation. Remember that this is not a limitation of the replication component. It can replicate arbitrary rotations, so you are free to write your own custom movement component that works with any orientation.