What can change the rotation of a newly possessed pawn ?

Hello,

Does anyone knows what determines the rotation of a newly possessed pawn ?

My APlayerController has a defaultpawn (first person control) has a function to possess some other ACharacter (third person control).

I always want to keep the point of view of the DefaultPawn, whatever other pawn is possessed.

I do this with a server side RPC (defined in my playercontroller.cpp):

void AyagPlayerController::ControlPawn_Implementation(APawn* TracedCharacter)
{
	if (Role == ROLE_Authority)
	{
		Possess(TracedCharacter);
		SetViewTarget(DefaultPawn);
		AttachToPawn(DefaultPawn);
	}
}

Both the DefaultPawn and the TracedCharacter are replicated.

here is the problem: as soon as i fire the possess event, the newly possessed character seems to align itself with the default pawn.

Capture 1 is just before the possession, capture 2 just after. No move has been done between the two captures, i just left-clicked to possess.

before:

After:

Wherever i am, the possessed pawn instantaneously reorients itself and shows me its back.

The fun thing is this instant rotation happens only on the clients. On the (listening) server, everything works as intended.

I have tried to play with various options/functions (server side / client side) i could find in the c++ doc such as:

SetViewTarget()
AttachToPawn()
bAttachToPawn = false;
bAutoManageActiveCameraTarget = false;

I couldn’t find any working combo and the result of my various tests seemed sometimes crazy (just implying that i am not understanding). For exemple, even with bAutoManageActiveCameraTarget = false in the constructor, the call to possess puts the view on the possessed pawn if i don’t call the SetViewTarget(DefaultPawn) to make things right.

The truth is i don’t understand in details what is going on during possession (what about the location/rotation of pawns and controller ?) so I am just trying everything blindly but no luck so far.

Any help appreciated.

Thanks

Cedric

#Desired Controller Rotation

what’s the status of these vars for your possessed character/pawn

Character Movement Component

bUseControllerDesiredRotation

Pawn.h

bUseControllerRotationYaw

Rama

#Character Movement

I am betting its this, try this!

CharacterMovement->bUseControllerDesiredRotation = false

Hi Rama,

Unfortunately it didn’t work but i hadn’t thought about digging the CharacterMovement, a good reflex to learn !! So thanks for the hint :-))

Here, it works well on the server but not on the client, so it looks like some kind of replication problem somehow.

It seems that my PlayerController teleports to the target character on the server, hence the character keeps its native orientation, while it stays on the starting character on the client, hence the target character is possessed by a controller that stands on the starting character and rotates following the starting character.

So that smells like some controller replication problem.

Of course, i’m not sure, i try to guess based on logic, but without real knowledge. I don’t know whether a pawn rotates based on its controller when possessed, or if the controller rotates based on its possessed pawn, and so on.

The two pawns (start and target) and the PlayerController have their bReplicates and bReplicateMovement set to true.

Cedric

Hi,

Definitely a problem of PlayerController location.

In the movement function of the target pawn, i switched between those two controls (when the mouse moves):

FRotator Rotation = PlayerController->GetControlRotation();
FRotator Rotation = DefaultPawn->GetActorRotation();

My initial problem was described using DefaultPawn. When i switch to PlayerController, i get two very different behaviors:

  • on the server, the target pawn moves following its own referential (using its own forward vector so to speak)

  • on the clent, the target pawn movex following my (DefaultPawn) referential (using my -spectator- forward vector)

So that seems to prove that:

  • on the server the PlayerController is teleported on the target pawn
  • on the client, the PlayerController remains on the initial pawn

I still don’t see where my error is, continuing my tests.

Any detailed explanation about the behavior of the player controller in network is welcome :slight_smile:

Cedric

When a PlayerController possesses a pawn, it sets its control rotation to match the Pawn’s current rotation (see APlayerController::Possess() if you have source). I would try to see if the pawn’s rotation is correct on the client when it’s spawned.

You might try using the console commands “displayall Pawn Rotation” and “displayall Controller Rotation” to see what the rotations look like in-game (easier than logging it sometimes).

Controller::SetInitialLocationAndRotation is another thing to look at. That sets the location/rotation of the controller used to spawn the spectator (DefaultPawn). Perhaps this isn’t happening correctly between the server and client.

Hi Zak,

Thanks for your answer.

I could check on the console that the behavior is different on the server and on the client when using possess in network:

  • on the server, the controller acquires the pawn’s rotation

  • on the client, the pawn acquires the controller’s rotation

I could make a manual workaround with the function you provided (thanks again), but still, it would be better to have the same behavior on the client and the server (all automatic or all manual, no matter as long as it is documented).

Cedric

I ran into the exact same issue. I’ve come to the conclusion that calling SetControlRotation() on the server does not replicate the change to the client. This leaves the two out-of-sync. I didn’t want to modify SetControlRotation() until I knew exactly how it was used throughout the code base, so I ended up creating my own function to force the client sync within my own PlayerController class. Here is the function definition:

	/** Force the control rotation on client and server. */
	UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = "Pawn", meta = (Tooltip = "Set the control rotation."))
	virtual void ForceControlRotation(const FRotator& NewRotation);

and here is the function’s body (from my ASDPlayerController class that derives from APlayerController):

void ASDPlayerController::ForceControlRotation(const FRotator& NewRotation)
{
	if (!HasAuthority())
	{
		// Just call SetControlRotation() on the client
		SetControlRotation(NewRotation);
		return;
	}

	// On server
	SetControlRotation(NewRotation);

	// Force on client
	ClientSetRotation(NewRotation);
}

In my Blueprint I then spawn my pawn/character, have the controller call Possess() with it, and then call my ForceControlRotation() to give both the pawn and controller the same rotation on the server and client.

I hope that helps out. If someone has a better solution that doesn’t require custom code, that would be great!

  • Dave

It looks like InputAxis events throw some values on initializing, so i solved this problem pretty simple:
Just put some boolean variable before “add controller yaw/pitch” and set it true after little delay on begin play, all works fine!

Paul

1 Like

You are awesome

I have been trying to resolve this forever and this finally fixed the issue I was having! You are an absolute legend.