Character Movement Replication - Rotation Stuttering Jitter (video included)

I’m working on a Cave-Plugin (similar to nDisplays, but much smaller and cross platform).

Setup is as followed:

Server spawns a Character that represents the Cave users head that is moved by a headtracking system (or by keyboard and mouse). Each client is parsing a configuration file with all information about its corresponding wall and screen (warping, blending etc.) and spawns n Actors (for each attached monitor/projector). These Actors spawn Slate Windows with special camera components for off axis projection.
The Cave Head Character is replicated to the clients and each Off Axis Camera Actor is attached to the Cave Head Character by

AttachToActor(
            CaveGameInstance->GetCaveHeadCharacter(),
            FAttachmentTransformRules(EAttachmentRule::SnapToTarget, false)
);

The Actors on the clients mimic the server characters motion correctly, translation works ok, but the rotations on the clients are always stuttering. Any suggestions why?

Btw: The Default Pawns of the clients are custom with all user defined controls disabled

AutoPossessPlayer = EAutoReceiveInput::Disabled;
DisableInput(nullptr);
GetMovementComponent()->Deactivate();

Here is the video: https://www.youtube.com/watch?v=Xk-_8TzY4hw&feature=youtu.be
The stuttering is most visible at around 16 seconds.

Pushing up the replicated rotation precision seems to make the stutter less obvious, but it’s still there and noticeable.

ACaveHeadCharacter::ACaveHeadCharacter()
{
/*....*/
    FRepMovement RepMovement = FRepMovement();
    // default is ByteComponents
    RepMovement.RotationQuantizationLevel = ERotatorQuantization::ShortComponents;

    SetReplicatedMovement(RepMovement);
}
1 Like

Since my setup is a little bit unusual (Server dictates everything, clients just follow; therefore the replication is only unidirectional from server to client; no validation needed; no (significant) bandwidth or latency limitation, since it’s LAN only), I decided to throw away the movement component replication completely.

Now I’m using a NetMulticast method and some temporary members to store location and rotation:

UCLASS()
class  ACaveHeadCharacter : public ACharacter {
    GENERATED_BODY()
    /* .... */
public:
    UFUNCTION(NetMulticast, Reliable)
    void Multicast_UpdateLocationAndRotation(FVector Loc, FRotator Rot);

    FVector NetLoc = FVector(0,0,0);
    FRotator NetRot = FRotator(0,0,0);
    /* .... */
}

ACaveHeadCharacter::ACaveHeadCharacter()
{
    SetReplicates(true);
    SetReplicateMovement(false);
    /* .... */
}

void ACaveHeadCharacter::Multicast_UpdateLocationAndRotation_Implementation(FVector Loc, FRotator Rot){
    NetLoc = Loc;
    NetRot = Rot;
}

void ACaveHeadCharacter::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

    if (HasAuthority())
    {
        Multicast_UpdateLocationAndRotation(GetActorLocation(), GetActorRotation());
    }
}

Then I access NetLoc, NetRot on the clients from whereever I want.

This works smoothly and snappy in our LAN, since there is not much else going on there.