Hello @iNOTme,
I believe I was having the same problem as you - input sometimes not working on client after server travel (actually, it did not work much more often than it did) . As a matter of fact, while searching for answers myself, I have seen this kind of behavior happening to a lot of other users. The common issue here seems to be the server travel. So let me share my findings, maybe they help.
After a lot of logging and debugging, I was able to pinpoint the problem, in my case, at least, to the SetupPlayerInputComponent() method in the pawn. Sometimes, the method simply did not get called because of some weird conditions depending on how pawns are spawned and posessed remotely. If you want, to can try for yourself, adding some logging in the method, overriding some other spawn/possess methods of Pawn and PlayerController, and adding some logging in there, etc.
The first and naive solution I came up with was to force the recompute of the player input. In my player controller, I overriden the OnRep_Pawn() method (you would need to have your own player controller extending from the default one) :
void AMyPlayerController::OnRep_Pawn()
{
if (GetPawn<AMyPawn>() != nullptr) {
UE_LOG(LogTemp, Warning, TEXT("onrep pawn %s"), *GetPawn< AMyPawn>()->GetFName().ToString());
GetPawn< AMyPawn>()->RecomputePlayerInput();
}
}
and then, obviously implementing the RecomputePlayerInput() method in my pawn. Please note that this implementation is actually just a striped-down copy-paste from APawn::PawnClientRestart()
void MyPawn::RecomputePlayerInput()
{
if (InputComponent == nullptr)
{
InputComponent = CreatePlayerInputComponent();
if (InputComponent)
{
SetupPlayerInputComponent(InputComponent);
InputComponent->RegisterComponent();
if (UInputDelegateBinding::SupportsInputDelegate(GetClass()))
{
InputComponent->bBlockInput = bBlockInput;
UInputDelegateBinding::BindInputDelegates(GetClass(), InputComponent);
}
}
}
}
However, I later realized that there’s a much easier way - handling input inside the player controller, and not in the pawn. The player controller is free from such replication/spawning/possessing issues, and will just forward the input to the pawn. So I removed the SetupPlayerInputComponent() from my pawn, and I added it in my player controller ( virtual void SetupInputComponent() override; )
void AMyPlayerController::SetupInputComponent()
{
Super::SetupInputComponent();
InputComponent->BindAxis("MoveForward", this, &AMyPlayerController::MoveForward);
InputComponent->BindAxis("MoveRight", this, &AMyPlayerController::MoveRight);
}
void AMyPlayerController::MoveForward(float Input)
{
if (GetPawn<AMyPawn>() == nullptr) return;
GetPawn<AMyPawn>()->MoveForward(Input);
}
Not sure if this is the best way, but it looks pretty clean and I really hope this gets your issues fixed