Trying to reference a pointer to a valid widget crashes the game (multiplayer)?

I’m trying to implement a “ready” system in a 2-person game. When one player clicks “ready” it checks if the other player has clicked “ready” yet, and if they have, it destroys the “ready” widget and starts the game.

I’m getting crashes that I just have no clue what to do with. It started when I tried calling this code in the player controller:

if (IsLocalPlayerController())
{
if (bDestroy)
{
if (IsValid(MatchSetup_PlacePieces)) // ← The widget getting destroyed.
{
// Destroy this widget.
MatchSetup_PlacePieces->RemoveFromParent();
}
}
}

This causes this crash:

UE4Editor_Kingdoms_0608!AMatch_PlayerController::CreatePlacePiecesWidget() [G:\My Drive\Projects\Kingdoms\Intermediate\Build\Win64\UE4Editor\Inc\Kingdoms\Match_PlayerController.gen.cpp:104]
UE4Editor_Kingdoms_0608!AMatch_PlayerState::OnRep_ReadyToPlay() [G:\My Drive\Projects\Kingdoms\Source\Kingdoms\Private\Framework\Match\Match_PlayerState.cpp:67]

But when I comment out the above code, I get the exact same crash report.

Here’s how my code works now: pressing the “ready” button in the MatchSetup_PlacePieces widget gets the widget’s owning player state and calls a server RPC called “SetReady”, which just changes a boolean variable in my player state class.

The boolean variable “bReady” has an OnRep function. That function gets the game state and calls a function there called CheckReadyToStart, which gets every player state in the “Players” array variable and returns true if all of their bReady variables are true.

If CheckReadyToStart returns true, then the OnRep function gets the player’s player controller class and calls a client RPC named CreatePlacePiecesWidget. This is the function I showed some of in the code at the beginning of the post. It takes a boolean parameter called bDestroy. I show what happens if the parameter is true, but if it’s false, the function creates the MatchSetup_PlacePieces widget and sets the MatchSetup_PlacePieces pointer variable to the created widget.

I’ve been stuck with these same crashes for days, and am really at a loss for what to do. Can someone please help me out?

Thanks in advance!

Hi ThatNerdFury,

I’d try setting a breakpoint in the code above that part and look at the reference and any other things that may be pertinent. Then I’d just step through one line at a time until it bombed.

I did that, but every time I playtest it, it seems like something different causes the crash. Yesteryday, just calling the (empty) function CreatePlacePiecesWidget was crashing the game. This morning, referencing the pointer crashed the game, but now, nothing crashes the game, but RemoveFromParent() simply doesn’t work. The widget remains on the screen, despite RemoveFromParent() being successfully called.

It can crash if the function is being called on a dead component. For example, if you are transitioning to a new level, the playerstate gets torn down; if you are calling a function on that playerstate after it has gotten torn down, it will crash.

Can you add some isValid’s on the component before calling your function and see if that solves your issue? If the component, or playerstate, is not valid, then don’t call any functions on it, because it is dead and gone anyway.

I already have some IsValids on the objects causing the crash, which is the “place pieces” widget. And it always says that the object is valid right before trying to destroy it, and then destroying it causes another crash. I have validity checks before using any casted objects, so exceptions for the player state, player controller, and game state are already handled and have no problem.

The weirdest part is that I’ve already done this entire widget creation and deletion thing in this project. Before the “ready” widget is created, a deck selection widget is created in the exact same way and destroyed in the same way after it’s clicked. Then when I try to do the same process for a different widget, it crashes the game.

That would definitely be frustrating. Something must be different. I made a ready system just recently and my method was the client calls a function on the server, the server then toggles ready, and returns to the client that the status has changed. The server then determines if all players are ready and if so, calls functions on the clients to proceed.
Feels like you have some kind of race condition causing your issue. I will be interested to hear the solution once you find it.

Not sure how bDestroy is set/reset. Is it a member variable?

Maybe the code attemps to destroy twice and you need to reset bDestroy e.g.

if (bDestroy)
{
	if (IsValid(MatchSetup_PlacePieces)) // ← The widget getting destroyed.
	{
		// Destroy this widget.
		MatchSetup_PlacePieces->RemoveFromParent();
	}
	bDestroy = false; // <-- new code
}