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.cnblogs.com/psklf/p/14778289.html

你还没有登录,请先登录注册
  • 还没有人评论,欢迎说说您的想法!