static void LogGetPackageLinkerError(FLinkerLoad* Linker, const TCHAR* InFilename, const FText& InFullErrorMessage, const FText& InSummaryErrorMessage, UObject* InOuter, uint32 LoadFlags) { LogGetPackageLinkerError(Linker ? Linker->Loader : nullptr, InFilename, InFullErrorMessage, InSummaryErrorMessage, InOuter, LoadFlags); }
// // Find or create the linker for a package. // ULinkerLoad* GetPackageLinker ( UPackage* InOuter, const TCHAR* InLongPackageName, uint32 LoadFlags, UPackageMap* Sandbox, FGuid* CompatibleGuid ) { // See if there is already a linker for this package. ULinkerLoad* Result = ULinkerLoad::FindExistingLinkerForPackage(InOuter); // Try to load the linker. // See if the linker is already loaded. if( Result ) { return Result; } FString NewFilename; if( !InLongPackageName ) { // Resolve filename from package name. if( !InOuter ) { // try to recover from this instead of throwing, it seems recoverable just by doing this FText ErrorText(LOCTEXT("PackageResolveFailed", "Can't resolve asset name")); LogGetPackageLinkerError(Result, InLongPackageName, ErrorText, ErrorText, InOuter, LoadFlags); return nullptr; } if( !FPackageName::DoesPackageExist(InOuter->GetName(), CompatibleGuid, &NewFilename) ) { // Compiled in packages have no linker and this is ok if (!(LoadFlags & LOAD_AllowDll) && !(InOuter->PackageFlags & PKG_CompiledIn)) { FFormatNamedArguments Arguments; Arguments.Add(TEXT("AssetName"), FText::FromString(InOuter->GetName())); Arguments.Add(TEXT("PackageName"), FText::FromString(GSerializedPackageLinker ? *(GSerializedPackageLinker->Filename) : TEXT("NULL"))); LogGetPackageLinkerError(Result, GSerializedPackageLinker ? *GSerializedPackageLinker->Filename : nullptr, FText::Format(LOCTEXT("PackageNotFound", "Can't find file for asset '{AssetName}' while loading {PackageName}."), Arguments), LOCTEXT("PackageNotFoundShort", "Can't find file for asset."), InOuter, LoadFlags); } return nullptr; } } else { FString PackageName(InLongPackageName); if (!FPackageName::TryConvertFilenameToLongPackageName(InLongPackageName, PackageName)) { // try to recover from this instead of throwing, it seems recoverable just by doing this FText ErrorText(LOCTEXT("PackageResolveFailed", "Can't resolve asset name")); LogGetPackageLinkerError(Result, InLongPackageName, ErrorText, ErrorText, InOuter, LoadFlags); return nullptr; } if (UPackage* ExistingPackage = FindObject<UPackage>(nullptr, *PackageName)) { if (!ExistingPackage->GetOuter() && (ExistingPackage->PackageFlags & PKG_CompiledIn)) { // this is a compiled in package and so it has no linker and this is ok return nullptr; } } // Verify that the file exists. if( !FPackageName::DoesPackageExist( PackageName, CompatibleGuid, &NewFilename ) ) { FFormatNamedArguments Arguments; Arguments.Add(TEXT("Filename"), FText::FromString(InLongPackageName)); // try to recover from this instead of throwing, it seems recoverable just by doing this LogGetPackageLinkerError(Result, InLongPackageName, FText::Format(LOCTEXT("FileNotFound", "Can't find file '{Filename}'"), Arguments), LOCTEXT("FileNotFoundShort", "Can't find file"), InOuter, LoadFlags); return nullptr; } // Create the package with the provided long package name. UPackage* FilenamePkg = CreatePackage(nullptr, *PackageName); if (LoadFlags & LOAD_PackageForPIE) { FilenamePkg->PackageFlags |= PKG_PlayInEditor; } // If no package specified, use package from file. if (!InOuter) { if( !FilenamePkg ) { FFormatNamedArguments Arguments; Arguments.Add(TEXT("Filename"), FText::FromString(InLongPackageName)); LogGetPackageLinkerError(Result, InLongPackageName, FText::Format(LOCTEXT("FilenameToPackage", "Can't convert filename '{Filename}' to asset name"), Arguments), LOCTEXT("FilenameToPackageShort", "Can't convert filename to asset name"), InOuter, LoadFlags); return nullptr; } InOuter = FilenamePkg; Result = ULinkerLoad::FindExistingLinkerForPackage(InOuter); } else if (InOuter != FilenamePkg) //!!should be tested and validated in new UnrealEd { // Loading a new file into an existing package, so reset the loader. //UE_LOG(LogLinker, Log, TEXT("New File, Existing Package (%s, %s)"), *InOuter->GetFullName(), *FilenamePkg->GetFullName() ); ResetLoaders( InOuter ); } } #if 0 // Make sure the package is accessible in the sandbox. if( Sandbox && !Sandbox->SupportsPackage(InOuter) ) { FFormatNamedArguments Arguments; Arguments.Add(TEXT("AssetName"), FText::FromString(InOuter->GetName())); LogGetPackageLinkerError(Result, InLongPackageName, FText::Format(LOCTEXT("Sandbox", "Asset '{AssetName}' is not accessible in this sandbox"), Arguments), LOCTEXT("SandboxShort", "Asset is not accessible in this sandbox"), InOuter, LoadFlags); return nullptr; } #endif // Create new linker. if( !Result ) { check(IsLoading()); // we will already have found the filename above check(NewFilename.Len() > 0); Result = ULinkerLoad::CreateLinker( InOuter, *NewFilename, LoadFlags ); } // Verify compatibility. if( CompatibleGuid && Result->Summary.Guid!=*CompatibleGuid ) { FFormatNamedArguments Arguments; Arguments.Add(TEXT("AssetName"), FText::FromString(InOuter->GetName())); // This should never fire, because FindPackageFile should never return an incompatible file LogGetPackageLinkerError(Result, InLongPackageName, FText::Format(LOCTEXT("PackageVersion", "Asset '{AssetName}' version mismatch"), Arguments), LOCTEXT("PackageVersionShort", "Asset version mismatch"), InOuter, LoadFlags); return nullptr; } return Result; }
// // Find or create the linker for a package. // FLinkerLoad* GetPackageLinker ( UPackage* InOuter, const TCHAR* InLongPackageName, uint32 LoadFlags, UPackageMap* Sandbox, FGuid* CompatibleGuid ) { // See if there is already a linker for this package. auto Result = FLinkerLoad::FindExistingLinkerForPackage(InOuter); // Try to load the linker. // See if the linker is already loaded. if (Result) { return Result; } FString NewFilename; if( !InLongPackageName ) { // Resolve filename from package name. if( !InOuter ) { // try to recover from this instead of throwing, it seems recoverable just by doing this FText ErrorText(LOCTEXT("PackageResolveFailed", "Can't resolve asset name")); LogGetPackageLinkerError(Result, InLongPackageName, ErrorText, ErrorText, InOuter, LoadFlags); return nullptr; } FString NativeFilename; FString LocalizedFilename; const bool DoesNativePackageExist = FPackageName::DoesPackageExist(InOuter->GetName(), CompatibleGuid, &NativeFilename, false); const bool DoesLocalizedPackageExist = FPackageName::DoesPackageExist(InOuter->GetName(), CompatibleGuid, &LocalizedFilename, true); // If we are the editor, we must have a native package. If we are the game, we must have a localized package or a native package. if ( (GIsEditor && !DoesNativePackageExist) || (!GIsEditor && !DoesLocalizedPackageExist && !DoesNativePackageExist) ) { // In memory-only packages have no linker and this is ok. if (!(LoadFlags & LOAD_AllowDll) && !(InOuter->PackageFlags & PKG_InMemoryOnly)) { FUObjectThreadContext& ThreadContext = FUObjectThreadContext::Get(); FFormatNamedArguments Arguments; Arguments.Add(TEXT("AssetName"), FText::FromString(InOuter->GetName())); Arguments.Add(TEXT("PackageName"), FText::FromString(ThreadContext.SerializedPackageLinker ? *(ThreadContext.SerializedPackageLinker->Filename) : TEXT("NULL"))); LogGetPackageLinkerError(Result, ThreadContext.SerializedPackageLinker ? *ThreadContext.SerializedPackageLinker->Filename : nullptr, FText::Format(LOCTEXT("PackageNotFound", "Can't find file for asset '{AssetName}' while loading {PackageName}."), Arguments), LOCTEXT("PackageNotFoundShort", "Can't find file for asset."), InOuter, LoadFlags); } return nullptr; } // The editor must not redirect packages for localization. if (GIsEditor) { NewFilename = NativeFilename; } else { if (DoesLocalizedPackageExist) { NewFilename = LocalizedFilename; } // If we are the game, we can fallback to the native package, but must issue a warning. else { // In memory-only packages have no linker and this is ok. if (!(LoadFlags & LOAD_AllowDll) && !(InOuter->PackageFlags & PKG_InMemoryOnly)) { FUObjectThreadContext& ThreadContext = FUObjectThreadContext::Get(); FFormatNamedArguments Arguments; Arguments.Add(TEXT("AssetName"), FText::FromString(InOuter->GetName())); Arguments.Add(TEXT("PackageName"), FText::FromString(ThreadContext.SerializedPackageLinker ? *(ThreadContext.SerializedPackageLinker->Filename) : TEXT("NULL"))); LogGetPackageLinkerError(Result, ThreadContext.SerializedPackageLinker ? *ThreadContext.SerializedPackageLinker->Filename : nullptr, FText::Format(LOCTEXT("PackageNotFound", "Can't find localized file for asset '{AssetName}' while loading {PackageName}."), Arguments), LOCTEXT("PackageNotFoundShort", "Can't find localized file for asset."), InOuter, LoadFlags); } NewFilename = NativeFilename; } } } else { FString PackageName(InLongPackageName); if (!FPackageName::TryConvertFilenameToLongPackageName(InLongPackageName, PackageName)) { // try to recover from this instead of throwing, it seems recoverable just by doing this FText ErrorText(LOCTEXT("PackageResolveFailed", "Can't resolve asset name")); LogGetPackageLinkerError(Result, InLongPackageName, ErrorText, ErrorText, InOuter, LoadFlags); return nullptr; } UPackage* ExistingPackage = FindObject<UPackage>(nullptr, *PackageName); if (ExistingPackage) { if (!ExistingPackage->GetOuter() && (ExistingPackage->PackageFlags & PKG_InMemoryOnly)) { // This is a memory-only in package and so it has no linker and this is ok. return nullptr; } } // Verify that the file exists. FString NativeFilename; FString LocalizedFilename; const bool DoesNativePackageExist = FPackageName::DoesPackageExist(PackageName, CompatibleGuid, &NativeFilename, false); const bool DoesLocalizedPackageExist = FPackageName::DoesPackageExist(PackageName, CompatibleGuid, &LocalizedFilename, true); if( (GIsEditor && !DoesNativePackageExist) || (!GIsEditor && !DoesLocalizedPackageExist && !DoesNativePackageExist) ) { FFormatNamedArguments Arguments; Arguments.Add(TEXT("Filename"), FText::FromString(InLongPackageName)); // try to recover from this instead of throwing, it seems recoverable just by doing this LogGetPackageLinkerError(Result, InLongPackageName, FText::Format(LOCTEXT("FileNotFound", "Can't find file '{Filename}'"), Arguments), LOCTEXT("FileNotFoundShort", "Can't find file"), InOuter, LoadFlags); return nullptr; } // The editor must not redirect packages for localization. if (GIsEditor) { NewFilename = NativeFilename; } else { // Use the localized package if possible. if (DoesLocalizedPackageExist) { NewFilename = LocalizedFilename; } // If we are the game, we can fallback to the native package. else { NewFilename = NativeFilename; } } // Create the package with the provided long package name. UPackage* FilenamePkg = (ExistingPackage ? ExistingPackage : CreatePackage(nullptr, *PackageName)); if (FilenamePkg != ExistingPackage && (LoadFlags & LOAD_PackageForPIE)) { FilenamePkg->PackageFlags |= PKG_PlayInEditor; } // If no package specified, use package from file. if (!InOuter) { if( !FilenamePkg ) { FFormatNamedArguments Arguments; Arguments.Add(TEXT("Filename"), FText::FromString(InLongPackageName)); LogGetPackageLinkerError(Result, InLongPackageName, FText::Format(LOCTEXT("FilenameToPackage", "Can't convert filename '{Filename}' to asset name"), Arguments), LOCTEXT("FilenameToPackageShort", "Can't convert filename to asset name"), InOuter, LoadFlags); return nullptr; } InOuter = FilenamePkg; Result = FLinkerLoad::FindExistingLinkerForPackage(InOuter); } else if (InOuter != FilenamePkg) //!!should be tested and validated in new UnrealEd { // Loading a new file into an existing package, so reset the loader. //UE_LOG(LogLinker, Log, TEXT("New File, Existing Package (%s, %s)"), *InOuter->GetFullName(), *FilenamePkg->GetFullName() ); ResetLoaders( InOuter ); } } #if 0 // Make sure the package is accessible in the sandbox. if( Sandbox && !Sandbox->SupportsPackage(InOuter) ) { FFormatNamedArguments Arguments; Arguments.Add(TEXT("AssetName"), FText::FromString(InOuter->GetName())); LogGetPackageLinkerError(Result, InLongPackageName, FText::Format(LOCTEXT("Sandbox", "Asset '{AssetName}' is not accessible in this sandbox"), Arguments), LOCTEXT("SandboxShort", "Asset is not accessible in this sandbox"), InOuter, LoadFlags); return nullptr; } #endif // Create new linker. if( !Result ) { check(IsLoading()); // we will already have found the filename above check(NewFilename.Len() > 0); Result = FLinkerLoad::CreateLinker( InOuter, *NewFilename, LoadFlags ); } // Verify compatibility. if (Result && CompatibleGuid && Result->Summary.Guid != *CompatibleGuid) { FFormatNamedArguments Arguments; Arguments.Add(TEXT("AssetName"), FText::FromString(InOuter->GetName())); // This should never fire, because FindPackageFile should never return an incompatible file LogGetPackageLinkerError(Result, InLongPackageName, FText::Format(LOCTEXT("PackageVersion", "Asset '{AssetName}' version mismatch"), Arguments), LOCTEXT("PackageVersionShort", "Asset version mismatch"), InOuter, LoadFlags); return nullptr; } return Result; }