问题

用PakTools插件打包出来的pak文件,打包运行挂载pak文件后(使用PakLoader插件加载),有的pak文件系统无法加载指定路径的资产。

原因分析:

使用cmd命令查看pak文件,得到如下输出:

1
2
3
4
5
6
cmd:UnrealPak.exe F:\00_Imrcao\01_MyProject\PreviewTools\Saved\DownloadedPaks\Models\chair_P.pak -List
Mount point ../../../PreviewTool/
LogPakFile: Display: "AssetRegistry.bin" offset: 0, size: 3948 bytes, 
LogPakFile: Display: "Content/Assets/Materials/Models/Fabric_3.uasset"
LogPakFile: Display: "Content/Assets/Materials/Models/Fabric_3.uexp"
LogPakFile: Display: "Content/Assets/Materials/Models/Metal_2.uasset" 
1
2
3
4
5
6
7
cmd:UnrealPak.exe F:\00_Imrcao\01_MyProject\PreviewTools\Saved\DownloadedPaks\Models\Bed_P.pak -List

Mount point ../../../
PreviewTool/Content/Assets/Texture/UMG/Thumbnails/Models/Bed.ubulk"
LogPakFile: Display: "PreviewTool/Content/Assets/Texture/UMG/Thumbnails/Models/Bed.uexp"
LogPakFile: Display: "PreviewTool/Content/Blueprints/Sku/Models/Bed.uasset" 
LogPakFile: Display: "PreviewTool/Content/Blueprints/Sku/Models/Bed.uexp" 

可以发现两个pak文件的mountPoint不一样,默认mountPoint系统自己计算,但也可以自己设置。那么mountPoint不一致会有什么问题呢?先看我的挂载代码。

1
UPakLoaderLibrary::MountPakFile(PakPaths, "")
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//挂载pak
UPakLoaderLibrary::MountPakFile(PakPaths, "")

//注册挂载点,这个是核心
UPakLoaderLibrary::RegisterMountPoint("/PTPakDLC/", "../../../PreviewTool/Content/");
//
UPakLoaderLibrary::LoadPakAssetRegistryFile("../../../PreviewTool/AssetRegistry.bin");

//拼接资产名称
TArray<FString>pakFiles = UPakLoaderLibrary::GetFilesInPak(PakPaths, true);
for (auto pakFile : pakFiles)
{
	FString str = UBlueprintPathsLibrary::GetExtension(pakFile);
	if (!str.Equals("uexp") && !str.Equals("ubulk"))
		{
			//仅加载BPActor
			if (pakFile.Contains("Blueprints/Sku"))
					{
						pakFile.Split("Content/", nullptr, &pakFile);
						pakFile = "/PTPakDLC/" + pakFile;
						//去掉.uasset后缀,获取纯包路径:/PTPakDLC/Blueprints/Sku/Lights/SpotLight_P
						pakFile.Split(".", &pakFile, nullptr);
						AssetFiles.AddUnique(pakFile);
					}
		}
}

//根据资产名称加载pak中的资产
UPakLoaderLibrary::GetPakFileClass(const FString &Filename)

问题在于最后需要的资产的路径:/PTPakDLC/Blueprints/Sku/Lights/SpotLight_P,需要长这样。但是我之前是这样拼接的:pakFile.Replace(TEXT(“PreviewTool/Content”), TEXT("/PTPakDLC/"));我以为所有的pak文件都像Bed_P.pak文件一样,内部资产路径都是以PreviewTool/Content开头的。但是chair_P.pak是以Content开头的。但实际上它们俩在引擎中的实际资产路径都是以../../../PreviewTool/Content开头,由于注册了挂载点:RegisterMountPoint("/PTPakDLC/", “../../../PreviewTool/Content/"),引擎就会把所有的”../../../PreviewTool/Content/“替换为”/PTPakDLC/",但又由于UPakLoaderLibrary::GetFilesInPak(PakPaths, true),返回的是PreviewTool/Content/…/…或者是Content/…/…。所以使用pakFile.Replace就不妥当,要想获取这样的路径:/PTPakDLC/Blueprints/Sku/…/…/,就必须改变方法,最终目的就是要让引擎能够识别/PTPakDLC/Blueprints/Sku/…/…/路径,并且在pak中确实有这个资产。

总结

刚开始并不知道是这个原因导致的pak资产加载失败,尝试了很多方法,网上说加载了这个资产UPakLoaderLibrary::LoadPakAssetRegistryFile ("../../../PreviewTool/AssetRegistry.bin"),引擎可以自动识别资产路径,还没有深入测试。