void FRedirectCollector::OnStringAssetReferenceLoaded(const FString& InString) { FUObjectThreadContext& ThreadContext = FUObjectThreadContext::Get(); FPackagePropertyPair ContainingPackageAndProperty; if (InString.IsEmpty()) { // No need to track empty strings return; } if (ThreadContext.SerializedObject) { FLinkerLoad* Linker = ThreadContext.SerializedObject->GetLinker(); if (Linker) { ContainingPackageAndProperty.SetPackage(FName(*Linker->Filename)); if (Linker->GetSerializedProperty()) { ContainingPackageAndProperty.SetProperty( FName(*FString::Printf(TEXT("%s:%s"), *ThreadContext.SerializedObject->GetPathName(), *Linker->GetSerializedProperty()->GetName()))); } #if WITH_EDITORONLY_DATA ContainingPackageAndProperty.SetReferencedByEditorOnlyProperty( Linker->IsEditorOnlyPropertyOnTheStack() ); #endif } } StringAssetReferences.AddUnique(FName(*InString), ContainingPackageAndProperty); }
void UArrayProperty::LinkInternal(FArchive& Ar) { FLinkerLoad* MyLinker = GetLinker(); if( MyLinker ) { MyLinker->Preload(this); } Ar.Preload(Inner); Inner->Link(Ar); Super::LinkInternal(Ar); }
/** * * Ensure thumbnails are loaded and then reset the loader in preparation for a package save * * @param InOuter The outer for the package we are saving * @param Filename The filename we are saving too */ void ResetLoadersForSave(UObject* InOuter, const TCHAR *Filename) { UPackage* Package = dynamic_cast<UPackage*>(InOuter); // If we have a loader for the package, unload it to prevent conflicts if we are resaving to the same filename FLinkerLoad* Loader = FLinkerLoad::FindExistingLinkerForPackage(Package); // This is the loader corresponding to the package we're saving. if( Loader ) { // Before we save the package, make sure that we load up any thumbnails that aren't already // in memory so that they won't be wiped out during this save Loader->SerializeThumbnails(); // Compare absolute filenames to see whether we're trying to save over an existing file. if( FPaths::ConvertRelativePathToFull(Filename) == FPaths::ConvertRelativePathToFull( Loader->Filename ) ) { // Detach all exports from the linker and dissociate the linker. ResetLoaders( InOuter ); } } }
void UUserDefinedStruct::RecursivelyPreload() { FLinkerLoad* Linker = GetLinker(); if( Linker && (NULL == PropertyLink) ) { TArray<UObject*> AllChildMembers; GetObjectsWithOuter(this, AllChildMembers); for (int32 Index = 0; Index < AllChildMembers.Num(); ++Index) { UObject* Member = AllChildMembers[Index]; Linker->Preload(Member); } Linker->Preload(this); if (NULL == PropertyLink) { StaticLink(true); } } }
UObject* UObjectPropertyBase::FindImportedObject( const UProperty* Property, UObject* OwnerObject, UClass* ObjectClass, UClass* RequiredMetaClass, const TCHAR* Text, uint32 PortFlags/*=0*/ ) { UObject* Result = NULL; check( ObjectClass->IsChildOf(RequiredMetaClass) ); bool AttemptNonQualifiedSearch = (PortFlags & PPF_AttemptNonQualifiedSearch) != 0; // if we are importing default properties, first look for a matching subobject by // looking through the archetype chain at each outer and stop once the outer chain reaches the owning class's default object if (PortFlags & PPF_ParsingDefaultProperties) { for (UObject* SearchStart = OwnerObject; Result == NULL && SearchStart != NULL; SearchStart = SearchStart->GetOuter()) { UObject* ScopedSearchRoot = SearchStart; while (Result == NULL && ScopedSearchRoot != NULL) { Result = StaticFindObject(ObjectClass, ScopedSearchRoot, Text); // don't think it's possible to get a non-subobject here, but it doesn't hurt to check if (Result != NULL && !Result->IsTemplate(RF_ClassDefaultObject)) { Result = NULL; } ScopedSearchRoot = ScopedSearchRoot->GetArchetype(); } if (SearchStart->HasAnyFlags(RF_ClassDefaultObject)) { break; } } } // if we have a parent, look in the parent, then it's outer, then it's outer, ... // this is because exported object properties that point to objects in the level aren't // fully qualified, and this will step up the nested object chain to solve any name // collisions within a nested object tree UObject* ScopedSearchRoot = OwnerObject; while (Result == NULL && ScopedSearchRoot != NULL) { Result = StaticFindObject(ObjectClass, ScopedSearchRoot, Text); // disallow class default subobjects here while importing defaults // this prevents the use of a subobject name that doesn't exist in the scope of the default object being imported // from grabbing some other subobject with the same name and class in some other arbitrary default object if (Result != NULL && (PortFlags & PPF_ParsingDefaultProperties) && Result->IsTemplate(RF_ClassDefaultObject)) { Result = NULL; } ScopedSearchRoot = ScopedSearchRoot->GetOuter(); } if (Result == NULL) { // attempt to find a fully qualified object Result = StaticFindObject(ObjectClass, NULL, Text); if (Result == NULL) { // match any object of the correct class whose path contains the specified path Result = StaticFindObject(ObjectClass, ANY_PACKAGE, Text); // disallow class default subobjects here while importing defaults if (Result != NULL && (PortFlags & PPF_ParsingDefaultProperties) && Result->IsTemplate(RF_ClassDefaultObject)) { Result = NULL; } } } // if we haven;t found it yet, then try to find it without a qualified name if (!Result) { const TCHAR* Dot = FCString::Strrchr(Text, '.'); if (Dot && AttemptNonQualifiedSearch) { // search with just the object name Result = FindImportedObject(Property, OwnerObject, ObjectClass, RequiredMetaClass, Dot + 1); } FString NewText(Text); // if it didn't have a dot, then maybe they just gave a uasset package name if (!Dot && !Result) { int32 LastSlash = NewText.Find(TEXT("/"), ESearchCase::CaseSensitive, ESearchDir::FromEnd); if (LastSlash >= 0) { NewText += TEXT("."); NewText += (Text + LastSlash + 1); Dot = FCString::Strrchr(*NewText, '.'); } } // If we still can't find it, try to load it. (Only try to load fully qualified names) if(!Result && Dot) { #if USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING FLinkerLoad* Linker = (OwnerObject != nullptr) ? OwnerObject->GetClass()->GetLinker() : nullptr; const bool bDeferAssetImports = (Linker != nullptr) && (Linker->LoadFlags & LOAD_DeferDependencyLoads); if (bDeferAssetImports) { Result = Linker->RequestPlaceholderValue(ObjectClass, Text); } if (Result == nullptr) #endif // USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING { uint32 LoadFlags = LOAD_NoWarn | LOAD_FindIfFail; UE_LOG(LogProperty, Verbose, TEXT("FindImportedObject is attempting to import [%s] (class = %s) with StaticLoadObject"), Text, *GetFullNameSafe(ObjectClass)); Result = StaticLoadObject(ObjectClass, NULL, Text, NULL, LoadFlags, NULL); #if USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS check(!bDeferAssetImports || !Result || !FBlueprintSupport::IsInBlueprintPackage(Result)); #endif // USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS } } } // if we found an object, and we have a parent, make sure we are in the same package if the found object is private, unless it's a cross level property if (Result && !Result->HasAnyFlags(RF_Public) && OwnerObject && Result->GetOutermost() != OwnerObject->GetOutermost()) { const UObjectPropertyBase* ObjectProperty = dynamic_cast<const UObjectPropertyBase*>(Property); if ( !ObjectProperty || !ObjectProperty->AllowCrossLevel()) { UE_LOG(LogProperty, Warning, TEXT("Illegal TEXT reference to a private object in external package (%s) from referencer (%s). Import failed..."), *Result->GetFullName(), *OwnerObject->GetFullName()); Result = NULL; } } check(!Result || Result->IsA(RequiredMetaClass)); return Result; }
void ULevelStreaming::AsyncLevelLoadComplete(const FName& InPackageName, UPackage* InLoadedPackage, EAsyncLoadingResult::Type Result) { bHasLoadRequestPending = false; if( InLoadedPackage ) { UPackage* LevelPackage = InLoadedPackage; // Try to find a UWorld object in the level package. UWorld* World = UWorld::FindWorldInPackage(LevelPackage); if ( World ) { ULevel* Level = World->PersistentLevel; if( Level ) { check(PendingUnloadLevel == NULL); SetLoadedLevel(Level); // Broadcast level loaded event to blueprints OnLevelLoaded.Broadcast(this); // Make sure this level will start to render only when it will be fully added to the world if (LODPackageNames.Num() > 0) { Level->bRequireFullVisibilityToRender = true; // LOD levels should not be visible on server Level->bClientOnlyVisible = LODPackageNames.Contains(InLoadedPackage->GetFName()); } // In the editor levels must be in the levels array regardless of whether they are visible or not if (ensure(Level->OwningWorld) && Level->OwningWorld->WorldType == EWorldType::Editor) { Level->OwningWorld->AddLevel(Level); #if WITH_EDITOR // We should also at this point, apply the level's editor transform if (!Level->bAlreadyMovedActors) { FLevelUtils::ApplyEditorTransform(this, false); Level->bAlreadyMovedActors = true; } #endif // WITH_EDITOR } } else { UE_LOG(LogLevelStreaming, Warning, TEXT("Couldn't find ULevel object in package '%s'"), *InPackageName.ToString() ); } } else { // There could have been a redirector in the package. Attempt to follow it. UObjectRedirector* WorldRedirector = nullptr; UWorld* DestinationWorld = UWorld::FollowWorldRedirectorInPackage(LevelPackage, &WorldRedirector); if (DestinationWorld) { // To follow the world redirector for level streaming... // 1) Update all globals that refer to the redirector package by name // 2) Update the PackageNameToLoad to refer to the new package location // 3) If the package name to load was the same as the destination package name... // ... update the package name to the new package and let the next RequestLevel try this process again. // If the package name to load was different... // ... it means the specified package name was explicit and we will just load from another file. FName OldDesiredPackageName = InPackageName; TWeakObjectPtr<UWorld>* OwningWorldPtr = ULevel::StreamedLevelsOwningWorld.Find(OldDesiredPackageName); UWorld* OwningWorld = OwningWorldPtr ? OwningWorldPtr->Get() : NULL; ULevel::StreamedLevelsOwningWorld.Remove(OldDesiredPackageName); // Try again with the destination package to load. // IMPORTANT: check this BEFORE changing PackageNameToLoad, otherwise you wont know if the package name was supposed to be different. const bool bLoadingIntoDifferentPackage = (GetWorldAssetPackageFName() != PackageNameToLoad) && (PackageNameToLoad != NAME_None); // ... now set PackageNameToLoad PackageNameToLoad = DestinationWorld->GetOutermost()->GetFName(); if ( PackageNameToLoad != OldDesiredPackageName ) { EWorldType::Type* OldPackageWorldType = UWorld::WorldTypePreLoadMap.Find(OldDesiredPackageName); if ( OldPackageWorldType ) { UWorld::WorldTypePreLoadMap.FindOrAdd(PackageNameToLoad) = *OldPackageWorldType; UWorld::WorldTypePreLoadMap.Remove(OldDesiredPackageName); } } // Now determine if we are loading into the package explicitly or if it is okay to just load the other package. if ( bLoadingIntoDifferentPackage ) { // Loading into a new custom package explicitly. Load the destination world directly into the package. // Detach the linker to load from a new file into the same package. FLinkerLoad* PackageLinker = FLinkerLoad::FindExistingLinkerForPackage(LevelPackage); if (PackageLinker) { PackageLinker->Detach(); DeleteLoader(PackageLinker); PackageLinker = nullptr; } // Make sure the redirector is not in the way of the new world. // Pass NULL as the name to make a new unique name and GetTransientPackage() for the outer to remove it from the package. WorldRedirector->Rename(NULL, GetTransientPackage(), REN_DoNotDirty | REN_DontCreateRedirectors | REN_ForceNoResetLoaders | REN_NonTransactional); // Change the loaded world's type back to inactive since it won't be used. DestinationWorld->WorldType = EWorldType::Inactive; } else { // Loading the requested package normally. Fix up the destination world then update the requested package to the destination. if (OwningWorld) { if (DestinationWorld->PersistentLevel) { DestinationWorld->PersistentLevel->OwningWorld = OwningWorld; } // In some cases, BSP render data is not created because the OwningWorld was not set correctly. // Regenerate that render data here DestinationWorld->PersistentLevel->InvalidateModelSurface(); DestinationWorld->PersistentLevel->CommitModelSurfaces(); } WorldAsset = DestinationWorld; } } } } else if (Result == EAsyncLoadingResult::Canceled) { // Cancel level streaming bHasLoadRequestPending = false; bShouldBeLoaded = false; } else { UE_LOG(LogLevelStreaming, Warning, TEXT("Failed to load package '%s'"), *InPackageName.ToString() ); } // Clean up the world type list and owning world list now that PostLoad has occurred UWorld::WorldTypePreLoadMap.Remove(InPackageName); ULevel::StreamedLevelsOwningWorld.Remove(InPackageName); STAT_ADD_CUSTOMMESSAGE_NAME( STAT_NamedMarker, *(FString( TEXT( "RequestLevelComplete - " ) + InPackageName.ToString() )) ); }