Why does my client's UMG Widget disappear when connecting to listen server ?

Hi everyone,

What is actually happening when both the server and the client create and AddToViewport() their own UMG Widget ?

My issue right now is that when the client connects to the server, the client widget appears for a couple of frame then disappear. If I close the server, the client widget appears again.

So it looks like the client actually also try to display the server widget which doesn’t exist on the client, and it ends up with a black screen.

So here are couple of questions:

  • Does AHUD is replicated between server and client ? According the link of the last question, NO.
  • Do AddToViewport() add the widget for everyone (client + server) ?
  • In which class widgets should be created and handled when they are specific to only one executable ? According the link of the last question, AHUD.
  • And finally, where the hell can I find everything about what is and is not replicated by default over the network with UE4 ?! An overview here

Best regards.

EDIT: No, I’m not testing it from the editor. I’m testing this using two different executable.

It seems like when you connect to the server, your client gets a call to remove the widget. When you close the server, the client is then kicked out and reloads thus creating the widget again just like if you started the game.

In regards to the other questions, as far as I know AHUD in the PlayerController is not replicated. (In PlayerController.h, AHUD only has a default UPROPERTY(), no sign of replication. Unless your AHUD belongs to something else, then I’m not sure, and will look into the source code for that. But the chances of AHUD being replicated is low, as it doesn’t make sense.

AddToViewport() seems to add the widget for everyone. If I’m not mistaken because I just had an issue with it. If the server tell its PlayerController that is for a client to AddToViewport, and then the client also does a AddToViewport, the result is two widgets for the client. Don’t quote me on this, but that’s what happened from what I remember, and I had to add a check on server side to check if the PlayerController was local before calling the bunch of code that setup the widgets for the PlayerController.

As to finding where everything can be replicated, seems like the best option as of now is to look to the source code and see if it has a replicated property to it.

Thanks for your feedback ! I set my HUD class using the default value in the game mode. Am I wrong doing this ?

I’ve tested something even simpler. Only the client calls AddToViewport(). The widget sill disappears after connecting to the listen server.

The WhatTheFuckNess is real here. My EventInit is called only once on the client which means that there is only one instance of my AHUD class (which is the correct behavior, no replication).

I also force the visibility to ESlateVisibility::Visible, and I’m 100% sure I don’t remove the widget anywhere else in the code.

So why the hell is my client widget disappearing ?

I finally decided to handle menus in a GameInstance cause there, I’m sure I will have only ONE instance by executable. I’m handling menu states changes in a GameState class.

All right so here is how I fixed it for people who are interested in.

  • The first thing to notice is that when you will run the client executable, it will first create bunch of temporary classes while waiting to be connected to the server. That means, for a moment, the client will behave like a “standalone” single player game.That means, it will have the ROLE_Authority and so on until it get connected to the server.
    Correct me if I’m wrong about this.

  • So first, while being in this “temporary” state, my client creates some widgets. Then the connection with the server occurs and I think most of classes are reseted to their “network/connected” state. That involve destruction of objects instances and construction again.
    That could explain why my widget disappear when I connect to the server, and reappears again when disconnecting.

Actual Solution

SO, to solve this issue, I implemented the function MyGameMode::PostLogin() in which I call clients RPCs to tell them “You are connected, you can now safely create what you need”.

Here is the full function

///////////////////////////////////////////////////////////////////////////////
void AMode_Base::PostLogin(APlayerController * NewPlayer)
{
	Super::PostLogin(NewPlayer);

	UGameInstance_Base* GameInstance = Cast<UGameInstance_Base>(GetWorld()->GetGameInstance());
    // This code is only executed on the server side
    // Some peole would say "Wait, GameMode only exists on servers". Yes! But during the short time the client is still connecting to the server, the client behave like a standalone game so it will have a GameMode too !
	if (GameInstance && GameInstance->ExecutableType == EPoliceExecutableType::POLICE_EXEC_SERVER)
	{
		AController_Base* Controller = Cast<AController_Base>(NewPlayer);
		if (Controller)
		{
			// Call client's RPC
			Controller->ShowMenu();
		}
	}
}

I would love to hear some feedbacks about this post cause I think it’s an important concept to understand to get into Unreal Network stuff.

Best regards.

Creating widget stuff after PostLogin sounds right.

Not sure about the whole temporary thing. I know that when you launch the game, you have a GameMode, but once you connect to the server, specifically when the Server’s GameMode does PostLogin, the client will definitely not have a GameMode. I wouldn’t exactly call it temporary, just that is acts as a standalone. The game can not be considered a client until it is connecting or connected to the server in my opinion.

Thus your if statement for checking GameInstance doesn’t seem necessary for checking if it’s a server, since client will never have a GameMode in PostLogin, and even before that, since that ruins the whole point of GameMode being server-side only.

Unless the ClientTravel is SeamlessTravel I’m pretty sure everything gets trashed including the widgets. (Except for GameInstance stuff, which I would assume is used to handle things related to the Instance of the game, such as keybind settings.)

I hope your previous issue, wasn’t the fact that you never created the widget after connecting to the server. Since I already assumed you created the widget after you confirmed the client has connected, and then it was disappearing for you for some reason. Thus seeing your “solution” came as a surprise for me, as I assumed that was something you had already done.

Thanks for your feedback.
The official documentation lacks so hard of this kind of explanation. Or am I missing something ?

And no. I’m a fully newbie of Unreal Engine haha. But my formation teaches me how to find your own way whatever is your problem !

Yeah, the documentation can be quite lacking at certain areas. As far as I’m aware, the documentation doesn’t talk about connecting to a server. Only thing I’ve found that is most related is traveling in multiplayer, but that’s for clientTravel that occurs when a client is already connected to a server.

I mostly read through the Engine’s source code to figure how it works. Thankfully the tricky areas in the Engine do have some good comments in them. So that helps in understanding how some specific niche part of the Engine works.

EDIT: Actually this is much more related Client-Server Model | Unreal Engine Documentation

I got the same issue a few days ago. And I solved it by implement this to show the widget again after joining the game.

In AMyPlayerController.h :

void ChangeMenuWidget(TSubclassOf<UUserWidget> NewWidgetClass);
TSubclassOf<UUserWidget> StartingWidgetClass;
bool bIsPlayerFirstTick = true;
AMyGameState* MyGameState = nullptr;

In AMyPlayerController.cpp :

void AMyPlayerController::PlayerTick(float DeltaTime)
{
	Super::PlayerTick(DeltaTime);

	//** This will run for the first tick on the server/standalone
	if (bIsPlayerFirstTick && Role == ROLE_Authority)
	{
		//** My function to show the UMG widget
		ChangeMenuWidget(StartingWidgetClass);
		bIsPlayerFirstTick = false;
	}

	//** This will run on the client and check whether the game state is ready
	if (MyGameState == nullptr && Role < ROLE_Authority)
	{
		MyGameState = (GetWorld() != nullptr ? GetWorld()->GetGameState<AMyGameState>() : nullptr);
		if (MyGameState)
		{
			//** My function to show the UMG widget
			ChangeMenuWidget(StartingWidgetClass);
		}
	}
}

Thank you so much for that solution. Based on that and my own investigations, I found that the AHUD is created after the PostLogin call. So I just create my HUD widget blueprints on BeginPlay of my HUD actor, which I find a lot more intuitive and does not require an additional replicated function call. Plus the HUD is always local to it’s PlayerController, so there is no need to check for remote roles or anything like that.

To make sure the Widget is destroyed, when the HUD is destroyed, simply call Destroy on the Widget, on Destroyed and on EndPlay of your HUD class.