Jittery first person view for clients

I’m super new to Unreal and I’ve been slowly figuring out how to do multiplayer/replication stuff. I’ve managed to figure everything out until now, and I spent all of yesterday trying to fix this.
Whenever I play as a client, the camera view jitters and lags a lot, specifically when I look around. Everything works fine when playing as the server. I looked up this problem and found a lot of answers but none of them fixed it for me. I suspect the issue may be with my use of thrusters for my movement, as the jitter only seems to happen with the specific controls that use thrusters.

Some things I’ve tried:

  1. Sending the input to a multicast custom event, then a server-side event, then the movement code.
  2. Using Switch Has Authority checks to make sure the code is only being run on the server instead of once on the server and once on the client (depending on where I put the check, it either disabled the camera movement or simply didn’t do anything).
    Note: I am not using any default character movement components, just thrusters (for looking), and Add Impulse (for movement).

Here’s a quick demonstration of the problem:
https://youtu.be/IkxUFwYc-YM
Here’s my initial input code (and variables and such to the left):


And here’s my movement code (all of the other thruster movement sequences are identical):

When replicating movement like this you will always be at the mercy of the latency between you and the server. The included CharacterMovementComponent makes up for this using client prediction and then forcing the character back if the movement shown on the client was inconsistent with server.

Moving beyond that after watching your video it seems to me there may be some type of collision or colliding issue? Be sure to check anything that has physics. If your camera has a spring arm try disabling the collision test to see if that solves the issue.

In your post you say that you send input through a multicast then server-side. Is this movement replicated? If so, there is no reason to multicast this event as it will be replicated once it is run server-side. This could be the cause of your jitter as the multicast and the server replication joust for supremacy.

Hopefully I was able to give enough direction for you to solve your issue :smiling_face_with_three_hearts:

I’m not sure about your code implementation, but you could check a couple of easy things to rule them out…

In your editor preferences are you emulating network latency? I forget off the top of my head the exact name of the tick box, but If it’s enabled, it’ll make everything look laggy on purpose to simulate lag. You could make sure that is turned off.

Also what about your net update frequency on the actor in question? If it’s low you may see some effects like you describe. You could try turning it up a bit.

Otherwise it may be an issue with the replication itself through your logic… I’ve had to run some functions along side server/multicast events that run on owning client to keep everything in sync, but that would require a little more investigation.

Thanks for the response!
The multicast thing is something I had tried in the past to fix it. It’s not currently implemented, and when it was I saw no improvement or otherwise.
The only things in the entire project that have physics are the ship meshes themselves (and the ground which they’re not touching, I guess). No spring arm for the camera, it’s just static, attached to the front of the ship.
I agree that it’s probably a physics issue, though. If I can’t fix this I may switch to a different method of movement, but I’d hate to have to remake the movement again (been doing a lot of experimenting already).

Thanks for the suggestions!
The network latency emulation is turned off. I tried changing the update frequency on the actor like you suggested, but I didn’t see any changes no matter how high or low I set it.
I tried having the movement code run on both the server and client at one point in the past, but it caused a far worse issue – the pawn would start to turn before being forced back to looking straight ahead. Tried it again just now and same result.
It may be a latency issue but I get the feeling it’s not since if I simply move side to side there’s no jitter or lag. It’s only when I use the thruster-based controls that control where the character is looking.

Yeah, it’s definitely looking like a replication issue then. I have spent a lot of time battling replication for movement controls and rotations and I hear a lot of people say do it this way or that way, but those solutions never proved fruitful for me. This is especially true on dedicated servers in conjunction with options for LAN sessions. They certainly behave differently than one another.

Rotation is in relation to pitch, finding out in a hard way, not replicated out of the box at all. It needs to be replicated on tick or timers and passed to your animation blueprint. I also found that replicating on LAN is also different than dedicated servers and movements don’t replicate like they do there. I had issues with rubber banding and solve them completely in the LAN session solution just to package a dedicated server to find the clients couldn’t move at all.

Now this is on a character and not a flying vessel, but my solution goes like such:

I feed my axis values into two separate events. One RunOnServer event and one RunsOnOwningClient event. These are not reliable for the network’s sake.

On the server event it calls an unreliable multicast event that executes the movement logic like normal and passes the axis value from the server event to the multicast to the add movement node.

On the owning client event it simply executes the logic like normal as well by passing the axis value to the add movement input node like the multicast event.

From here I am perfectly in sync on client and server no matter what. You could probably make this work with on rep functions, but it wasn’t nearly as straight forward as this approach.

Before I get any lashings from the community about clogging the network with so many server calls, I can say that this is not a cause for concern in my testing and these are unreliable and you still have network prediction for any lag that occurs. The movement inputs over the server represent a tiny execution of data. Mostly on the lower end of the scale of like no more than 3-100 BITS not bytes of data confirmed in the network profiler. So only whilst moving you are sending and receiving a negligible amount of data unreliably and even so you can tune down the update frequency on the actor to optimize further.

Now comes the part where the rotation still rubber bands or doesn’t replicate at all. For this I implemented a function I named “ControlRotation”.
It looks like this:

It was important to note that this variable needs to be replicated and marked to “SkipOwner”.

For this to update at an acceptable rate it needs to be on tick or a timer at appropriate intervals. It’s not very performance heavy despite being on tick either I can still churn out many hundreds of FPS without consideration to anything else going on in the game.

Now I have a replicated rotation variable I can use in the animation blueprint I implemented like:

Now that I have this variable in place in the anim blueprint I can set my pitch and we are moving around like butter, pitching up and down, moving left and right, frolicking around without any rubber banding at all while only sending a tiny bit of data to and from the server.

As far as updating movement speed, I addressed this by just updating the movement speeds at the tail end of my add movement with a series of branches that set the appropriate speeds depending on what is true or false because it was the only way I found to reliably update the speeds without getting out of sync with my logic. So in lieu of setting faster speeds when sprinting or running an afterburner on a button push, I set a boolean variable true or false and the branch checks after the add movement catch this and set everything appropriately and reliably because it’s happening very frequently.

Sorry this became very long. It’s a bad habit of mine. I’ve tested this across the country on remote servers and can verify excellent results. Hopefully it helps you or others. I’m open to input or criticism on the subject or any clarification on what I rambled on about lol.

Thank you! I don’t mind long posts, they provide more info, which is always good! That said, I’m not sure exactly how to implement this strategy into my code. I’m not directly setting my pitch/yaw anywhere, just activating and deactivating thrusters which do physics calculations to set the pitch/yaw. As such I’m unsure where to call ControlRotationREP and how to get its values to apply to my pawn.

Much welcome. You can just run that rotation function off event tick or probably an event with a timer on a small timer loop. The pitch variable set in the animation blueprint with the constantly updating rotation variable can be implemented into your blend space for that seamless pitch on your vessel without the jitter of the corrections from the server.

I forgot to mention that this was in fact used for the animation blend spaces and assumed you had a blend space for pitching and movement… The pitch variable in the animation blueprint will provide the necessary information for it to work properly, by plugging it into the blend space on the anim graph.

If you’re just setting it exclusively where you posted the screenshot, perhaps by running the logic with the run on owning client and the server event calling the multicast may provide you with a better result. The result for me running a raw server event had all the clients moving the same when an individual client made inputs…

Looking at it again, I would assume “PitchStrength” would need to be set somewhere on a server event as well, otherwise it may be returning the default value and that’s what’s causing the fight between the client and server. You could perhaps feed that variable into the event itself also so that when it’s called locally it’s just passed on through much like the axis value is…

If you are using Character movement Component then note anything you do on the server will be applied to the client eventually. Either by a teleport or interp (location, rotation, State, movement mode etc)…aka a correction.

So the general order of things is to apply local, then RPC server to do exactly the same with the same exact values. All the values should be obtainable by the server, so you shouldn’t have to pass anything…in most cases.

For rotation (pitch, yaw) you’ll typically use Get Controller -> Get Control Rotation on the server side.


If everything works when playing as server, then the issue is more than likely server correction.

Is there any chance that this issue was solved? I am getting this issue on a single player game. no network involved.

There isn’t an issue with character movement component in this regard.

What movement component are you using?
Show your movement code.
Show your Play in editor settings.