Hi ^^ノシ
I’m trying to asynchronously load a level using LoadPackageAsync(). Simply using OpenLevel() freezes the game for about 10 seconds. The level has lots of static mesh actors placed inside (around 17k) which I believe is the reason it takes so long to load. I tried async loading it with this code:
void UCustomGameInstance::PostLevelLoadProcess(FName const& PackageName, UPackage* LoadedPackage, EAsyncLoadingResult::Type Result)
{
// Prevent Garbage collector from deleting loaded package and world
PackageBeingLoaded = LoadedPackage;
WorldBeingLoaded = UWorld::FindWorldInPackage(LoadedPackage);
if (AfterLoadPreHeatDuration > 0)
{
FTimerHandle TimerHandle;
GetWorld()->GetTimerManager().SetTimer(TimerHandle, [this, PackageName]()
{
// Loading level PreLevelChangeDispatch
if(AAdvancedBaseGameMode* GameMode = Cast<AAdvancedBaseGameMode>(GetWorld()->GetAuthGameMode()))
{
GameMode->PreLevelChangeDispatch();
}
// Reset Defaults
AfterLoadPreHeatDuration = 0.f;
bAbsoluteLoad = true;
LoadOptions = FString(L"");
// Open loaded level
UGameplayStatics::OpenLevel(GetWorld(), WorldBeingLoaded->GetFName(), bAbsoluteLoad, LoadOptions);
}, AfterLoadPreHeatDuration, false);
}
else
{
// Loading level PreLevelChangeDispatch
if(AAdvancedBaseGameMode* GameMode = Cast<AAdvancedBaseGameMode>(GetWorld()->GetAuthGameMode()))
{
GameMode->PreLevelChangeDispatch();
}
// Reset Defaults
AfterLoadPreHeatDuration = 0.f;
bAbsoluteLoad = true;
LoadOptions = FString(L"");
// Open loaded level
UGameplayStatics::OpenLevel(this, PackageName, bAbsoluteLoad, LoadOptions);
}
}
void UCustomGameInstance::PostLoadedLevelInitialization(UWorld* LoadedWorld, UWorld::InitializationValues InitializationValues)
{
// Loaded World should be the same as the pointer we saved unless its the loading level or first game open
if (LoadedWorld == WorldBeingLoaded)
{
WorldBeingLoaded = nullptr;
PackageBeingLoaded = nullptr;
}
}
void UCustomGameInstance::ChangeMainLevelAsync(const FString& InLevelName, float PreHeatDuration, bool bAbsolute, FString Options)
{
if(AAdvancedBaseGameMode* GameMode = Cast<AAdvancedBaseGameMode>(GetWorld()->GetAuthGameMode()))
{
GameMode->PreLevelChangeDispatch();
}
// Change load properties
AfterLoadPreHeatDuration = PreHeatDuration;
bAbsoluteLoad = bAbsolute;
LoadOptions = Options;
// Open loading level
UGameplayStatics::OpenLevel(this, Levels::LoadingLevelFullName, bAbsolute, Options);
// Load target level asynchronously
LoadPackageAsync(InLevelName, FLoadPackageAsyncDelegate::CreateLambda([this](FName const& PackageName, UPackage* LoadedPackage, EAsyncLoadingResult::Type Result)
{
if (Result == EAsyncLoadingResult::Succeeded)
{
PostLevelLoadProcess(PackageName, LoadedPackage, Result);
}
else
{
UE_LOG(LogTemp, Error, TEXT("Failed to load level: %s"), *PackageName.ToString());
}
}),0 , PKG_ContainsMap);
}
void UCustomGameInstance::Init()
{
Super::Init();
FWorldDelegates::OnPostWorldInitialization.AddUObject(this, &UCustomGameInstance::PostLoadedLevelInitialization);
}
Now the problem is PostLevelLoadProcess() gets called almost instantly after the LoadPackageAsync() but when I open level the game goes on 10 seconds freeze again. I save pointers from the Uworld and UPackage of the loaded package to prevent them from being garbage collected before openLevel getting called but when I checked the pointer for the opened world inside the PostLoadedLevelInitialization() it is different from the UWorld pointer I saved O.o I even went as far as checking if the saved pointer using ISValid ( thinking maybe the world from the package got moved under the hood? not sure if moving will make the result of IsValid false, have to try it later) and the original pointer is still valid. Can anyone please explain what is going on here? I also found this inside logs
LogStreaming: Display: FlushAsyncLoading(): 0 QueuedPackages, 1 AsyncPackages
LogStreaming: Display: FlushAsyncLoading(): 16284 QueuedPackages, 0 AsyncPackages
Is LoadPackageAsync simply loading level without any of it’s placed actors and then openLevel can’t use it because of that? Any help is appreciated here…