Now that we are in 2025, and still noone has suggested this - I will post an alternative solution - C++ only - which works super nice, and imo better than the listed ideas:
By browsing UEngine::LoadMap() I came across some interesting code sections, and it turns out there’s a built-in movie player, which has all the support I needed for my project. It can show a single widget, or even iteration through a list of movies, and it can automatically hide the loading screen after map load is complete - so manually keeping track of when new map is finished loading is not necessary. Here’s the barebones of a custom GameInstance Subsystem to handle it:
#include "MoviePlayer.h"
[...]
void UMy_LoadingScreenSubsystem::ShowLoadingScreen()
{
FLoadingScreenAttributes Attributes;
Attributes.MinimumLoadingScreenDisplayTime = 1.0f;
Attributes.bAutoCompleteWhenLoadingCompletes = false;
// MyWidgetClass is TSubclassOf<UUserWidget>
auto MyWidget = CreateWidget(GetGameInstance(), MyWidgetClass);
Attributes.WidgetLoadingScreen = MyWidget->TakeWidget();
IGameMoviePlayer* MoviePlayer = GetMoviePlayer();
MoviePlayer->SetupLoadingScreen(Attributes);
}
This is so much nicer, and was primarily motivated by code I saw inside UEngine::LoadMap():
// Display loading screen.
// Check if a loading movie is playing. If so it is not safe to redraw the viewport due to potential race conditions with font rendering
bool bIsDesktopLoadingMovieCurrentlyPlaying =
FCoreDelegates::IsLoadingMovieCurrentlyPlaying.IsBound() ?
FCoreDelegates::IsLoadingMovieCurrentlyPlaying.Execute() : false;
[...]
if(!bIsDesktopLoadingMovieCurrentlyPlaying && !bIsXRLoadingMovieCurrentlyPlaying)
{
LoadMapRedrawViewports();
}
I think the comment says it all. Without really diving deeper into WHY inside how FreeType2 is used for rendering fonts, or double acquired swapchain images, I can see the point of not redrawing the viewport while a loading screen is shown - and the system is easy to extend to movie playing as well. ![]()
You will need to add a module dependency to "MoviePlayer" inside project Build.cs file.
It may also be necessary to store the created UUserWidget as a UPROPERTY, to prevent garbage collection. I’m not 100% sure right now.
It’s necessary to delay the loading screen a bit until FCoreUObjectDelegates::PreLoadMap if doing client travel and playing a movie loading screen, otherwise the game will crash.