When/Where is it safe to create GUI [multiplayer]?

Where/when is it safe to create the GUI (widgets) in multiplayer for both dedicated and non-dedicated games? So far I was able to find this solution (it works) but it’s hacky and OnRep_Pawn() is called more than once for clients, so not very ideal.

// Is called at least once for every client but is NOT called for a non-dedicated-server
void MyAwesome_Controller::OnRep_Pawn()
{
	Super::OnRep_Pawn();
	AttemptToCreateGUI();
}

void MyAwesome_Controller::Possess(APawn* InPawn)
{
	Super::Possess(InPawn);
	// A client whom is also the server (so not dedicated), will never execute OnRep_Pawn(). Therefor we must create it's GUI here. And because it is the host machine, it will already have it's Pawn and such so we can call it here.
	if (GetNetMode() == ENetMode::NM_Standalone)	{ AttemptToCreateGUI(); }
}

So where is the function that I need to override (or event) where I can create my GUI-widgets knowing 100% sure (to prevent nullptr crashes) that the Pawn&PlayerController for that player have been created and that the player successfully logged in?

Do it where you feel it is appropriate. You just want to use IsLocallyControlled() in an if-statement to be sure the HUD code will only run on the owning client. With that and a few other functions, you can put role-specific code in places that run on all roles (i.e. HasAuthority()).

I can’t just do it where I feel it is appropriate because you have to be 100% sure that everything required is already replicated and not null. For example, I found out that even in the Possess() function, the GetPawn might still return a nullptr in some cases. But a non-dedicated-host does not get a replicated pawn and thus must have it’s code somewhere else. Took me some time to figure this out.

But I am hoping for a single safe method somewhere to override where I can just say:

if (IsLocallyControlled()) { CreateGUI(); }

What’s wrong with BeginPlay in the player pawn/character?

You could just create the widgets in the player controlller code. When each player logs in it will execute the code on that specific player.

Because the BeginPlay() of APawn does not guarantee the Player being logged/it’s controller being not null. My guess is that they are created more or less simultaneously and thus one creation does not guarantee the creation of the other. Sometimes even the this keyword returns a nullptr.

So I was hoping that there is some function that I missed that guarantees everything to be spawned and ready + the owner being fully connected/logged in so I can do my own stuff there, 100% safely.

My code is already in the player-controller.

Ok, how are you handling the login? I dont have much experience with c++ in unreal but i have alot with bp multiplayer. Are you using an event called “event post login” or does it work differently in c++ projects?

Not sure what problem you are seeing but BeginPlay in a networked game will not be called until the actor has been spawned into the world. By default, this happens after login. If you’re overriding something then that may not be the case anymore, but I count on BeginPlay happening after the player is fully set up. I’ve never had a problem. And the controller is always there too – where it’s supposed to be at least. Obviously you don’t get controllers on the non-owning clients. But if you use IsLocallyControlled() you can avoid using the controller when you shouldn’t.

The only time “this” could be NULL is when the function is called with a null pointer, so it’s not the function that’s the problem, it’s what is calling the function. Sounds like you have a different problem than you think, but it’s hard to tell.