Unreal: Dynamic load map from Pak file

Unreal: Dynamic load map from Pak file

目标:在程序运行时加载自定义 Pak 文件,并打开指定关卡,显示其中的完整 map 内容

Unreal 的 Pak 文件内包括了物体,材质,blueprint,map等等。Level 以 map 的形式保存。

Firsr of all, Pak 相关的调试需要 Package Project 执行,不能在 Editor 里面直接 Launch,否则 FCoreDelegates::MountPak IsBound 为 false , 则无法执行后续操作。

Code

在 GameMode 的 InitGame() 内调用如下代码。

void MyMainClass::MyMainClass::Exe(UWorld *world) { UE_LOG(LogTemp, Warning, TEXT("Init Main class")); if (FCoreDelegates::MountPak.IsBound()) { UE_LOG(LogTemp, Warning, TEXT("LoadPakDelegate(): OnMountPak.IsBound()")); FString pakPath = TEXT("../../../MyProject3/Content/Paks/MyProject1-MacNoEditor.pak"); IPakFile *pakFile = FCoreDelegates::MountPak.Execute(pakPath, 4); if (pakFile) { const auto& mountPoint = pakFile->PakGetMountPoint(); UE_LOG(LogTemp, Warning, TEXT("LoadPakDelegate(): MountPoint %s"), *mountPoint); FString pakContentPath = mountPoint + "MyProject1/Content/"; // FPackageName::RegisterMountPoint("/Game/", "../../../MyProject1/Content/"); FPackageName::RegisterMountPoint("/Game/", pakContentPath); UGameplayStatics::OpenLevel(world, FName(TEXT("Map2")) ); } } else { UE_LOG(LogTemp, Warning, TEXT("LoadPakDelegate(): OnMountPak.IsBound() Falied")); } } RegisterMountPoint 的分析 static void RegisterMountPoint (     const FString & RootPath,     const FString & ContentPath )

This will insert a mount point at the head of the search chain (so it can overlap an existing mount point and win).

参数解释:

RootPath: Logical Root Path.

ContentPath: Content Path on disk.

Logical Path 是程序运行时会去找的 path 并非实际路径,根据反复尝试,只有在这个参数写成 “/Game/” 的时候才能正确加载到所有资源,若随意命名可能只能加载到 map 资源,连 map_builtdata 都找不到。会有如下报错:
LogStreaming: Error: Couldn't find file for package /Game/StarterContent/Maps/Map2_BuiltData requested by async loading code. NameToLoad: /Game/StarterContent/Maps/Map2_BuiltData

我的猜测是当前运行的程序的默认加载路径是 Game 所以这样写可以成功,应该也有方法自定义加载的路径,但是我暂时不知道。

Content Path 是指需要 mount 到前面这个目录的内容的父路径,这个路径取决于加载的Pak 的当前挂载点和 Pak 内部的文件路径。

通过 PakGetMountPoint() 函数得到挂载点为 "../../../"
而且 Pak 内部文件如下

MyProject1/Content/StarterContent/Blueprints/... MyProject1/Content/StarterContent/Maps/... MyProject1/Content/StarterContent/Materials/... MyProject1/Content/StarterContent/Shapes/... ...

故最终路径为 “../../../MyProject1/Content/”

Missing shader resource

成功加载 map 但是模型材质和 shader 丢失,log 如下:

[UE4] [2021.05.17-03.57.53:734][ 0]LogShaders: Error: Missing shader resource for hash '589973CAE03D7F0ECFEC6B825B774136FF9FCB9D' for shader platform 16 in the shader library LogMaterial: Error: Tried to access an uncooked shader map ID in a cooked application [UE4] [2021.05.17-08.02.25:186][ 0]LogMaterial: Can't compile BasicShapeMaterial with cooked content, will use default material instead

这个问题原因是在要加载 Pak 的工程设置里面启用了 Share Material Shader Code,启用这个选项会 “Save shader only once” 这样的优化选项导致了外部的 shader 无法被找到。
在工程中关闭此开关即可。

Ref:

https://answers.unrealengine.com/questions/363767/how-to-load-a-map-from-a-dynamic-level.html 参见 TestyRabbit May 03 '18 at 4:07 PM 的评论

sample code: https://pastebin.com/ZWAPtynK

https://answers.unrealengine.com/questions/258386/loading-map-from-pak-at-runtime.html top 回答

https://answers.unrealengine.com/questions/963414/view.html

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyssfd.html