虚幻引擎 4:在打包游戏中使用 AssetRegistry 加载 PAK 文件、加载/挂载它们以及加载资源的正确方法是什么?

Ker*_*iro 6 unreal-engine4

我想这样做:创建并打包原创游戏。然后我想根据原始游戏中的蓝图创建带有新网格/声音/动画和蓝图的附加 PAK 文件。原始游戏不应该知道任何关于附加网格/动画/等的信息。因此,我需要在原始游戏中使用 AssetRegistry 创建一个智能系统,扫描所有 PAK 文件,加载/挂载它们,并使用 AssetRegistry 扫描这些 PAK 文件中的所有资产。

我为实现目标所做的事情:我为目标平台(Windows 独立版)成功创建并打包了原始游戏。然后在项目中,我创建附加内容并为目标平台烘焙它们。我使用 UnrealPak.exe 为附加内容创建 PAK 文件。我可以通过将 PAK 文件放在 Paks 文件夹中来加载/挂载原始游戏中的 PAK 文件,并且它们在游戏启动时加载/挂载(这句话是基于原始游戏中的 LOG 文件,我不知道如何来检查它是否真实)。我什至可以使用 FCoreDelegates::OnMountPak.Execute 来加载/挂载 PAK 文件(这句话也是基于原始游戏的 LOG 文件)。因此加载/挂载 PAK 文件应该可以正常工作。但现在最大的问题在哪里。我想使用 AssetRegistry 扫描所有 PAK 文件中的所有资产。我尝试了我想出的一切。我尝试了 ScanPathsSynchronous 方法、GetAllAssets 方法。唯一发生的事情是它从原始游戏 PAK 文件加载资产。看来 AssetRegistry 对其他 PAK 文件一无所知。我试图用 AddPath 方法告诉 AssetRegistry 这些文件在哪里,但仍然不起作用。

所以我尝试过的示例代码在这里:

         FString path1 = FPaths::ConvertRelativePathToFull(FString("../../../TestPaks/Content/Paks/test.pak"));
     FString path2 = FPaths::ConvertRelativePathToFull(FString("../../../TestPaks/Content/Paks/testmaterial.pak"));        

     bool check1 = false;
     bool check2 = false;
     if (FCoreDelegates::OnMountPak.IsBound())
     {
         check1 = FCoreDelegates::OnMountPak.Execute(path1, 0, nullptr); //Number should be 0-4; specifies search order
         check2 = FCoreDelegates::OnMountPak.Execute(path2, 0, nullptr); //Number should be 0-4; specifies search order
     }

     UE_LOG(LogTemp, Warning, TEXT("%s"), *path1);
     UE_LOG(LogTemp, Warning, TEXT("%s"), *path2);

     FString NewString1 = check1 ? "true" : "false";
     FString NewString2 = check2 ? "true" : "false";
     UE_LOG(LogTemp, Warning, TEXT("check 1 = %s"), *NewString1);
     UE_LOG(LogTemp, Warning, TEXT("check 2 = %s"), *NewString2);

     FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(FName("AssetRegistry"));
     IAssetRegistry& assetRegistry = AssetRegistryModule.Get();

     TArray<FString> ContentPaths;
     TArray<FAssetData> data;
     //assetRegistry.AddPath(path1);
     FString contentRelativeDir = TEXT("/Game/Paks");
     assetRegistry.AddPath(contentRelativeDir);
     assetRegistry.ScanPathsSynchronous({ contentRelativeDir });
     //assetRegistry.SearchAllAssets(true);
     assetRegistry.GetAllAssets(data, false);

     assetRegistry.GetAllCachedPaths(ContentPaths);
     for (FString& data : ContentPaths)
     {
         UE_LOG(LogTemp, Warning, TEXT("GetAllCachedPaths: %s"), *data);
     }

     FString NewString = FString::FromInt(data.Num());
     UE_LOG(LogTemp, Warning, TEXT("%s"), *NewString);

     for (int32 i = 0; i < data.Num(); i++)
     {
         FString s = data[i].AssetName.ToString();
         FString ss = data[i].AssetClass.ToString();
         UE_LOG(LogTemp, Warning, TEXT("%s | %s"), *s, *ss);
     }
Run Code Online (Sandbox Code Playgroud)

我尝试了很多版本的路径,但没有任何效果。我陷入这种混乱状态大约两周了,对于该做什么以及什么会起作用,我没有更多的建议。那么这应该如何正常工作???我查看了这里的论坛和 StackOverflow,有一些解决方案,但它们不再起作用了。

小智 7

我已从 .pak 文件加载资源,但我使用 FStreamableManager 而不是 AssetRegistry。我将描述我所做的事情......

1)挂载.pak文件:我只需要将额外的.pak文件放入WindowNoEditor / [Project_Name] / Content / Paks /文件夹(假设您打包为window),游戏引擎将自动挂载该.pak文件。

2) 从该 .pak 文件加载/获取资源:

FPakPlatformFile *PakPlatformFile;
FString PlatformFileName = FPlatformFileManager::Get().GetPlatformFile().GetName();
if (PlatformFileName.Equals(FString(TEXT("PakFile"))))
{
  PakPlatformFile = static_cast<FPakPlatformFile*>(&FPlatformFileManager::Get().GetPlatformFile());
}
else
{
  PakPlatformFile = new FPakPlatformFile;
    if (!PakPlatformFile->Initialize(&FPlatformFileManager::Get().GetPlatformFile(), TEXT("")))
    {
        UE_LOG(LogTemp, Error, TEXT("FPakPlatformFile failed to initialize"));
        return;
    }
    FPlatformFileManager::Get().SetPlatformFile(*PakPlatformFile);
}
TArray<FString> ArrAllMountedPakFile;
PakPlatformFile->GetMountedPakFilenames(ArrAllMountedPakFile);
for (int32 i = 0; i < ArrAllMountedPakFile.Num(); i++)
{
   FString PakFileName = ArrAllMountedPakFile[i];
   FString PakFilePathFull = FPaths::ConvertRelativePathToFull(PakFileName);
   FPakFile PakFile(PakPlatformFile, *PakFilePathFull, false);
   TArray<FString> FileList;
   FString MountPoint = PakFile.GetMountPoint();
   PakFile.FindFilesAtPath(FileList, *MountPoint, true, false, true);
   for (int32 i = 0; i < FileList.Num(); i++)
   {
       FString AssetName = FileList[i];
       FString AssetShortName = FPackageName::GetShortName(AssetName);
       FString FileName, FileExt;
       AssetShortName.Split(TEXT("."), &FileName, &FileExt);
       FString NewAssetName = TEXT("/Game/<path_to_asset>/") + FileName + TEXT(".") + FileName;

       FSoftObjectPath StrNewAssetRef = NewAssetName;
       FStreamableManager AssetLoader;
       UObject* NewLoadedObject = AssetLoader.LoadSynchronous(StrNewAssetRef);
       if (NewLoadedObject)
       {
           // do something, cast to compatible type.
       }
   }
}
Run Code Online (Sandbox Code Playgroud)

希望对您有所帮助。欢呼!