Why is the server rotation range changing from (-180 to 180) to (-360 to 360)?

Replication3.jpg


void AKoreChar::SERVER_ChangeFacing_Implementation(FVector inVec)
{
	Capsule->SetRelativeRotation(FRotationMatrix::MakeFromZX(Capsule->GetComponentLocation(), inVec).ToQuat());
	Controller->SetControlRotation(Capsule->GetComponentRotation());
	pawnCR = Controller->GetControlRotation();
	pawnFacing = Capsule->RelativeRotation;
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Magenta, FString::Printf(TEXT("%s"), *pawnFacing.ToString()));
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Magenta, FString::Printf(TEXT("%s"), *pawnCR.ToString()));
	CLIENT_displayROTATIONS(pawnFacing, pawnCR);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//		Replication List
void AKoreChar::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);

	//Gravity Scale, Adjustments in In-Game Editor
	DOREPLIFETIME_CONDITION(AKoreChar, pawnFacing, COND_OwnerOnly);
	DOREPLIFETIME_CONDITION(AKoreChar, pawnCR, COND_OwnerOnly);
}

void AKoreChar::CLIENT_displayROTATIONS_Implementation(FRotator inCap, FRotator inCR)
{
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Cyan, FString::Printf(TEXT("%s"), *inCap.ToString()));
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Cyan, FString::Printf(TEXT("%s"), *inCR.ToString()));
}

The image shows the capsule rotation and control rotation printed to screen from the server and the client. The SERVER_ChangeFacing_Implementation sets the two replicated FRotators and displays them on screen in Magenta, then immediately calls the client function to display the same FRotators on screen in Cyan. You can see they are different. How is this possible? Why is the client version changing the rotation range from -180 to 180 to -360 to 360?

Because of the way rotators are sent over the network. When they are NetSerialize()'d the Pitch, Yaw and Roll are each compressed to a 16 bit unsigned short. The compression happens in FRotator::CompressAxisToShort(float Angle) using the following formula:


// map 0->360) to 0->65536) and mask off any winding
return FMath::RoundToInt(Angle * 65536.f / 360.f) & 0xFFFF;

Decompression happens in FRotator::DecompressAxisFromShort(uint16 Angle):


// map 0->65536) to 0->360)
return (Angle * 360.f / 65536.f);

The key here is the masking (& 0xFFFF) in the compression. It is used to deal with cases where the Angle is either >= 360.0f or < 0.0f
Your angle -15 is essentially converted to the equivalent 345 and -18 is converted to 342 (approximately).