Quaternion in IInputComponentData prevents client/server sync

I have this struct

{
    public Vector2 move;
    public Vector2 look;
    public InputEvent jump;
    public quaternion lookRotation;
}

A system then fills in the struct:

        foreach (RefRW<PlayerInputData> input in SystemAPI.Query<RefRW<PlayerInputData>>().WithAll<GhostOwnerIsLocal>())
        {
            input.ValueRW.look = new UnityEngine.Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"));
        }

I then finally apply the inputs, with client prediction on. This works, all clients can see each others avatars rotating, but there is jitter, (i assume it’s from the prediction).

[UpdateInGroup(typeof(PredictedSimulationSystemGroup))]
partial class CameraControlSystem : SystemBase
{
    protected override void OnUpdate()
    {
        foreach (var (localTransform, cameraControl, playerInputData) in SystemAPI.Query<RefRW<LocalTransform>, RefRO<CameraControl>, RefRO<PlayerInputData>>())
        {
            localTransform.ValueRW = localTransform.ValueRW.RotateX(-playerInputData.ValueRO.look.y * cameraControl.ValueRO.rotateSpeed);
            var worldYrotation = quaternion.AxisAngle(new float3(0, 1, 0), playerInputData.ValueRO.look.x * cameraControl.ValueRO.rotateSpeed);
            localTransform.ValueRW.Rotation = math.mul(worldYrotation, localTransform.ValueRO.Rotation);
        {
...

Instead of sending the mouse input over to the server I though I might try letting the client hold the rotation as a quaternion and send that over instead (to see if it helps reduce jitter)

So here i calc the quaternion and store it in the IInputComponentData

        foreach (RefRW<PlayerInputData> input in SystemAPI.Query<RefRW<PlayerInputData>>().WithAll<GhostOwnerIsLocal>())
        {
            input.ValueRW.lookRotation = math.mul(input.ValueRO.lookRotation, quaternion.AxisAngle(new float3(1, 0, 0), -Input.GetAxis("Mouse Y") * 0.05f));
            input.ValueRW.lookRotation = math.mul(quaternion.AxisAngle(new float3(0, 1, 0), Input.GetAxis("Mouse X") * 0.05f), input.ValueRO.lookRotation);
        }

and finally apply that quaternion:

partial class CameraControlSystem : SystemBase
{
    protected override void OnUpdate()
    {
        foreach (var (localTransform, cameraControl, playerInputData) in SystemAPI.Query<RefRW<LocalTransform>, RefRO<CameraControl>, RefRO<PlayerInputData>>())
        {
            localTransform.ValueRW.Rotation = playerInputData.ValueRO.lookRotation;
        {
...

Now each client can rotate their own camera around without jitter, yay, but the other clients can’t anybody else rotation.

I have no clue why this is happening, I assumed that anything inside of IInputComponentData will work with prediction

If other players can’t see a state change, it’s most likely because a) they aren’t receiving it or b) they are overriding or ignoring it. Check if it’s the latter, it may be caused by your prediction code?

Btw I would avoid sending quaternions just for the “looks”. That struct is 16 bytes.

Consider that most games only rotate around Y. That’s a float you should synchronize, or compress it to half (typically accurate enough for other players). If your players can look up/down (X) as well, you may want to “compress” that -90 to +90 angle down to a byte because other players don’t need to care the exact look angle - unless you use that for deterministic shooting. So that makes 2 or 4 bytes plus 1 to send.

Focusing only on the one or two rotation axis’ should also make your prediction code simpler to implement and debug.

Please include full system component code including attributes. It can simply be some code missing correct UpdateInGroup attribute. You’re also never query for Simulate tag in your code? Also make sure you are actually syncronizing the rotation of the ghost by not disabling it in inspector or VariantSystem.