运行时读取PAK文件
運(yùn)行時讀取PAK文件
https://zhuanlan.zhihu.com/p/79209172
?
運(yùn)行時讀取PAK文件
安寧
游戲/仿真開發(fā),UE4用戶
運(yùn)行時加載資產(chǎn)的問題
Unreal運(yùn)行時加載資產(chǎn)有兩個問題:
第一,Unreal不會自動加載任何額外的pak文件。
第二,一旦加載了一個pak, 它不會將pak文件中的任何資產(chǎn)添加到內(nèi)存中的AssetRegistry ..所以即使加載了pak,你也無法訪問它的內(nèi)容
而這段代碼中的ScanForModPlugins()函數(shù)處理了這兩個問題:
https://github.com/smogworks/ModSkeleton/blob/master/Source/ModSkeleton/ModSkeletonRegistry.cpp?
github.com
?
開發(fā)和測試流程
兩個非常重要的限制:
在PIE模式中加載Pak文件時,只能加載未Cook的內(nèi)容
在發(fā)布以后的程序中加載Pak文件時,只能加載已Cook的內(nèi)容
因此需要設(shè)計一套流程,便于在發(fā)布以后的程序中測試,其中包含兩個步驟:
下面對每個過程進(jìn)行闡述:
Cook 內(nèi)容資源
打開內(nèi)容所在的工程,打開Project Launcher,創(chuàng)建一個新的Profile,僅選擇Cook: By the book , 其余Build, Package, Archive, Deploy, Launch都不要。然后運(yùn)行該P(yáng)rofile即可達(dá)到Cook的效果。
一個讓以后Cook更簡單的辦法是,在運(yùn)行上述Profile以后,復(fù)制其命令內(nèi)容:
粘貼到一個文本文件中,去掉BuildCookRun之前的內(nèi)容,復(fù)制到剪貼板中;
然后搜索到RunUAT.bat文件,找到其路徑,cmd定位到該目錄下,然后輸入 RunUAT.bat 然后將剪貼板中的內(nèi)容粘貼到該命令后面,即可直接Cook內(nèi)容。
Cook以后的內(nèi)容默認(rèn)情況下位于
工程目錄/Saved/Cooked/<Platform Folder>/打包Pak
搜索UnrealPak.exe文件,CMD定位到該目錄下,輸入:
UnrealPak.exe Pak文件的完整路徑和名稱 -create=要打包的文件夾路徑注意-create=后面也可以跟一個文本文件,列出所有需要打包的具體uasset等文件的全名。
發(fā)布可執(zhí)行程序
和Cook內(nèi)容資源過程相似,區(qū)別在于這次需要勾選上Build和Package,并合適地設(shè)置。
掛載(Mount)Pak并異步加載內(nèi)容
代碼:
.h:
//pak文件中的文件路徑列表TArray<FSoftObjectPath> ObjectPaths;TArray<TSoftObjectPtr<UObject>> ObjectPtrs;.cpp:
void APakMount::MountPak() {//第一步//FPlatformFileManager::Get()返回單例//GetPlatformFile()返回相應(yīng)平臺的PlatformFile,即處理相應(yīng)平臺文件讀寫的對象//因此在Windows平臺,這里返回的是FWindowsPlatformFile的實(shí)例IPlatformFile& InnerPlatform = FPlatformFileManager::Get().GetPlatformFile();//第二步//這里創(chuàng)建了一個FPakPlatformFile,但是未指定當(dāng)前使用什么平臺去讀寫這個文件FPakPlatformFile* PakPlatformFile = new FPakPlatformFile();//第三步//使用相應(yīng)平臺的PlatformFile去初始化PakPlatformFile//第二個參數(shù)是命令行參數(shù),一般都為空PakPlatformFile->Initialize(&InnerPlatform, TEXT(""));//第四步//再將當(dāng)前PlatformFile設(shè)置為"相應(yīng)平臺下pak文件讀寫"的模式FPlatformFileManager::Get().SetPlatformFile(*PakPlatformFile);const FString PakFileFullName = TEXT("D:\\ExamplePak.pak");//測試用MountPointFString MountPoint(FPaths::EngineContentDir());//創(chuàng)建FPakFile對象,同樣使用相應(yīng)平臺的PlatformFile初始化//第二個參數(shù)是pak文件的完整路徑+名稱//第三個參數(shù)是是否有符號?FPakFile* Pak = new FPakFile(&InnerPlatform, *PakFileFullName, false);if (Pak->IsValid()){//具體Mount方法可以參考函數(shù) FPakPlatformFile::Mount//但是其中有大量多余內(nèi)容(例如版本編號處理)//Pak->SetMountPoint(*MountPoint);PakPlatformFile->Mount(*PakFileFullName,1000,*MountPoint);TArray<FString> Files;Pak->FindFilesAtPath(Files, *(Pak->GetMountPoint()), true, false, true);for(auto File : Files){FString Filename, FileExtn;int32 LastSlashIndex;File.FindLastChar(*TEXT("/"), LastSlashIndex);FString FileOnly = File.RightChop(LastSlashIndex + 1); FileOnly.Split(TEXT("."), &Filename, &FileExtn);if (FileExtn == TEXT("uasset")){File = FileOnly.Replace(TEXT("uasset"), *Filename);File = TEXT("/Engine/")+File;ObjectPaths.AddUnique(FSoftObjectPath(File));//將FSoftObjectPath直接轉(zhuǎn)換為TSoftObjectPtr<UObject>并儲存ObjectPtrs.AddUnique(TSoftObjectPtr<UObject>(ObjectPaths[ObjectPaths.Num()-1]));}}MyGI->GetStreamableManager().RequestAsyncLoad(ObjectPaths,FStreamableDelegate::CreateUObject(this,&APakMount::CreateAllChildren));}}掛載的核心方法是 PakPlatformFile->Mount.
掛載之后我們無法直接使用,還需要對其中的資源進(jìn)行列舉,并轉(zhuǎn)換成可以直接加載的格式(包括去掉.uasset后綴名,以及前面加/Engine/)
然后將其存儲到FSoftObjectPath數(shù)組中,并順便轉(zhuǎn)換為TSoftObjectPtr并儲存到一個數(shù)組中,以便后期進(jìn)行訪問。
最后使用StreamableManager進(jìn)行異步加載。
存在的疑問:
使用動態(tài)加載的內(nèi)容
在此例中已知pak中儲存的內(nèi)容均為staticmesh,因此可以直接這樣處理,生成新的StaticMeshComponent組件。
存在的疑問:
如果不知道類型,如何判斷加載的資源類型?
void APakMount::CreateAllChildren() {UE_LOG(LogTemp,Log,TEXT("finished loading assets"));for (int32 i = 0; i < ObjectPtrs.Num(); ++i){UStaticMeshComponent* NewComp = NewObject<UStaticMeshComponent>(this);if (!NewComp){return;}UStaticMesh* staticMesh = Cast<UStaticMesh>(ObjectPtrs[i].Get());NewComp->SetStaticMesh(staticMesh);NewComp->AttachToComponent(GetRootComponent(), FAttachmentTransformRules(EAttachmentRule::KeepRelative, true));NewComp->SetRelativeLocation(FVector(0, (i + 1) * 100.0f, 0));NewComp->RegisterComponent();} }幾個相關(guān)概念/類
資產(chǎn)注冊表(Asset Registry)
是特定資產(chǎn)的信息存儲庫,是在保存package時提取的
AssetManager
是一個單例UObject,它提供在運(yùn)行時掃描和加載主資源的操作。它旨在替換ObjectLibraries當(dāng)前提供的功能,并包裝FStreamableManager以處理實(shí)際的異步加載。引擎資產(chǎn)管理器提供基本管理,但更復(fù)雜的事情(如緩存)可以由特定于游戲的子類實(shí)現(xiàn)。
主要資產(chǎn)(Primary Assets)
是可以根據(jù)游戲狀態(tài)的變化手動加載/卸載的資產(chǎn)。這包括地圖和游戲特定對象,例如庫存物品或角色類。
輔助資產(chǎn)(Secondary Assets)
是所有其他資產(chǎn),例如紋理,聲音等。這些資產(chǎn)是根據(jù)主資產(chǎn)的使用自動加載的
?
總結(jié)
以上是生活随笔為你收集整理的运行时读取PAK文件的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 车身控制器BCM系统框图
- 下一篇: AtCoder - 2365 Came