I know it’s an old question, but I had encoutered the same kind of issue. So I’ll to explain 2-3 things.
You have to separate two things : Controller ID and Controller Index.
The index is the position in the world player controller’s array. It may change for the same controller especially in a Listen Server after a seamless travel with a controller swap (ex : if changing the class).
The ID (indentifier) of the controller is store in the LocalPlayer and is unique for each local controller, where 0 is the “main” controller that can be used for referencing HUD & Widgets.
So " the controller on index 0 is always "your player controller" " is not true.
If you need the main controller, you have to add a little C++ function like so :
APlayerController* UMyClass::GetMainController(const UObject* WorldContextObject)
{
// Get world context (containing player controllers)
if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull))
{
// Loop on player controllers
for (FConstPlayerControllerIterator Iterator = World->GetPlayerControllerIterator(); Iterator; ++Iterator)
{
// Get player controller from iterator
APlayerController* PlayerController = Iterator->Get();
// Get local player if exist
ULocalPlayer* LocalPlayer = PlayerController->GetLocalPlayer();
// If it's local and id is 0, it's the main controller
if (LocalPlayer != nullptr && LocalPlayer->GetControllerId() == 0)
{
return PlayerController;
}
}
}
// Not found
return nullptr;
}
Hope it’ll help some other devs !