I’ve been banging my head against this for weeks and could use some advice.
Overview
In a multiplayer session, I have two Characters that can run around. I also have a Boat, which is an Actor that has two Seats (Child Actors). When a Character (player) runs up to the boat and interacts with a Seat, I have the Character attach to the Seat component on the Server.
Problem
On the Server, both players in the boat smoothly move with the boat as it moves.
On the Client, the non-Client player’s location jitters as the boat moves.
Detail
When a Player interacts with the Seat, I “Attach Actor to Component” the Player actor to the Seat component, set the Player Character’s movement type to Flying, and tell their Player Controller to Disable Input on the Player Actor. This all works just fine except for the motion jitter. Clearly it’s the server and client fighting over what the true position is, but I’m not sure how to resolve this.
are you sure the attachment is being propagated? on the client set a debug key on the PlayerCharacter to print the result of GetOwner()
if you make a function on the Client that disables the Controller and put them in the seat, and trigger that function does it have the same behavior?
are both instances running on the same system, or are both instance running on separate systems? if these are on the same system, if you give the Client focus and not the server does it jitter at that point?
is this happening in PIE, or in a Packaged version?
I’m testing in PIE where Listen Server and Client are on the same system, but this is also happening in builds where I’m playing with another person on a different system. And locally, it happens regardless if the Client’s window is focused or not. It definitely appears to be a replication/server correction issue.
I set up a debug key to print what the Server says is the Player Character’s owner and then what the Client says is the owner, and I did find that there was a different answer! I corrected that, but it didn’t resolve the issue.
I did find that turning off the Character’s Replicate Movement stopped the jitter, but it also caused other issues.
Revisiting this to say that I discovered what was causing the client player character from jittering when attached to a moving actor (i.e. a car). Disabling the player’s Replicate Movement stops the client and server from fighting over the player’s true position and hands it fully over to the parent actor.
HOWEVER! Turning off Replicate Movement breaks replication of animation montages and montage notifies. Unsure if this is a bug, but it isn’t what I’d expect to be affected by this change.
have you tried only attaching on the server not the client, since the movement is replicated which you need, you dont need to attach on client i think which could be causing the fighting/dsync
Unfortunately, that doesn’t do it. I’ve reproduced the attachment jitter in a fresh project that works like this:
Player presses B button
Calls a reliable Run on Server custom event
This Run On Server event calls CharacterMovement->DisableMovement, Set Actor Enable Collision to false, then uses Attach Actor to Component to attach the player to the object.
Also tried: the Run on Server event calls a reliable Multicast event which performs the Attach Actor to Component.
In both cases, the Client player has motion jitter until I turn off Replicate Movement on the player.
I tried changing Step 3 up there to set the Character Movement Mode to None/Flying/Swimming/Custom instead of disabling, and same result.
Ultimately, I don’t think there should be a need for client-side prediction on the player once they’re attached to the vehicle, as they’re an attached child object, right?
After all of these months, I finally found the solution, and it’s really dead simple:
When you attach a Character (with a Character Movement Component on it) to another actor and want them to stay put, you need to set CharacterMovementComponent -> bIgnoreClientMovementErrorChecksAndCorrection to True. This is accessible both in C++ and in Blueprints (get the movement component, drag off of it, and create a Set Ignore Client Movement Error Checks And Correction node).
Want to also add, for the sake of completeness, that it’s ALSO possible that this is caused by playing a Montage or Animation Sequence that has Root Motion enabled. If turning on bIgnoreClientMovementErrorChecksAndCorrection doesn’t nail it, make sure you’re not playing any animations with Root Motion enabled!