I am using world partition for a pretty large map. When I change level from the main menu to the game map using WP you can see a number of the non-spacially loaded assets in the map as it loads the rest of the scene, and then the rest of the world pops into existence.
This behaviour is obviously undesirable and I would like to hide it behind a loading screen. The trouble is, when I create a widget at begin play for the WP level it doesn’t cover up the issue until the rest of the world is loaded in any way. And using the old method of having sublevels that load in the map will the engine and the build every time.
Is there an easy way to keep the screen black or display a widget to cover up the loading in the background?
I’ve switched my game map to World Partition and noticed this issue today.
Previously, my loading screen covered up nicely if I transition from regular level to another regular level, however, if I transition from regular level to World Partition level, there is a small window where the loading screen couldn’t detect any meaningful status to keep showing and thus hidden for a split second.
Below is the code I used for checking - mainly copied from Lyra project:
// Start out with 'unknown' reason in case someone forgets to put a reason when changing this in the future.
DebugReasonForShowingOrHidingLoadingScreen = TEXT("Reason for Showing/Hiding LoadingScreen is unknown!");
const UGameInstance* LocalGameInstance = GetGameInstance();
if (LoadingScreenCVars::ForceLoadingScreenVisible)
{
DebugReasonForShowingOrHidingLoadingScreen = FString(TEXT("CommonLoadingScreen.AlwaysShow is true"));
return true;
}
const FWorldContext* Context = LocalGameInstance->GetWorldContext();
if (Context == nullptr)
{
// We don't have a world context right now... better show a loading screen
DebugReasonForShowingOrHidingLoadingScreen = FString(TEXT("The game instance has a null WorldContext"));
return true;
}
UWorld* World = Context->World();
if (World == nullptr)
{
DebugReasonForShowingOrHidingLoadingScreen = FString(TEXT("We have no world (FWorldContext's World() is null)"));
return true;
}
AGameStateBase* GameState = World->GetGameState<AGameStateBase>();
if (GameState == nullptr)
{
// The game state has not yet replicated.
DebugReasonForShowingOrHidingLoadingScreen = FString(TEXT("GameState hasn't yet replicated (it's null)"));
return true;
}
if (bCurrentlyInLoadMap)
{
// Show a loading screen if we are in LoadMap
DebugReasonForShowingOrHidingLoadingScreen = FString(TEXT("bCurrentlyInLoadMap is true"));
return true;
}
if (!Context->TravelURL.IsEmpty())
{
// Show a loading screen when pending travel
DebugReasonForShowingOrHidingLoadingScreen = FString(TEXT("We have pending travel (the TravelURL is not empty)"));
return true;
}
if (Context->PendingNetGame != nullptr)
{
// Connecting to another server
DebugReasonForShowingOrHidingLoadingScreen = FString(TEXT("We are connecting to another server (PendingNetGame != nullptr)"));
return true;
}
if (!World->HasBegunPlay())
{
DebugReasonForShowingOrHidingLoadingScreen = FString(TEXT("World hasn't begun play"));
return true;
}
if (World->IsInSeamlessTravel())
{
// Show a loading screen during seamless travel
DebugReasonForShowingOrHidingLoadingScreen = FString(TEXT("We are in seamless travel"));
return true;
}
// Ask the game state if it needs a loading screen
if (ILoadingProcessInterface::ShouldShowLoadingScreen(GameState, /*out*/ DebugReasonForShowingOrHidingLoadingScreen, /*out*/ bLoadingScreenInstant))
{
return true;
}
// Ask any game state components if they need a loading screen
for (UActorComponent* TestComponent : GameState->GetComponents())
{
if (ILoadingProcessInterface::ShouldShowLoadingScreen(TestComponent, /*out*/ DebugReasonForShowingOrHidingLoadingScreen, /*out*/ bLoadingScreenInstant))
{
return true;
}
}
// 2023/09/29 myw ADD: Ask all the game mode components if they need a loading screen, ex: UFTExperienceManagerComponent
AGameModeBase* GameMode = World->GetAuthGameMode<AGameModeBase>();
if (GameMode)
{
for (UActorComponent* TestComponent : GameMode->GetComponents())
{
if (ILoadingProcessInterface::ShouldShowLoadingScreen(TestComponent, /*out*/ DebugReasonForShowingOrHidingLoadingScreen, /*out*/ bLoadingScreenInstant))
{
return true;
}
}
}
Does anyone have ideas on how to solve or circumvent this issue?
Thank you!
I want to share a solution I came up with. It’s far from perfect, but it might be a useful starting point for someone.
The core idea is to preload assets related to a level. The process looks roughly like this: scan the contents of the target level > gather dependencies > load resources > launch the level.
However, this approach has its caveats:
World Partition levels can include a huge number of assets and resources.
Possible solutions:
Split the level into smaller parts and stream the remaining content separately.
Use PrimaryAssetLabel to load a specific subset of assets, and let the default system handle the rest.
Even after the level is loaded, streaming may still be ongoing, so you’ll need to additionally check the streaming status.
Here’s a link to the repository: https://github.com/Pavreally/LevelProgressTracker
It’s where I tried to implement this subsystem — maybe it’ll be helpful to someone or spark some ideas for a better solution.
Unbelievable,two years past,this issue still exist.When loading wp map from an normal map,there are some blur images and non-spacially loaded assets ,very bad