GameState's PlayerArray is NULL

I am trying to create a game mode, similar to Gears of War, where the match is played in rounds. Best 2 out of 3 wins. I am using the shootergame as a reference.

So initially each time a player dies I call a funtion call CheckTeamElimination(). This iterates over the player array and checks who is dead. If it finds that an entire team is dead, that round is over and very thing is reset using Super::RestartGame(); in my game mode class.

Everything up to this point works great! However during the second round, as soon as someone is killed. The game mode attempts to iterate over everyone as see who is dead and who is alive. However this time the PlayerArray is no NULL and I get an assertion failed. See below:

Anyone have any experience with this that could give me some pointers maybe?

Could you verify the size of the array in a debug build? It seams that the array is empty and you are trying to access a non existing index.

That is what I initially thought as well so I added this check:

if (GameState->PlayerArray.Num() > 0)
{
    //...
}

But it still throws the same error. So its acting like the PlayerArray is NULL so any operation you try and perform on it will throw and exception.

If PlayerArray where NULL you would get an access violation, where are you iterating through the array?

Hey Ky -

If you’re able to play the first round normally and then get this error in your second round, it sounds as though the array is being cleared between rounds and not being reinitialized at the start of the second round. Where in the code is the array being initialized before the first rounds starts? If you are able to run through debugging can you either add a breakpoint at the Super::RestartGame() call and step through the process from that point or pause the game after the first round ends (and the second starts) and check the status of the PlayerArray?

Cheers

Okay, so this is what Super::RestartGame() does:

void AGameMode::RestartGame()
{
	if ( GameSession->CanRestartGame() )
	{
		if (GetMatchState() == MatchState::LeavingMap)
		{
			return;
		}

		GetWorld()->ServerTravel("?Restart",GetTravelType());
	}
}

The above is engine code and I can’t change it. But it seems it is just doing a ServerTravel.

Now as for the PlayerArray is is initialized in Post Initialize Component of AGameState, which again is engine code:

void AGameState::PostInitializeComponents()
{
	Super::PostInitializeComponents();

	FTimerManager& TimerManager = GetWorldTimerManager();
	TimerManager.SetTimer(TimerHandle_DefaultTimer, this, &AGameState::DefaultTimer, 1.0f / GetWorldSettings()->GetEffectiveTimeDilation(), true);

	UWorld* World = GetWorld();
	World->GameState = this;

	if (World->IsGameWorld() && Role == ROLE_Authority)
	{
		UpdateServerTimeSeconds();
		if (ServerWorldTimeSecondsUpdateFrequency > 0.f)
		{
			TimerManager.SetTimer(TimerHandle_UpdateServerTimeSeconds, this, &AGameState::UpdateServerTimeSeconds, ServerWorldTimeSecondsUpdateFrequency, true);
		}
	}

	for (TActorIterator<APlayerState> It(World); It; ++It)
	{
		AddPlayerState(*It);
	}
}

I can’t figure out a way to step through this since when playing in editor RestartGame doesn’t seem to work, it only works in the stand alone version

You can create a packaged game in Debug mode for example, then run the game and attach to the process in VS. You will now be able to set a breakpoint and test it.

Would a link to my github repo work for you?

[link removed]

If this is inconvenient let me know and I will put everything in dropbox

Hey Ky -

I believe that the issue has to do with the PlayerArray being setup in the PostInitializeComponents() function as you mentioned and this not being updated after restarting the game. If possible could you send a copy of your project for me to test directly for additional information. The best way to do this would be to upload the project to Dropbox and then post a link for me to download the project. If privacy is a concern, instead of posting the link here you can send me a private message on the forums with the download link.

Cheers

Sorry I had to remove your link. Your repo contains content that is guarded by the EULA and so you can not put it on a public repo, to share you project and still be safe please follow the following guide:A new, community-hosted Unreal Engine Wiki - Announcements - Unreal Engine Forums . Please remove Epics content from the repo or make it private.

Sorry about that, I’ll be sure to take care of that! Thanks for the heads up.

Since there are some issues using the GitHub link it would be best if you could upload the project to dropbox and send me a private message on the forums with a link to download. Let me know here when you’ve had the chance to do so and I can take a look at the project.

I’ve downloaded the .zip file from the private message you sent me however I’m unable to open / unzip the folder onto my machine. If possible could you make a zip file of your local project and upload that?

If you are trying to make a Gears style round based game you should not be calling RestartGame() between rounds. That’s essentially destroying and creating a new game. Gears kept track of rounds using a GameState property. The GoalScore for the game was set to the number of rounds needed to win. Each time a round ended, the number of rounds won by each team was compared against the goal score to see if the match was ended. Once ended, the stats would be posted and then the game would transition to the next state. Player matches kept the group and moved to a new map. Ranked matches went back to matchmaking to find the next team.

That is really helpful thanks. I am still confused though, when a rounds ends how to I set the map, the players, weapons etc back to their default state?

Is there something built into the engine that could easily do this or do I have to write my own handler for this?

In this case you would want to look at using AGameMode::ResetLevel().

I played with this a bit, inside my MyGameMode I called super::ResetLevel(); it did everything great except it didn’t reset the players, they just became stuck and couldn’t move in the new “round”.

Hey Ky-

Let me know if the information on this page helps: Travelling in Multiplayer in Unreal Engine | Unreal Engine 5.1 Documentation

From my understanding you should be able to use UWorld::ServerTravel to have the server (and all clients) travel to the same map they are currently on which should effectively restart the map. I’ve also found that the console command “RestartLevel” works to position players and actors back to their starting location. I’ve not found this in code however you can use the “Execute Console Command” Bp node instead.

Cheers

1 Like