Exemple #1
0
//
// 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);
}
Exemple #4
0
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;
}