// // Empty the loaders. // void ResetLoaders( UObject* InPkg ) { // Make sure we're not in the middle of loading something in the background. FlushAsyncLoading(); // Top level package to reset loaders for. UObject* TopLevelPackage = InPkg ? InPkg->GetOutermost() : NULL; // Find loader/ linker associated with toplevel package. We do this upfront as Detach resets LinkerRoot. if( TopLevelPackage ) { // Linker to reset/ detach. ULinkerLoad* LinkerToReset = ULinkerLoad::FindExistingLinkerForPackage(CastChecked<UPackage>(TopLevelPackage)); if ( LinkerToReset ) { for (TMap<UPackage*, ULinkerLoad*>::TIterator It(GObjLoaders); It; ++It) { ULinkerLoad* Linker = It.Value(); // Detach LinkerToReset from other linker's import table. if( Linker->LinkerRoot != TopLevelPackage ) { for( int32 j=0; j<Linker->ImportMap.Num(); j++ ) { if( Linker->ImportMap[j].SourceLinker == LinkerToReset ) { Linker->ImportMap[j].SourceLinker = NULL; Linker->ImportMap[j].SourceIndex = INDEX_NONE; } } } else { check(Linker == LinkerToReset); } } // Detach linker, also removes from array and sets LinkerRoot to NULL. LinkerToReset->Detach(true); } } else { TArray<ULinkerLoad *> LinkersToDetach; GObjLoaders.GenerateValueArray(LinkersToDetach); for (int32 Index = 0; Index < LinkersToDetach.Num(); Index++) { ULinkerLoad* Linker = LinkersToDetach[Index]; // Detach linker, also removes from array and sets LinkerRoot to NULL. Linker->Detach(true); } } }
UObject* FStreamableManager::SynchronousLoad(FStringAssetReference const& InTargetName) { UE_LOG(LogStreamableManager, Verbose, TEXT("Synchronous load %s"), *InTargetName.ToString()); if (FPackageName::IsShortPackageName(InTargetName.ToString())) { UE_LOG(LogStreamableManager, Error, TEXT(" Can't load invalid package name %s"), *InTargetName.ToString()); return NULL; } FStringAssetReference TargetName = ResolveRedirects(InTargetName); FStreamable* Existing = StreamableItems.FindRef(TargetName); while (Existing && Existing->bAsyncLoadRequestOutstanding) { UE_LOG(LogStreamableManager, Verbose, TEXT(" Flushing async load for %s"), *TargetName.ToString()); check(!Existing->bAsyncUnloadRequestOutstanding); // we should not be both loading and unloading FlushAsyncLoading(); // the async request might have found a redirect and retried TargetName = ResolveRedirects(TargetName); Existing = StreamableItems.FindRef(TargetName); } if (!Existing) { Existing = StreamableItems.Add(TargetName, new FStreamable()); } check(!Existing->bAsyncLoadRequestOutstanding); // should have already dealt with this if (Existing->bAsyncUnloadRequestOutstanding) { check(!Existing->bAsyncLoadRequestOutstanding); // we should not be both loading and unloading UE_LOG(LogStreamableManager, Verbose, TEXT(" Aborted unload for %s"), *TargetName.ToString()); Existing->bAsyncUnloadRequestOutstanding = false; } check(!Existing->bAsyncUnloadRequestOutstanding); // should have already dealt with this check(!Existing->WeakTarget.Get()); // weak target is only valid during GC if (!Existing->Target) { UE_LOG(LogStreamableManager, Verbose, TEXT(" Static loading %s"), *TargetName.ToString()); Existing->Target = StaticLoadObject(UObject::StaticClass(), NULL, *TargetName.ToString()); // need to manually detect redirectors because the above call only expects to load a UObject::StaticClass() type while (UObjectRedirector* Redirector = Cast<UObjectRedirector>(Existing->Target)) { Existing->Target = Redirector->DestinationObject; } if (Existing->Target) { UE_LOG(LogStreamableManager, Verbose, TEXT(" Static loaded %s"), *Existing->Target->GetFullName()); FStringAssetReference PossiblyNewName(Existing->Target->GetPathName()); if (PossiblyNewName != TargetName) { UE_LOG(LogStreamableManager, Verbose, TEXT(" Which redirected to %s"), *PossiblyNewName.ToString()); StreamableRedirects.Add(TargetName, PossiblyNewName); StreamableItems.Add(PossiblyNewName, Existing); StreamableItems.Remove(TargetName); TargetName = PossiblyNewName; // we are done with the old name } } else { Existing->bLoadFailed = true; UE_LOG(LogStreamableManager, Log, TEXT("Failed attempt to load %s"), *TargetName.ToString()); } } else { Existing->bLoadFailed = false; } return Existing->Target; }
void ResetLoaders(UObject* InPkg) { // Make sure we're not in the middle of loading something in the background. FlushAsyncLoading(); FLinkerManager::Get().ResetLoaders(InPkg); }
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; }