How can I resolve ChoosePlayerStart(AController* Player) Player is NULL?

Hi!
When I try to override ChoosePlayerStart(AController* Player)
in my custom game mode, the Player pointer passed has value NULL. I would need to know which player it is in order to choose the correct PlayerStart. Why is this happening and how can I solve it?

Look on source code suggest it is possible that this function might get null pointer

https://github.com/EpicGames/UnrealEngine/blob/7fdf681ee21b111524848ade9e952de3ad3fa1ac/Engine/Source/Runtime/Engine/Private/GameMode.cpp#L334

And give this warning if both playercontroller and return from ChoosePlayerStart will be null
“Warning - PATHS NOT DEFINED or NO PLAYERSTART with positive rating”

Maybe try to “if” it out if that happens and return null, i didnt analize possibilities deply but maybe you might got another call with controller. You would need to debug call stack to check what really sends then null and to debug that you need engine call symbols (pdb files) which you can get by compiling the engine.

I am also interested in an answer to this question, it seems to be the case at least when the player is first started in the GameMode, not sure if the NewPlayer is null in the match flow when it calls RestartPlayer(AController* NewPlayer) yet.

either way, i found a workaround.

its hackish, but it has gotten me the functionality i wanted and if you haven’t found a solution yet, it should work for you as well. you seemz to got the skillz to do this just by description, but in case any n00bs find this post later, i will be explicit for posterity.

put this in your GameMode header:

            /** spawns default pawn for player*/
            	virtual APawn* SpawnDefaultPawnFor(AController* NewPlayer, class AActor* StartSpot) OVERRIDE;
        
    /** hack to select teamspawn, due to null controller passed to ChoosePlayerStart by engine*/
    	AActor* GetTeamStart(AYourPlayerController* Player);

then when you override it in your GameMode CPP, check it:

 APawn* AYourGameMode::SpawnDefaultPawnFor(AController* NewPlayer, class AActor* StartSpot)
    {
    //choose the player start location based on player start's PlayerStartTag
    FRotator StartRotation(ForceInit);
    FVector StartLocation;
    AActor* TeamStart;
    
    FActorSpawnParameters SpawnInfo;
    SpawnInfo.Instigator = Instigator;
    APawn* ResultPawn;
    
    //newplayer is not null here.
    AYourPlayerController* PCOwner = Cast<AYourPlayerController>(NewPlayer);
    // team information stored in playerstate.
    AYourPlayerState* PSOwner = CastChecked<AYourPlayerState>(NewPlayer->PlayerState);
    
    TeamStart = GetTeamStart(PCOwner);
    
    if(TeamStart == NULL) // if assignment failed, use default.
    {
    TeamStart = StartSpot;
    }
    
    StartRotation.Yaw = TeamStart->GetActorRotation.Yaw;
    StartLocation = TeamStart->GetActorLocation();
    
    ResultPawn = ()->SpawnActor<APawn>(GetDefaultPawnClassForController(NewPlayer), StartLocation, StartRotation, SpawnInfo);
    		return ResultPawn;
    }

and lastly, the GetTeamStart function, which populates the arrays with teamstarts based on their player start tag, which can be edited in the Unreal Editor by clicking on the player start in the viewport and changing the object in the “details” section that says “Player Start Tag”

   AActor* AYourGameMode::GetTeamStart(AYourPlayerController* Player)
    {
//Arrays to hold the starts for each team
TArray<APlayerStart*> Team1Starts;
TArray<APlayerStart*> Team2Starts;

        FString Team1STag = "Team1Start";
    	FString Team2STag = "Team2Start";
    	
    	FName Team1Tag = FName(*Team1STag);
    	FName Team2Tag = FName(*Team2STag);
    	
    	
    	for (int i = 0; i < PlayerStarts.Num(); i++)
    	{
    		if (PlayerStarts[i]->PlayerStartTag == Team1Tag)
    		{
    			Team1Starts.Add(PlayerStarts[i]);
    		}
    		else if (PlayerStarts[i]->PlayerStartTag == Team2Tag)
    		{
    			Team2Starts.Add(PlayerStarts[i]);
    		}
    	}
    
    	AActor* TeamStart = NULL;
    	if (Player)
    	{
    		AYourPlayerState* PState = CastChecked<AYourPlayerState>(Player->PlayerState);
    		if (PState)
    		{
    			if (PState->GetTeamNum() == 1)
    			{
    				TeamStart = Team1Starts[FMath::RandHelper(Team1Starts.Num())];
    			}
    			else if (PState->GetTeamNum() == 2)
    			{
    				TeamStart = Team2Starts[FMath::RandHelper(Team2Starts.Num())];
    			}
    		}
    	}
    
    	return TeamStart;
    }

of course, this assumes that you have already assigned your teams in your PlayerStates, and have added a “GetTeamNum()” function to them, hope this helps SOMEONE out at some point.i would love a more elegant solution to this.

Is not virtual to prevent override of generated code needed to use it in blueprint since version 4.8, as lot of GameMode functions was given BlueprintNativeEvent specifier and all functions with actual code of it need to be placed in function with *_Implementation surrfix, so in this case SpawnDefaultPawnFor_Implementation() and you do override here too

This compiled for you? Which engine version was this built with? Currently (UE 4.9), SpawnDefaultPawnFor() is not a virtual function and cannot be overridden in this manner.

Thank you, using this works perfectly:
virtual AActor* ChoosePlayerStart_Implementation(AController* Player) override;