How to get PlayerController from Index?

Hi, I’m having problems with player spawning: I have set a function named “CreateSecondPlayer()”, called in my game mode’s BeginPlay() function. Currently it spawns the second player only sometimes, to avoid that randomness and make that player always spawn I’ve overriden the “ChoosePlayerStart” function.

The problem now is that I don’t know how to link or interrelate the two functions (CreatePlayer and ChoosePlayerStart) references to the player, because CreatePlayer needs the ID number / Index of the player and ChoosePlayerStart needs a AController*.

Now this is how it looks, obviously the ChoosePlayerStart is never applied to the player with index 1, created with CreatePlayer.

void AGameModePush::CreateSecondPlayer()
{
	FString Error;
	auto It1 = GetWorld()->GetPlayerControllerIterator();
	APlayerController* Player1 = *It1;
	AGameModePush::ChoosePlayerStart(Player1);


	GEngine->GameViewport->CreatePlayer(1, Error, true);
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Yellow, TEXT("Spawn time 1!"));
}

This is an outline of what I want to achieve:

    void AGameModePush::CreateSecondPlayer()
    {
    	FString Error;
//WARNING! That function doesn't exist!
    	APlayerController* Player1 = GetPlayerControllerByIndex(1);
    	AGameModePush::ChoosePlayerStart(Player1);
    
    
    	GEngine->GameViewport->CreatePlayer(1, Error, true);
    	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Yellow, TEXT("Spawn time 1!"));
    }

Here I’m inventing a function called “GetPlayerControllerByIndex” returns a pointer to the player controller with that index (APlayerController*).

As that function doesn’t exist, what would you do to solve this situation? Does it exist something like what I’m looking for directly, a function that returns the controller from the index you give it? Or is something different required? I’m pretty lost on this.

There’s a function called GetPlayerControllerIterator in World. Here’s how you use it:

auto It = GetWorld()->GetPlayerControllerIterator();
for (int Idx = 0; Idx < INDEX_YOU_WANT; ++Idx)
    ++It;
APlayerController* PC = *It;

In case you need all controllers (including AIs), there is also a GetControllerIterator function available.

Thanks for the suggestions. I’m having a type casting problem, though, as you can see in this piece of code. GetGamePlayer returns a ULocalPlayer* and ChoosePlayerStart returns a AController*. How would one cast or solve that?

		FString Error1;
		AController* Player1;
		ULocalPlayer* LocP1;

		LocP1 = GEngine->GetGamePlayer(GEngine->GameViewport, 1);
                //problem and error here:
		Player1 = Cast<LocP1> (AController*);


		AGameModePush::ChoosePlayerStart(Player1);

		GEngine->GameViewport->CreatePlayer(1, Error1, true);

EDIT: Actually resolving the cast wouldn’t be useful to achieve the solution, so forget about this comment. I’m going to edit the first post to explain it better.

There is GetGamePlayer which you can call on GEngine

Edit: actually checked out and what I constructed from this isn’t giving working results.

Any ideas? I’ve completely reformulated the first post, I hope someone might be able to help if checking it back.

How about:

ULocalPlayer* ThePlayer = GEngine->GetGamePlayer(GetWorld(), RequiredIndex);
if( ThePlayer != NULL )
{
	APlayerController* PC = ThePlayer->PlayerController;
}

Hello, thank you for the comment, @anonymous_user_33677f36 Nesbit, I think I’m nearer to the solution now; however the editor crashes when trying to play and the log says there was a critical error, and I don’t know if it’s related with this but here there is a suspicious line:

[2014.04.22-19.48.10:385][157]LogWindows: Assertion failed: InPlayer < PlayerList.Num() [File:D:\BuildFarm\buildmachine_++depot+UE4-Releases+4.0\Engine\Source\Runtime\Engine\Private\UnrealEngine.cpp] [Line: 8400]

Here’s the code I’m using now (from my game mode):

void AGameModePush::BeginPlay()
{
	Super::BeginPlay();

	if (GEngine)
	{
		CreateSecondPlayer();
		CreateThirdPlayer();
		CreateForthPlayer();
	}
}


void AGameModePush::CreateSecondPlayer()
{
	FString Error;

	ULocalPlayer* ThePlayer = GEngine->GetGamePlayer(GetWorld(), 1);
	if (ThePlayer != NULL)
	{
		APlayerController* PC = ThePlayer->PlayerController;
		AGameModePush::ChoosePlayerStart(PC);
	}

	GEngine->GameViewport->CreatePlayer(1, Error, true);
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Yellow, TEXT("Spawn time 1!"));
}


void AGameModePush::CreateThirdPlayer()
{

	FString Error;

	ULocalPlayer* ThePlayer = GEngine->GetGamePlayer(GetWorld(), 2);
	if (ThePlayer != NULL)
	{
		APlayerController*  PC = ThePlayer->PlayerController;
		AGameModePush::ChoosePlayerStart(PC);
	}

	GEngine->GameViewport->CreatePlayer(2, Error, true);
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Yellow, TEXT("Spawn time 2!"));
}

void AGameModePush::CreateForthPlayer()
{
	FString Error;

	ULocalPlayer* ThePlayer = GEngine->GetGamePlayer(GetWorld(), 3);
	if (ThePlayer != NULL)
	{
		APlayerController* PC = ThePlayer->PlayerController;
		AGameModePush::ChoosePlayerStart(PC);
	}

	GEngine->GameViewport->CreatePlayer(3, Error, true);
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Yellow, TEXT("Spawn time 3!"));
}

Analizing it, what I first think is that it might be an issue with the player index number in one of these lines:

    	ULocalPlayer* ThePlayer = GEngine->GetGamePlayer(GetWorld(), 1);
    	if (ThePlayer != NULL)
    	{
    		APlayerController* PC = ThePlayer->PlayerController;
    		AGameModePush::ChoosePlayerStart(PC);
    	}

I say that because I really don’t know how the engine generates player indexes and at that point maybe it has not created or fully constructed indexes others than the default 0, maybe they need to be created manually through another process first, if that’s the case it would be great if someone could note it and explain on this.

Otherwise the problem might be that the Player Controller of a Player other than the one with index 0 is Null, and needs to be created in some manner. If that’s how it’s done, I would be thankful if someone could say it and tell more about that.

GetGamePlayer will assert if you try and get a player that does exist so you probably want to either use GetGamePlayers which will return the array of players and you can determine how many players have been created by checking the array size or use the GetLocalPlayerIterator method Arshia001 describes to iterate through the list of those created.

I dont know how and where your spawning the players so im not sure how you are going to identify which player is which in the array - if you create player 0 and 2 for example but dont create player 1 then the array will contain only 2 entries - player 0 and 2 so you cant just use the index.

This randomness has automatically been solved in 4.1.