Replication, Actor/Pawn Rotation in C++

After digging though some of the links i’ve found I decided to try my hand at getting character rotation to properly replicate.

Unfortunately I cannot get client’s to replicate their rotation to the server. If using a listen server the server pawn works and the clients can see the server pawn rotation. On clients only the owning client can see it’s rotation. As a side note I’m using the shootergame and plugged in the top down camera from the top down game (isometric). I know this is a combination of both client to server and server to client… but I failed at both independently so I thought I’d try both /shrug… poking it with a stick at this point.

Sorry for my presumably bad code only wrote my first line of code a few weeks ago. Any pointers in the right direction would be great.

ShooterCharacter.h

// Current Facing of the pawn
UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category=Movement)
FVector CurrentFacing;

/** Change the facing of the character */
void ChangeFacing(FVector TargetVector);

/** Change the facing of the character on server */
UFUNCTION(reliable, server, WithValidation)
void ServerChangeFacing(FVector TargetVector);

ShooterCharacter.cpp

AShooterCharacter::AShooterCharacter(const class FPostConstructInitializeProperties& PCIP) 
	: Super(PCIP.SetDefaultSubobjectClass<UShooterCharacterMovement>(ACharacter::CharacterMovementComponentName)){
    //...
    CurrentFacing = FVector::ZeroVector;
	bReplicates = true;
    //...
}

void AShooterCharacter::ChangeFacing(FVector TargetVector)
{
	// Get the player pawn location
	FVector pPawnLoc = GetActorLocation();

	// We create a new vector from the player to the target location
	FVector FacingVector = (TargetVector - GetActorLocation());
	FacingVector = FVector(FacingVector.X, FacingVector.Y, 0);
	FacingVector.Normalize();

	// We only care about rotation around the YAW axis
	FRotator TargetRotation = FRotator(0, FacingVector.Rotation().Yaw, 0);

	// We set the characters facing to match the facing of the vector
	SetActorRotation(TargetRotation);

	// We set our current facing to the direction the actor is facing
	CurrentFacing = TargetRotation.Vector();
}

bool AShooterCharacter::ServerChangeFacing_Validate(FVector TargetVector){
	return true;
}
void AShooterCharacter::ServerChangeFacing_Implementation(FVector TargetVector){
	ChangeFacing(TargetVector);
}

FVector AShooterCharacter::GetForwardVector()
{
	/** EXAMPLE USAGE
	CharLoc + returnValue //creats a unit vector the direction the char is facing 
	pPawnLoc + (returnValue * 300) //creates a 300 length (magnitize/size) vector from the character in it's facing direction
	*/

	// find out which way is forward
	const FRotator Rotation = GetActorRotation();
	const FRotator YawRotation(0, Rotation.Yaw, 0);

	// get forward vector
	const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);

	return Direction;
}

void AShooterCharacter::GetLifetimeReplicatedProps( TArray< FLifetimeProperty > & OutLifetimeProps ) const{
	Super::GetLifetimeReplicatedProps( OutLifetimeProps );
    //...
	DOREPLIFETIME( AShooterCharacter, CurrentFacing );
    //...
}

void AShooterCharacter::Tick(float DeltaSeconds){
    //...
    	// Rotate to the mouse curser
	if (MyPC && MyPC->IsLocalController())
	{
		MyPC->RotateToMouseCursor();
	}
    //...
}

ShooterPlayerController.h

/** Point the character to the mouse **/
void RotateToMouseCursor();

ShooterPlayerController.cpp

void AShooterPlayerController::RotateToMouseCursor() {
	// get reference to controllers character //May need to find a way to get the players index
	AShooterCharacter* pPawn = Cast<AShooterCharacter>(UGameplayStatics::GetPlayerPawn(this, 0));
	if (!pPawn)
		return;

	// we use hit result of visibility to determine the mouse location in world space 
	FHitResult mouseHit = FHitResult();
	bool BMouseResult = GetHitResultUnderCursor(ECC_Visibility, true, mouseHit);
	FVector MouseHitLoc = FVector::ZeroVector;

	// If we hit something set the location and update the rotation
	if (BMouseResult)
	{
		FVector pPawnLoc = pPawn->GetActorLocation();

		// Get the impact point of cursor in world space
		MouseHitLoc = mouseHit.ImpactPoint;

		// Currently we use the pawn Z we'll alter this later
		MouseHitLoc = FVector(MouseHitLoc.X, MouseHitLoc.Y, pPawnLoc.Z);

		// Have the character change it's facing
		pPawn->ChangeFacing(MouseHitLoc);
	}

	/** DEBUG LOS Tracer */
	// get the updated pPawnLoc
	FVector pPawnLoc = pPawn->GetActorLocation();
	FVector FwdVector = pPawn->GetForwardVector();

	if (true)
	{
		DrawDebugLine(
			GetWorld(),
			pPawnLoc,
			pPawnLoc + (FwdVector * 300),
			FColor(0, 255, 0),
			true,
			1,
			0,
			1
		);
	}
}

Hi,

I had the same problem than you and I just found the solution. In fact, the new rotation is never send to the server by the client.
You must add

if (Role < ROLE_Authority) { Server_ChangeFacing(CurrentFacing); }

at the end of your function ChangeFacing(FVector TargetVector).

With that the server updates the new facing to all the clients. I’m not sure that it is fully optimised but in my case that works.