struct FStreamable* FStreamableManager::StreamInternal(FStringAssetReference const& InTargetName) { check(IsInGameThread()); UE_LOG(LogStreamableManager, Verbose, TEXT("Asynchronous load %s"), *InTargetName.AssetLongPathname); if (FPackageName::IsShortPackageName(InTargetName.AssetLongPathname)) { UE_LOG(LogStreamableManager, Error, TEXT(" Can't load invalid package name %s"), *InTargetName.AssetLongPathname); return NULL; } FStringAssetReference TargetName = ResolveRedirects(InTargetName); FStreamable* Existing = StreamableItems.FindRef(TargetName); if (Existing) { if (Existing->bAsyncUnloadRequestOutstanding) { // It's valid to have a live pointer if an async loaded object was hard referenced later check(!Existing->bAsyncLoadRequestOutstanding); // we should not be both loading and unloading UE_LOG(LogStreamableManager, Verbose, TEXT(" Aborted unload for %s"), *TargetName.AssetLongPathname); Existing->bAsyncUnloadRequestOutstanding = false; check(Existing->Target || Existing->bLoadFailed); // should not be an unload request unless the target is valid return Existing; } if (Existing->bAsyncLoadRequestOutstanding) { UE_LOG(LogStreamableManager, Verbose, TEXT(" Already in progress %s"), *TargetName.AssetLongPathname); check(!Existing->bAsyncUnloadRequestOutstanding); // we should not be both loading and unloading check(!Existing->Target); // should not be an load request unless the target is invalid return Existing; // already have one in process } if (Existing->Target) { UE_LOG(LogStreamableManager, Verbose, TEXT(" Already Loaded %s"), *TargetName.AssetLongPathname); return Existing; } } else { Existing = StreamableItems.Add(TargetName, new FStreamable()); } FindInMemory(TargetName, Existing); if (!Existing->Target) { FString Package = TargetName.AssetLongPathname; int32 FirstDot = Package.Find(TEXT(".")); if (FirstDot != INDEX_NONE) { Package = Package.Left(FirstDot); } Existing->bAsyncLoadRequestOutstanding = true; LoadPackageAsync(Package, FLoadPackageAsyncDelegate::CreateStatic(&AsyncLoadCallbackWrapper, new FCallback(TargetName, this)) ); } return Existing; }
void USoundNodeModPlayer::LoadAsset() { if (IsAsyncLoading()) { SoundMod = SoundModAssetPtr.Get(); if (SoundMod == nullptr) { LoadPackageAsync(SoundModAssetPtr.GetLongPackageName(), FLoadPackageAsyncDelegate::CreateUObject(this, &USoundNodeModPlayer::OnSoundModLoaded)); } } else { SoundMod = SoundModAssetPtr.LoadSynchronous(); } }
void FWorldTileModel::LoadLevel() { // Level is currently loading or has been loaded already if (bLoadingLevel || LoadedLevel.IsValid()) { return; } // stream in this level bLoadingLevel = true; ULevel::StreamedLevelsOwningWorld.Add(TileDetails->PackageName, LevelCollectionModel.GetWorld()); LoadPackageAsync(*TileDetails->PackageName.ToString(), FLoadPackageAsyncDelegate::CreateSP(this, &FWorldTileModel::AsyncLevelLoadComplete) ); }
void USoundNodeWavePlayer::LoadAsset() { if (IsAsyncLoading()) { SoundWave = SoundWaveAssetPtr.Get(); if (SoundWave == nullptr) { const FString LongPackageName = SoundWaveAssetPtr.GetLongPackageName(); if (!LongPackageName.IsEmpty()) { LoadPackageAsync(LongPackageName, FLoadPackageAsyncDelegate::CreateUObject(this, &USoundNodeWavePlayer::OnSoundWaveLoaded)); } } } else { SoundWave = SoundWaveAssetPtr.LoadSynchronous(); } }
bool ULevelStreaming::RequestLevel(UWorld* PersistentWorld, bool bAllowLevelLoadRequests, bool bBlockOnLoad) { // Quit early in case load request already issued if (bHasLoadRequestPending) { return true; } // Previous attempts have failed, no reason to try again if (bFailedToLoad) { return false; } QUICK_SCOPE_CYCLE_COUNTER(STAT_ULevelStreaming_RequestLevel); FScopeCycleCounterUObject Context(PersistentWorld); // Package name we want to load FName DesiredPackageName = PersistentWorld->IsGameWorld() ? GetLODPackageName() : GetWorldAssetPackageFName(); FName DesiredPackageNameToLoad = PersistentWorld->IsGameWorld() ? GetLODPackageNameToLoad() : PackageNameToLoad; // Check if currently loaded level is what we want right now if (LoadedLevel != NULL && LoadedLevel->GetOutermost()->GetFName() == DesiredPackageName) { return true; } // Can not load new level now, there is still level pending unload if (PendingUnloadLevel != NULL) { return false; } // Try to find the [to be] loaded package. UPackage* LevelPackage = (UPackage*) StaticFindObjectFast(UPackage::StaticClass(), NULL, DesiredPackageName, 0, 0, RF_PendingKill); // Package is already or still loaded. if (LevelPackage) { // Find world object and use its PersistentLevel pointer. UWorld* World = UWorld::FindWorldInPackage(LevelPackage); // Check for a redirector. Follow it, if found. if ( !World ) { World = UWorld::FollowWorldRedirectorInPackage(LevelPackage); if ( World ) { LevelPackage = World->GetOutermost(); } } if (World != NULL) { #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if (World->PersistentLevel == NULL) { UE_LOG(LogLevelStreaming, Log, TEXT("World exists but PersistentLevel doesn't for %s, most likely caused by reference to world of unloaded level and GC setting reference to NULL while keeping world object"), *World->GetOutermost()->GetName()); // print out some debug information... StaticExec(World, *FString::Printf(TEXT("OBJ REFS CLASS=WORLD NAME=%s shortest"), *World->GetPathName())); TMap<UObject*,UProperty*> Route = FArchiveTraceRoute::FindShortestRootPath( World, true, GARBAGE_COLLECTION_KEEPFLAGS ); FString ErrorString = FArchiveTraceRoute::PrintRootPath( Route, World ); UE_LOG(LogLevelStreaming, Log, TEXT("%s"), *ErrorString); // before asserting checkf(World->PersistentLevel,TEXT("Most likely caused by reference to world of unloaded level and GC setting reference to NULL while keeping world object")); return false; } #endif if (World->PersistentLevel != LoadedLevel) { SetLoadedLevel(World->PersistentLevel); // Broadcast level loaded event to blueprints OnLevelLoaded.Broadcast(this); } return true; } } EPackageFlags PackageFlags = PKG_None; int32 PIEInstanceID = INDEX_NONE; // copy streaming level on demand if we are in PIE // (the world is already loaded for the editor, just find it and copy it) if ( PersistentWorld->IsPlayInEditor() ) { #if WITH_EDITOR if (PersistentWorld->GetOutermost()->HasAnyPackageFlags(PKG_PlayInEditor)) { PackageFlags |= PKG_PlayInEditor; } PIEInstanceID = PersistentWorld->GetOutermost()->PIEInstanceID; #endif const FString NonPrefixedLevelName = UWorld::StripPIEPrefixFromPackageName(DesiredPackageName.ToString(), PersistentWorld->StreamingLevelsPrefix); UPackage* EditorLevelPackage = FindObjectFast<UPackage>(nullptr, FName(*NonPrefixedLevelName)); bool bShouldDuplicate = EditorLevelPackage && (bBlockOnLoad || EditorLevelPackage->IsDirty() || !GEngine->PreferToStreamLevelsInPIE()); if (bShouldDuplicate) { // Do the duplication UWorld* PIELevelWorld = UWorld::DuplicateWorldForPIE(NonPrefixedLevelName, PersistentWorld); if (PIELevelWorld) { PIELevelWorld->PersistentLevel->bAlreadyMovedActors = true; // As we have duplicated the world, the actors will already have been transformed check(PendingUnloadLevel == NULL); SetLoadedLevel(PIELevelWorld->PersistentLevel); // Broadcast level loaded event to blueprints { QUICK_SCOPE_CYCLE_COUNTER(STAT_OnLevelLoaded_Broadcast); OnLevelLoaded.Broadcast(this); } return true; } else if (PersistentWorld->WorldComposition == NULL) // In world composition streaming levels are not loaded by default { if ( bAllowLevelLoadRequests ) { UE_LOG(LogLevelStreaming, Log, TEXT("World to duplicate for PIE '%s' not found. Attempting load."), *NonPrefixedLevelName); } else { UE_LOG(LogLevelStreaming, Warning, TEXT("Unable to duplicate PIE World: '%s'"), *NonPrefixedLevelName); } } } } // Async load package if world object couldn't be found and we are allowed to request a load. if (bAllowLevelLoadRequests) { FString PackageNameToLoadFrom = DesiredPackageName.ToString(); if (DesiredPackageNameToLoad != NAME_None) { PackageNameToLoadFrom = DesiredPackageNameToLoad.ToString(); } if (GUseSeekFreeLoading) { // Only load localized package if it exists as async package loading doesn't handle errors gracefully. FString LocalizedPackageName = PackageNameToLoadFrom + LOCALIZED_SEEKFREE_SUFFIX; FString LocalizedFileName; if (FPackageName::DoesPackageExist(LocalizedPackageName, NULL, &LocalizedFileName)) { // Load localized part of level first in case it exists. We don't need to worry about GC or completion // callback as we always kick off another async IO for the level below. LoadPackageAsync(*(GetWorldAssetPackageName() + LOCALIZED_SEEKFREE_SUFFIX), nullptr, *LocalizedPackageName, FLoadPackageAsyncDelegate(), PackageFlags, PIEInstanceID); } } if (FPackageName::DoesPackageExist(PackageNameToLoadFrom, NULL, NULL)) { bHasLoadRequestPending = true; ULevel::StreamedLevelsOwningWorld.Add(DesiredPackageName, PersistentWorld); UWorld::WorldTypePreLoadMap.FindOrAdd(DesiredPackageName) = PersistentWorld->WorldType; // Kick off async load request. STAT_ADD_CUSTOMMESSAGE_NAME( STAT_NamedMarker, *(FString( TEXT( "RequestLevel - " ) + DesiredPackageName.ToString() )) ); LoadPackageAsync(DesiredPackageName.ToString(), nullptr, *PackageNameToLoadFrom, FLoadPackageAsyncDelegate::CreateUObject(this, &ULevelStreaming::AsyncLevelLoadComplete), PackageFlags, PIEInstanceID); // streamingServer: server loads everything? // Editor immediately blocks on load and we also block if background level streaming is disabled. if (bBlockOnLoad || ShouldBeAlwaysLoaded()) { // Finish all async loading. FlushAsyncLoading(); } } else { UE_LOG(LogStreaming, Error,TEXT("Couldn't find file for package %s."), *PackageNameToLoadFrom); bFailedToLoad = true; return false; } } return true; }