Players jitters on moving platform

Platform constantly moving forward on server side with default replication.


image

Default Third person character with default replication settings and movement component(same as platform, default).

Left window Client view - Server character jitters crazy. Right window Server view - Client character jitters but less visible.
Local characters for each client doesn’t get jitter at all.
test

Tried to crank up replication values, changing smoothing modes, etc. Nothing helps. Any suggestions?

1 Like

The reason this is happening is because you need to implement extrapolation. Otherwise, two things will either happen.
A) Client platform is doing its own thing and so is completely out of sync.
B) Platform stutters/teleports.
It is just not possible for the server to send the client the new location fast enough.

For that, this plugin will help:

If you are not interested in the plugin, I would suggest this video since I am not entirely sure what it is you are trying to accomplish:

Best of luck.

2 Likes

Ok, interesting plugin, it has different sync “pattern”, a lot of settings and extrapolation… But this not solves problem, i tried different combinations of settings and mixing with default replication, doesn’t help. Sadly, the plugin is bringing desync sometime, especially with big extrapolation.

I would look for a method like: “parenting” characters to the platform - that type of thing.
How can i implement that?

Did simple “Attach Actor to Actor”: Character to platform and immediately ran into a problem. My character additionally moving same way as platform. Why?
It feels like my platform adds a location not only to itself, but also to the character.

But how?


This is how platform changes location.

Is there a setting in character movement component? Or somewhere else?

Ok, i found the dirty solution. Basically this problem happens because of CharacterMovementComponent, you need to override UpdateBasedMovement funcion. You can do it only in c++. Good luck.

1 Like

Is there any tutorial out there I have a really similar problem, but with a boat.

1 Like

Can you explain a little bit more? I bump anyways this if someone can help.

In the end, my previous solution as “attaching” method didn’t work well. If you have single-player game, this method is okay. When you attach Player to ANY actor, then on the shipping build you will get crazy lag spikes only client side(or you can reproduce this issue in-editor imitating average latency through console commands). I bug report it, but a few months later, engine devs decided “won’t fix”. Lazy bums!

Right now, i’m interested in a plugin GMC (General Movement Component). Currently, dev is cooking 2.0 version that will include Moving Platform support.
Downsides are: you have to rewrite all moving logic and this plugin is expensive.

But i wish there was a solution to this without relying on plugins.
If someone knows, please share :skull:

I used following settings in my blueprint of my moving platform and the jittering is gone.

My bad, this never fixed it. The problem with jittering is coming from inaccurate position of the actor on client and on server. For some reason static mesh when replicated keep their position synced but I didn’t explored it yet.

1 Like

I had a similar problem on my side with moving platforms in a Listen Server project:

I had a platform moving back and forth on the server side, with client-side replication (not using default movement replication, but custom replication in C++). There were only a few milliseconds of delay between the server and the client.

But during gameplay, the server always saw the client jittering (like in your original screenshot) when standing on the moving platform. The client didn’t see the jitter.

After some digging, it seemed to come from the Character Movement’s network smoothing mode conflicting on the server side.

Disabling the network smoothing for simulated proxies only on the server side seems to solve it.

Here is the C++ version:

void AMyCharacter::BeginPlay()
{
    Super::BeginPlay();

    if (UCharacterMovementComponent* MoveComp = GetCharacterMovement())
    {
        // Disable smoothing for simulated proxies on the Listen Server
        if (HasAuthority() && !IsLocallyControlled())
        {
            MoveComp->NetworkSmoothingMode = ENetworkSmoothingMode::Disabled;
        }
    }
}

Unfortunately, it seems that we can’t configure the network smoothing mode from Blueprints.

I’m still a beginner in UE networking, so I’m not sure if this is the best solution, but so far it’s the only one that worked for me.

Don’t replicate the movement. Use an Repnotify variable to toggle the platform on and off. Server just needs to turn it on.

IMO it’s not that simple.

If you don’t replicate movement, you’ll need to implement the exact same movement logic on both the server and the clients. The server is still the authority, so if the client’s position drifts too much, it’ll get corrected — which usually results in visible jitter.

To avoid that, the client-side simulation has to stay in sync with the server. In my case, I replicate the movement start time from the server, so both simulate the same motion deterministically. That way I get smooth movement without relying on ReplicateMovement.

It literally is that easy.

There is nothing in multiplayer that is truly synced. The mere fact that each player has varying ping and packet loss prevents it from happening. Every player simulates a “copy” of the game independently of the server. Player locations/rotations at any given point in time are approximations of what each autonomous did at some past point in time. In any published multiplayer game if you where to pause the game you wouldn’t find a single match in location/rotation for any moving actor.

To somewhat counter connectivity variance between players you implement client-side prediction. Simply put CSP is applying movement/action to client on input, then RPC the server bundled moves/actions. Server applies its version of those moves and actions, then compares the results. If the results are within margins then the server sends an ACK, otherwise it sends a correction.

Client-side prediction is already implemented in the Character Movement Component (CMC) which is what the “Character” class uses in the First and Thridperson templates.

If you are using either one of these, you are in fact implementing CSP on movement.


Lets take two players both with a 100ms ping.
Player A Jumps. On input the character will jump on the local simulation. Next tick CMC RPC’s the server (auth proxy). It will take 50ms for that packet to reach the server.

On receival of the packet it is added to a buffer. On the servers next tick it processes the packet. Packets are only ever Sent and Processed on tick start.

Server simulates the movement and then Flushes the net buffer. It will take 50ms for that packet to reach Player B. On receival the packet is buffered, then processed next tick. Simulation is handled by the Game thread and 2 frames later passed to the Render thread to start rendering the first frame of the jump anim sequence and the character launch.

The delay time from Player A inputting jump until Player B starts rendering it is over 133ms.

  • Client input delay +
  • Network travel time (50% Player A ping)+
  • Server processing delay +
  • Server tick rate (30Hz, 33.333ms) +
  • Network travel time (50% Player B ping) +
  • Client processing delay +
  • Game Thread simulation (GT is typically 2 frames ahead of RT) +
  • Render Thread processing

There’s no effective way to truly sync anything in networked games. You can try using delayed time executions, but they will not sync with player movement or proximity AND on top of that Clients network clock isn’t accurate to the millisecond. It fluctuates from 0.1 to upwards 5 seconds.

Interactions need to be applied ASAP. If I interact with a door or elevator it needs to start moving as close to “immediately” as possible. My ping alone should be the greatest hindrance to the action executing.

I interact → RPC server…50% ping → server receives and executes event on actor which updates a replicated state. Replication subsystem replicates the new state to all players. I receive the packet (50% ping + 33.333ms later). Actor executes its OnRep Function for the Actors State. Action starts.

To learn more…

Here’s a few graphics I created to visualize Player to Player ping variance && the network update process.

Ping Variance is the average network time (UTT + UTT) between 2 specific players. For a more accurate approximation add the servers tick rate interval. e.g. 60Hz [16.667ms], 30Hz [33.333ms]


Client Update Rate (Client → Server) is defined in the BaseGame.ini

[/Script/Engine.GameNetworkManager]
ClientNetSendMoveDeltaTime=0.0166
ClientNetSendMoveDeltaTimeThrottled=0.033
ClientNetSendMoveDeltaTimeStationary=0.0166
ClientNetSendMoveThrottleAtNetSpeed=10000
ClientNetSendMoveThrottleOverPlayerCount=64
1 Like

Thanks for the detailed explanation, very clear.

But I think it doesn’t contradict what I said. You’re right that everything in multiplayer is inherently approximate, and CSP handles a lot of the heavy lifting for characters. But when it comes to replicated actors like moving platforms, especially ones clients can stand on or interact with, things get more complex.

If a client receives the replicated state late (e.g., due to a temporary spike or during a late join), and the server actor has already been moving for 5 seconds, simply toggling a boolean via OnRep will make the platform start “now” on the client — causing visible desync or jitter unless the client knows how far along the movement it should be.

To solve that, you can replicate the start time (like I do), or the current server location, or use something like the SmoothSync plugin — anything that allows the client to interpolate correctly toward the true state.

So yes, in the best-case scenario it is that simple. But for consistency and robustness, especially under non-ideal network conditions, you really should handle those edge cases explicitly.

They are also receiving all other states from all other actors at the same rate. A player with a 100 ping is always 50ms behind the server. A player with a 30 ping is only 15ms behind the server.

None of this will resolve packet loss, or late join.


2 players Client mode, enable network emulation. Set the pings to 100ms.

Run around in front of the other player. Jump. Note the delay in movement.

All data is delayed for every player. Including movement.


Standard Character and Onrep Door states. Nothing else.

So you’re talking in terms of consistent latency, but that’s not really how networks behave, right?

If I receive an OnRep for the first elevator with a 500 ms delay, I’ll start simulating its movement at that time. If I receive another OnRep at the same moment, but only 200 ms after the server started a second elevator, I’ll start simulating that one earlier, meaning the two elevators will already be out of sync from the client’s point of view. And that’s just on one client.

With multiple clients, each with different and fluctuating latency, how do you ensure everyone sees the same thing at the same time?

I agree your approach works in a perfect world with stable latency, but it doesn’t cover edge cases, like late join, spikes, or clients trying to interact with synced elements in different timelines.

I get that visually, each client still sees a smooth motion — but it’s still a shifted timeline. That’s fine for visuals, but it breaks shared interactions and temporal logic across players.

If you get an Onrep 500ms late, you’re also getting everything else in the sim 500ms late. Including all other players movements. Your method would require all movement to be delayed as well. Complete removal of CSP and go a full on Lockstep networking.

How would you handle projectile shooting mechanics? You definitely don’t replicate the movement of the projectile. Each proxy does its own local simulation.

When I shoot, a local projectile needs to immediately move down range and interact in my simulation. Server will do its a few ms later, and then sim proxies on all other clients will shoot.

Fortnite and every other UE multiplayer game uses Character w/CSP and Onrep for movement states.

It’s not our job to cater to garbage connections.

OnRep was designed to handle late joins. Take a door. As soon as you load the map and are in Netcull distance you are getting the current states of relevant actors. Before your character is even spawned those actors are transitioning to the authoritative state. If you setup NCD correctly for your game you shouldn’t see any issues. Regardless ping.