How to keep Widgets on screen when using ServerTravel

Has anyone figured out where in source code widgets are removed when changing levels by calling ServerTravel, to remove that line/those lines in Unreal Engine 5.3.X / 5.4.X?

I tried looking around the code for ServerTravel but I couldn’t find the removal code.

I’m not sure to be correct, but it may give you some ideas:

To my understanding on non-seamless travel all non-root-set uobjects gets destroyed by garbage collector on travel, widgets included. But in case of seamless travel gc also happens, but iirc by some reason widgets are not removed in this case (or was i explicitely root them? idk).

So, something like either make seamless travel, either experiment with rooting some objects

Not sure if you mean that I should use seamless travel to keep widgets. If that is what you said, then with UE 5.3, Widgets are removed automatically with this type of travel as well. From want I read, their reason for removing them was that devs keep on having references from Level/World objects inside the Widgets, which would cause the game to crash when the Level/World changed.

I tried 5.4 preview, and this is still true, so this might be the new standard. I hope that they at least add an option in project settings to toggle if we want Widgets to be removed automatically, and if we uncheck that, to give a warning about the possible crash maybe.

Finding where the removal takes place would help, and I would take time and removing that with each UE version, but like I said, they should add an option in project settings, or even better to Game Mode, that way it is easier for devs to toggle it, maybe on some maps you want all widgets to be removed, on others maybe you don’t want?! And then it would be easy for the engine as it would look at that bool, if true then remove.

As a side note, if you create a Slate Widget in C++, that can be kept on the screen, and it is not removed as UMG Widgets are. The problem is that you have to make it in C++ and you don’t have the same easy control as you do with Blueprints.

I came up with a solution for this, but it does indeed require to change the source code of the game engine. The changes are easy to make but they do require to be added when you change version of the engine, from 5.3.2 to 5.4.0 for example. For this I added a toggle to “GameInstance”.

Here is a list with all the steps:

  1. Get the source code for the engine, if you know how to do it, you can skip this step
  • Go to Unreal Engine GitHub repository and change from release to the version you want, in my case was 5.3
  • After selecting the version click on “Code” then “Download ZIP”, and place it in a path that is less then 50 characters (that is what they recommend)
  • Unzip the archive and run “Setup.bat”. This will download the dependencies needed
  • After that is done, run “GenerateProjectFiles.bat” and when it completes, you have the source code and a usable C++ project
  1. Modify game engine
  • Open UE5.sln and go to “Solution / Engine / UE5 / Source / Runtime / Engine / Classes / Engine / GameInstance.h” and open it
  • Find “GENERATED_UCLASS_BODY()” that is inside “class UGameInstance : public UObject, public FExec”, and after it add:
public:
	/** Whether all widgets should be removed when the level/map/world is changed */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = General)
	uint32 bRemoveWidgets : 1;
  • Now go to “Solution / Engine / UE5 / Source / Runtime / UMG / Private / Blueprint / GameViewportSubsystem.cpp” and open it
  • Inside it find the function “void UGameViewportSubsystem::HandleRemoveWorld(UWorld* InWorld)” and encompass it’s content in this:
UGameInstance* gameInstance = InWorld->GetGameInstance();
bool removeWidgets = true;
if (gameInstance) {
	removeWidgets = gameInstance->bRemoveWidgets;
}

if (removeWidgets)
{
//Content of the function 
}
  1. Building the engine and the game
  • Check if “Development Editor” is selected and “Win64”. For me they were by default, but check it
  • After all the previews steps are done, right click on “UE5” from “Solution Explorer” inside “Engine” and choose build. This process will take a long time. I have a AMD 5950X and it takes around 30 min
  • Go where the source code is, and open “UnrealEditor.exe” from inside the folder “\Engine\Binaries\Win64”, and let it finish loading everything and the window to create a new project is opened. Now close that window, you only needed it to compile what it needs and to be visible by Epic for a next step
  • Now make a backup of the game just in case, if you haven’t done so already
  • Go to where the backup is and delete the following folders: “.vs”, “Binaries”, “Intermediate”, “Saved”; and the file “.vsconfig”
  • Right click on your “GameName.uproject” and select the version of engine you just built. It should look something like: “Source build at path”. This will also generate the project files
  • Now open “GameName.sln”, and go to “Build / Configuration Manager…” and in that list deselect UE5, and then “Build / Build Solution”. The first time you build your game after changing version of the engine, it will take longer, but after that it will take the same amount of time it did when using the game engine got from Epic Launcher
  1. Applying the change for the game
  • Now that you have the engine and the game compiled, open your game, and find your “CustomGameInstance” and look for “Remove Widgets” inside “Class Defaults”. Deselect it and compile the blueprint. If it is deselected already I recommend checking that box, compile, deselect and compile again
  • Now all widgets will be kept when “ServerTravel” is called. Don’t forget that before changing the level first call “Remove All Widgets” and after that create your Widget that you want to keep on the screen. If you don’t remove the widgets, you might have some that can cause problems because of the references they contain

//Edit: If you want per map control, you can add the toggle inside GameStateBase.