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 回答