Found this topic looking for something else and I can hopefully provide a useable solution.
NOTE:
-This will NOT work with split-screen. (You will see why)
A cheap way of getting the local player’s APlayerController (whether that be the listen server OR client) is to create a APlayerController pointer on a custom child class of AGameState and set that pointer during BeginPlay() on a custom child class of APlayerController.
Heres an example:
ACustomPlayerController.cpp
void ACustomPlayerController::BeginPlay()
{
if (IsLocalPlayerController())
{
ACustomGameState* CurrentGameState = GetWorld()->GetGameState<ACustomGameState>();
if (CurrentGameState)
{
CurrentGameState->SetOwningConnectionPlayerController(this);
}
}
}
ACustomGameState.h
public:
FORCEINLINE void SetOwningConnectionPlayerController(APlayerController* InPlayerController) { OwningConnectionPlayerController = InPlayerController; }
FORCEINLINE APlayerController* GetOwningConnectionPlayerController() { return OwningConnectionPlayerController; }
private:
UPROPERTY()
TObjectPtr<APlayerController> OwningConnectionPlayerController;
Once the player controller is set, the “getter” code above allows us to access the local players controller by a simple call like so
APlayerController* LocalPlayerController = nullptr;
ACustomGameState* CurrentGameState = GetWorld()->GetGameState<ACustomGameState>();
if (CurrentGameState)
{
LocalPlayerController = CurrentGameState->GetOwningConnectionPlayerController();
}
This works by taking advantage of the fact that there is only one active Game State per UWorld and EVERY player has its own version of Game State which ensures that whenever you use that getter it will give you the local players controller every time REGARDLESS of what AActor, APlayerState, or APawn you call it on.(Thanks Game State ) and since our OwningConnectionPlayerController pointer is NOT set Replicated we do not have to worry about this being overridden by the server on the local players Game State.
The best part is this can be accessed from anywhere(As long as you include ACustomGameState.h in the .cpp, or better yet create a lightweight function library that has no includes in its header since you put them all in the .cpp of said library and… im getting carried away here.) since GetWorld() is valid on everything that inherits from AActor (You can also make GetWorld() valid on custom UObjects as well of course.)
Hopefully this helps out anyone looking for a quick cheap answer to get global access to the local players controller without having to create a whole ULocalPlayerSubsystem.
P.S. Remember, when working with networking, each Client/Listen-Server should be viewed as their own separate application. They will only know about changes that you want them to know about via RPCs. Take advantage of that!