I’m having an issue where based on some event, I want to move the currently possessed character and then have the controller possess another pawn. This needs to work in a networked environment.
For simplicity’s sake, let’s assume that I’ve bound an input in my character to a function, which in turn calls a Server RPC. In the Server RPC, I call:
SetActorLocation(FVector(-18000, -12375, 145));
GetController()->UnPossess();
What I’ve noticed is that if I comment out the UnPossess call, this works fine. But if I include the UnPossess call, the movement happens on the server but is not replicated on the client.
In case you’re wondering: Yes, the character is marked as both bReplicates = true and bAlwaysRelevant = true. Character movement also works fine in a networked setting for me all the time for all players except for once the character is unpossessed.
So I dug into this some more and here’s what I found:
- If I first move the actor, then set a timer for 0.01s and do the unpossession when the timer goes off, everything works fine. It just seems to be a problem if it happens in the same frame.
- If I don’t include the unpossess call, then the movement eventually leads to
UCharacterMovementComponent::ClientAdjustPosition_Implementation
being called. - If I don’t include the unpossess call, it never reaches that point because
APlayerController::SendClientAdjustment()
returns early sinceAcknowledgedPawn != GetPawn()
- If I don’t include the unpossess call, it does seem to replicate
ReplicatedMovement
and it hits a breakpoint inACharacter::OnRep_ReplicatedMovement
, however this leads toACharacter::PostNetReceiveLocationAndRotation()
where it doesn’t end up updating the location becauseReplicatedBasedMovement.HasRelativeLocation()
is true.
At this point, I’m out of ideas. I don’t really want to spend more time digging into engine network movement code. I’ll use the timer workaround if I have to, but I’d rather figure out if this is a bug or a misunderstanding on my side.