Player rotation not correctly replicated in a gravity field

I found a fix to the problem on Movable surfaces, I overrid the OnRep_ReplicatedBasedMovement method on my character to be like this:

void ADeliveryShipCharacter::OnRep_ReplicatedBasedMovement()
{
	// Following the same pattern in AActor::OnRep_ReplicatedMovement() just in case...
	if (!IsReplicatingMovement())
	{
		return;
	}

	if (GetLocalRole() != ROLE_SimulatedProxy)
	{
		return;
	}

	// Skip base updates while playing root motion, it is handled inside of OnRep_RootMotion
	if (IsPlayingNetworkedRootMotionMontage())
	{
		return;
	}

	GetCharacterMovement()->bNetworkUpdateReceived = true;
	FGuardValue_Bitfield(bInBaseReplication, true);

	const bool bBaseChanged = (BasedMovement.MovementBase != ReplicatedBasedMovement.MovementBase || BasedMovement.BoneName != ReplicatedBasedMovement.BoneName);
	if (bBaseChanged)
	{
		// Even though we will copy the replicated based movement info, we need to use SetBase() to set up tick dependencies and trigger notifications.
		SetBase(ReplicatedBasedMovement.MovementBase, ReplicatedBasedMovement.BoneName);
	}

	// Make sure to use the values of relative location/rotation etc from the server.
	BasedMovement = ReplicatedBasedMovement;

	if (ReplicatedBasedMovement.HasRelativeLocation())
	{
		// Update transform relative to movement base
		const FVector OldLocation = GetActorLocation();
		const FQuat OldRotation = GetActorQuat();
		MovementBaseUtility::GetMovementBaseTransform(ReplicatedBasedMovement.MovementBase, ReplicatedBasedMovement.BoneName, GetCharacterMovement()->OldBaseLocation, GetCharacterMovement()->OldBaseQuat);
		const FTransform BaseTransform(GetCharacterMovement()->OldBaseQuat, GetCharacterMovement()->OldBaseLocation);
		const FVector NewLocation = BaseTransform.TransformPositionNoScale(ReplicatedBasedMovement.Location);
		FRotator NewRotation;

		if (ReplicatedBasedMovement.HasRelativeRotation())
		{
			// Relative location, relative rotation
			NewRotation = (FRotationMatrix(ReplicatedBasedMovement.Rotation) * FQuatRotationMatrix(GetCharacterMovement()->OldBaseQuat)).Rotator();
		}
		else
		{
			// Relative location, absolute rotation
			NewRotation = ReplicatedBasedMovement.Rotation;
		}

		// When position or base changes, movement mode will need to be updated. This assumes rotation changes don't affect that.
		GetCharacterMovement()->bJustTeleported |= (bBaseChanged || NewLocation != OldLocation);
		GetCharacterMovement()->bNetworkSmoothingComplete = false;
		GetCharacterMovement()->SmoothCorrection(OldLocation, OldRotation, NewLocation, NewRotation.Quaternion());
		OnUpdateSimulatedPosition(OldLocation, OldRotation);
	}
}

The content of this method is the same as the ACharacter version but I removed the part about keeping the Character vertical, and that’s it !

2 Likes