【UE4 C++】 UnrealPak 與 Pak 的制作、掛載、加載


簡介

  • 通過 UnrealPak,可以將資源打包成 Pak 文件
  • Pak文件是UE4游戲生成的數據包文件。
    • Pak 之前一般先有 Cooked 步驟,將資源烘焙為對應平台支持的資源

      • 一般打包后的項目使用 Cooked 過的 pak
      • PIE 使用未 Cooked 過的 pak
    • Pak 一般放在游戲路徑下的Content\Paks

    • 一個Pak 可以包含多個資源,可以是項目資源,也可以是非項目資源,如文本、視頻等

    • 可用於熱更新或DLC

    • 引擎自動加載 pak 的目錄

      • [ProjectName]/Content/Paks
      • [ProjectName]/Saved/Paks
      • Engine/Content/Paks

      image


UnrealPak

  • 命令行為一段,為方便閱讀,故分行顯示

支持參數(4.26)

UnrealPak <PakFilename> -Test
測試Pak文件能否打開(是否加密)

UnrealPak <PakFilename> -Verify

UnrealPak <PakFilename> -Info

UnrealPak <PakFilename> -List [-ExcludeDeleted]
查看

UnrealPak <PakFilename> <GameUProjectName> <GameFolderName> -ExportDependencies=<OutputFileBase> -NoAssetRegistryCache -ForceDependsGathering

UnrealPak <PakFilename> -Extract <ExtractDir> [-Filter=<filename>]
解包

UnrealPak <PakFilename> -Create=<ResponseFile> [Options]
打包

UnrealPak <PakFilename> -Dest=<MountPoint>
更改MountPoint

UnrealPak <PakFilename> -Repack [-Output=Path] [-ExcludeDeleted] [Options]

UnrealPak <PakFilename1> <PakFilename2> -diff
對比兩個 pak

UnrealPak <PakFolder> -AuditFiles [-OnlyDeleted] [-CSV=<filename>] [-order=<OrderingFile>] [-SortByOrdering]

UnrealPak <PakFilename> -WhatsAtOffset [offset1] [offset2] [offset3] [...]

UnrealPak <PakFolder> -GeneratePIXMappingFile -OutputPath=<Path>

Options:
	-blocksize=<BlockSize>
	 塊大小
	
	-bitwindow=<BitWindow>
	
	-compress
	 壓縮
	
	-order=<OrderingFile>
	 Cooker烘焙時的順序文件

	-diff (requires 2 filenames first)
	 比較 pak
	
	-enginedir (specify engine dir for when using ini encryption configs)
	 引擎目錄
	
	-projectdir (specify project dir for when using ini encryption configs)
	 項目目錄
	
	-encrypt
	 加密

	-encryptindex (encrypt the pak file index, making it unusable in unrealpak without supplying the key)
	 加密索引,不提供key無法解密。可以在Project Setting -> Packaging - > Encrypt the pak index....配置

	-encryptionini (specify ini base name to gather encryption settings from)
	 單獨加密ini文件,可以在Project Setting -> Packaging - > Encrypt ini files inside pak files配置

	-encryptionkeyoverrideguid (override the encryption key guid used for encrypting data in this pak file)
	
	-sign (generate a signature (.sig) file alongside the pak)
	 RSA簽名:0x<私鑰指數>+0x<私鑰系數>+0x<公鑰指數>  或者指定<KeyFileName>	
	
	-aes
	 32位密鑰

	-extracttomountpoint (Extract to mount point path of pak file)
	
	-compressionformat[s]=<Format[,format2,...]> (set the format(s) to compress with, falling back on failures)
	
	
	-fallbackOrderForNonUassetFiles (if order is not specified for ubulk/uexp files, figure out implicit order based on the uasset order. Generally applies only to the cooker order)
	
	-moveBulkAndUptnlOrderLast (move all ubulk and uptnl files after all other resources in the first Order list. Ubulk and uptnl files will be at the end, and will preserve their order)

補充:
	-abslog
	 指定打包日志文件路徑

	-UTF8Output
	 UTF8輸出

	-tempfiles=
	 烘焙文件臨時存儲

	-multiprocess
	 多線程
	
	patchpaddingalign=
	 數據塊對齊

	-generatepatch=
	 打Patch包時會添加的參數,后面指定要比較的Release文件

	-cryptokeys=<Crypto.json>
	 指定 Crypto.json

設置環境變量

  • 為方便使用命令行,設置環境變量

    image

  • UnrealPak.exe 是獨立應用,也可以單獨拷貝出來使用

  • 也可以使用 bat 文件。

Cook 文件打包 Pak

  • 注意 * 表示該文件夾下的所有目錄
  • 默認調用方法
UnrealPak "C:\Users\Alice\Documents\Unreal Projects\DesignPatterns\MyPaks\Maps.pak" "C:\Users\Alice\Documents\Unreal Projects\DesignPatterns\Saved\Cooked\WindowsNoEditor\DesignPatterns\Content\Maps\*" -compress
  • 文本調用方法

    • 設置ResponseFile

      • 第一個路徑為 Cook 后的資源路徑
      • 第二個路徑為 掛載路徑
      "C:\Users\Alice\Documents\Unreal Projects\DesignPatterns\Saved\Cooked\WindowsNoEditor\DesignPatterns\Content\Maps\NewMap.uexp" "../../../DesignPatterns/Content/Maps/NewMap.uexp" -compress
      "C:\Users\Alice\Documents\Unreal Projects\DesignPatterns\Saved\Cooked\WindowsNoEditor\DesignPatterns\Content\Maps\NewMap.umap" "../../../DesignPatterns/Content/Maps/NewMap.umap" -compress
      "C:\Users\Alice\Documents\Unreal Projects\DesignPatterns\Saved\Cooked\WindowsNoEditor\DesignPatterns\Content\Maps\NewMap_BuiltData.uasset" "../../../DesignPatterns/Content/Maps/NewMap_BuiltData.uasset" -compress
      "C:\Users\Alice\Documents\Unreal Projects\DesignPatterns\Saved\Cooked\WindowsNoEditor\DesignPatterns\Content\Maps\NewMap_BuiltData.ubulk" "../../../DesignPatterns/Content/Maps/NewMap_BuiltData.ubulk" -compress
      "C:\Users\Alice\Documents\Unreal Projects\DesignPatterns\Saved\Cooked\WindowsNoEditor\DesignPatterns\Content\Maps\NewMap_BuiltData.uexp" "../../../DesignPatterns/Content/Maps/NewMap_BuiltData.uexp" -compress
      "C:\Users\Alice\Documents\Unreal Projects\DesignPatterns\Saved\Cooked\WindowsNoEditor\DesignPatterns\Content\Maps\LightMap\LightMap.uexp" "../../../DesignPatterns/Content/Maps/LightMap/LightMap.uexp" -compress
      "C:\Users\Alice\Documents\Unreal Projects\DesignPatterns\Saved\Cooked\WindowsNoEditor\DesignPatterns\Content\Maps\LightMap\LightMap.umap" "../../../DesignPatterns/Content/Maps/LightMap/LightMap.umap" -compress
      
    • 執行腳本

      UnrealPak "C:\Users\Alice\Documents\Unreal Projects\DesignPatterns\MyPaks\Maps.pak" -create="C:\Users\Alice\Documents\Unreal Projects\DesignPatterns\MyPaks\MyPakLisk.txt"
      
    • bat 文件

      @ECHO OFF
      ECHO ------------------------------------------------------------------
      ECHO		UnrealPak Strart Create Pak
      ECHO ------------------------------------------------------------------
      
      set PakFilename="C:\Users\Alice\Documents\Unreal Projects\DesignPatterns\MyPaks\Maps.pak"
      set ResponseFile="C:\Users\Alice\Documents\Unreal Projects\DesignPatterns\MyPaks\MyPakLisk.txt"
      set UnrealPak="C:\SoftwareInstallation\EpicGames\UE_4.26\Engine\Binaries\Win64\UnrealPak.exe"
      CALL %UnrealPak% %PakFilename%  -create=%ResponseFile%
      
      ECHO ------------------------------------------------------------------
      ECHO		Finished
      ECHO ------------------------------------------------------------------
      PAUSE
      
  • 加密pak

    unrealpak PAK_NAME.pak -create=ResponseFile -compress -encrypt -encryptindex -aes=32bit_AESKey
    
    // 在\Config\DefaultEncryption.ini文件中查找AES的密鑰,4.26 提示用 -cryptokeys
    -encryptindex -encryptionini -enginedir="<EngineDir>" -projectdir="<GameDir>" -platform=Windows
    
    // 新版使用,可將項目設置中的 Encryption Key 填入到json中
    //json 格式為 { "EncryptionKey": {"Key": "tmAjE6/depliVQgG3XgI60bwrQE2iGgg5n8VRPXrGm0="} }
    -encrypt -encryptindex -compress -cryptokeys=<Crypto.json>
    
  • 項目打包截取的部分日志

    • 可以在項目設置中設置簽名與加密
    Output from:
    "C:\Users\Alice\Documents\Unreal Projects\DesignPatterns\DesignPatterns.uproject"
     "C:\Users\Alice\Documents\Unreal Projects\DesignPatterns\Saved\StagedBuilds\WindowsNoEditor\DesignPatterns\Content\Paks\DesignPatterns-WindowsNoEditor.pak"
     -create="C:\Users\Alice\AppData\Roaming\Unreal Engine\AutomationTool\Logs\C+SoftwareInstallation+EpicGames+UE_4.26\PakList_DesignPatterns-WindowsNoEditor.txt"
     -cryptokeys="C:\Users\Alice\Documents\Unreal Projects\DesignPatterns\Saved\Cooked\WindowsNoEditor\DesignPatterns\Metadata\Crypto.json"
     -order="C:\Users\Alice\Documents\Unreal Projects\DesignPatterns\Build\WindowsNoEditor\FileOpenOrder\CookerOpenOrder.log"
     -encryptindex
     -patchpaddingalign=2048
     -platform=Windows
     -multiprocess
     -abslog="C:\Users\Alice\AppData\Roaming\Unreal Engine\AutomationTool\Logs\C+SoftwareInstallation+EpicGames+UE_4.26\UnrealPak-DesignPatterns-WindowsNoEditor-2021.05.22-17.58.51.txt"
    

    image

解包 Pak

  • 解普通 pak

    UnrealPak "C:\Users\Alice\Documents\Unreal Projects\DesignPatterns\MyPaks\Maps.pak" -Extract "C:\Users\Alice\Documents\Unreal Projects\DesignPatterns\ExtractPak"
    
  • 解加密 pak

    unrealpak <PakFilename> -Extract <ExtractDir> -aes=32bit_AESKey
    
    unrealpak <PakFilename> -Extract <ExtractDir> -cryptokeys="[ProjectName]\Saved\Cooked\WindowsNoEditor\[ProjectName]\Metadata\Crypto.json"
    
    unrealpak <PakFilename> -Extract -encryptindex -encryptionini -enginedir="<EngineDir>" -projectdir="<GameDir>" -platform=Windows
    

查看Pak

  • -Test

  • -Verify

  • -Info

  • -List [-ExcludeDeleted]

  • 必要時需要加上密鑰簽名

    image


Pak 文件的掛載與加載

掛載與加載的區別

  • 掛載(Mount)
    • 告訴系統可以從哪些路徑訪問Pak文件包含的文件,起到提供路徑的作用
    • 掛載pak文件之后,可以通過常規的方式來訪問其中的文件
    • FPlatformFileManager
    • PakPlatformFile
      • 可以掛載多個Pak文件,其內部有一個記錄FPakFile的List
  • 加載(Load)
    • 一般指把文件的內容加載到內存中了

簡單使用-測試資源准備

  • 簡單實現用UI切換材質的gong

  • ToPak 為要打包的資源,不建議和掛載點路徑 不一致,容易導致依賴丟失

    ToPak
    ├─ BP_PakTest1.uasset
    ├─ UMG_Test.uasset
    ├─ Material
    │    ├─ M_Pak.uasset
    │    ├─ M_Pak_Inst.uasset
    │    └─ M_Pak_Inst1.uasset
    └─ Texture
         ├─ BlueHPTex.uasset
         ├─ GreyHPTex.uasset
         └─ RedHPTex.uasset
    
    
  • BP_PakTest1

    image

  • UMG_Test

    image

  • UnrealPak打包

    image

指定掛載

  • .Build.cs 添加 PakFile 模塊

  • 主要代碼

    TSharedPtr<FPakPlatformFile> PakPlatformFile;
    
    	IPlatformFile* InnerPlatformFile;
    
    	UFUNCTION(BlueprintCallable)
    	bool LoadPak(const FString& PakPath);
    
    void ALoadPakActor::BeginPlay()
    {
    	Super::BeginPlay();
    
    	
    	//獲取當前使用的平台
    	InnerPlatformFile = &FPlatformFileManager::Get().GetPlatformFile();
    	UE_LOG(LogTemp, Warning, TEXT("InnerPlatformFile: %s"), InnerPlatformFile->GetName());
    
    	//初始化PakPlatformFile 
    	PakPlatformFile = MakeShareable(new FPakPlatformFile());
    	PakPlatformFile.Get()->Initialize(InnerPlatformFile, TEXT(""));
    }
    
    bool ALoadPakActor::LoadPak(const FString& PakPath)
    {
    	bool Result = false;
    
    	// 切換到 pak平台
    	FPlatformFileManager::Get().SetPlatformFile(*PakPlatformFile.Get());
    
    	// 獲取pak文件
    	TSharedPtr<FPakFile> PakFile = MakeShareable(new FPakFile(InnerPlatformFile, *PakPath, false));
    	FString MountPoint = PakFile->GetMountPoint();
    	UE_LOG(LogTemp, Warning, TEXT("Default Mount Point: %s"), *MountPoint);
    
    #if WITH_EDITOR
    	// PIE模式下,MountPoint 使用絕對路徑
    	// 打包模式下,MountPoint 使用相對路徑
    	MountPoint = FPaths::ConvertRelativePathToFull(MountPoint);
    	UE_LOG(LogTemp, Warning, TEXT("Default Mount Point Full Path: %s"), *MountPoint);
    
    	// 設置pak文件的Mount點,因為在制作pak的時候已在文本中設定 mount point,故省略此步驟
    	MountPoint = FPaths::ProjectContentDir() + TEXT("DLC/");
    
    	// 可在此處檢測 默認MountPoint的絕對路徑釋放和本條語句執行結果是否一致
    	MountPoint = FPaths::ConvertRelativePathToFull(MountPoint);
    
    	PakFile->SetMountPoint(*MountPoint);
    	UE_LOG(LogTemp, Warning, TEXT("New Mount Point Full Path: %s"), *MountPoint);
    #endif
    
    	// 對pak文件進行掛載
    	if (PakPlatformFile->Mount(*PakPath, 1, *MountPoint))
    	{
    		// 加載 pak 里的資源
    		UClass* BP_PakTestClass = LoadClass<AActor>(nullptr, TEXT("Blueprint'/Game/DLC/BP_PakTest1.BP_PakTest1_C'"));
    		if (BP_PakTestClass)
    		{
    			GetWorld()->SpawnActor<AActor>(BP_PakTestClass, FVector::ZeroVector, FRotator::ZeroRotator);
    			Result = true;
    		}	
    		else
    			UE_LOG(LogTemp, Error, TEXT("Load BP_PakTest1 Class Failed"));
    
    		// 遍歷 pak 里的資源
    		TArray<FString> AssetList;
    		PakFile->FindPrunedFilesAtPath(AssetList, *PakFile->GetMountPoint(), true, false, true);
    		for (FString itemPath : AssetList)
    		{
    			UE_LOG(LogTemp, Warning, TEXT("%-30s\t%s"), *FPackageName::GetShortName(itemPath), *itemPath);
    			// 此處可異步加載資源
    		}			
    	}
    	else
    		UE_LOG(LogTemp, Error, TEXT("Mount Pak Failed"));
    		
    	// 設置回原來的PlatformFile, UE4.26 
    	// 不加該條語句,本測試崩潰,報錯:Pure Virtual function being called while application was running
    	FPlatformFileManager::Get().SetPlatformFile(*InnerPlatformFile);
    
    	return Result;
    }
    

    image

注意

  • 如果可以掛起,但無法加載,可以測試相對路徑與絕對路徑的問題
    • PIE模式下,MountPoint 使用絕對路徑
    • 打包模式下,MountPoint 使用相對路徑
  • pak 文件右鍵屬性賦值的路徑,有時會導致掛載失敗(無緣無故的bug調了一下午,煩躁)
  • PakPlatformFile->Unmount() 可卸載
  • PakPlatformFile->GetMountedPakFilenames() 獲取已加載的pak,可用於檢測,避免重復加載

使用 FCoreDelegates 掛載

  • 默認使用 Pak里的Mount Point

  • 測試時,PIE模式下掛載成功,但是loadClass 失敗,應該是路徑的問題.打包后沒問題

  • 修改 部分代碼

    bool ALoadPakActor::LoadPak(const FString& PakPath)
    {
    	bool Result = false;
    	if (FCoreDelegates::OnMountPak.IsBound())
    	{
    		if (FCoreDelegates::OnMountPak.Execute(PakPath, 0, nullptr))
    		{
    			UClass* BP_PakTestClass = LoadClass<AActor>(nullptr, TEXT("Blueprint'/Game/DLC/BP_PakTest1.BP_PakTest1_C'"));
    			if (BP_PakTestClass)
    			{
    				GetWorld()->SpawnActor<AActor>(BP_PakTestClass, FVector::ZeroVector, FRotator::ZeroRotator);
    				Result = true;
    			}
    			else
    				UE_LOG(LogTemp, Error, TEXT("Load BP_PakTest1 Class Failed"));
    
    		}
    		else
    			UE_LOG(LogTemp, Error, TEXT("OnMountPak.Execute() Failed"));
    	}
    	else
    		UE_LOG(LogTemp, Error, TEXT("OnMountPak.IsBound() Failed"));
    
    	return Result;
    }
    

修復

修復引用

  • 最開始資源是存放在 ToPak 目錄下,但是掛載在 DLC 目錄下 ,因而容易造成引用混亂
  • 確保 pak 里的其他資源加載,本問省略了該步驟
  • 因為使用一個工程進行測試,現在將資源 轉移到 DLC 下打包pak,使用時,將源資源移動到或者刪除。
  • 這樣 BP_PakTest1 和 UMG_Test 可以保持引用

材質丟失

  • 由於Pak 並沒有包含 Shader,從而導致依賴丟失

  • 解決方法1:ProjectSetting → Packaging → Share Material Shader Code 關閉共享,但這樣會使 Shader 變多

  • 解決方法2:將母材質至於項目內,使用 Material Instanse 打包進 pak, PIE 下也可以生效

    image

    • FShaderLibraryInstance、FRHIShaderLibrary、openlibrary、shaderbytecode

掛載加密pak

  • 默認 打包 cook 會生成 Crypto.json,路徑為 [ProjectName]\Saved\Cooked\WindowsNoEditor\[ProjectName]\Metadata\Crypto.json

  • 自定義最簡 Crypto.json

    { 
     	"EncryptionKey": {"Key": "tmAjE6/depliVQgG3XgI60bwrQE2iGgg5n8VRPXrGm0="} 
    }
    
  • 打包 pak

    UnrealPak "C:\Users\Alice\Documents\Unreal Projects\tips\MyPak\PakTest.pak"
     -create="C:\Users\Alice\Documents\Unreal Projects\tips\MyPak\PakList.txt"
     -encryptindex
     -compress
     -cryptokeys="C:\Users\Alice\Documents\Unreal Projects\tips\Config\Crypto.json"
    
  • 修改代碼

    // 在掛載前使用,本文調用位置為 ALoadPakActor::LoadPak() 首出
    // 綁定PAK解密函數
    FCoreDelegates::GetPakEncryptionKeyDelegate().BindUObject(this, &ALoadPakActor::InitEncrypt);
    
    //解密函數,Base64轉換
    void ALoadPakActor::InitEncrypt(uint8* Key) {
    	FString KeyStr = TEXT("tmAjE6/depliVQgG3XgI60bwrQE2iGgg5n8VRPXrGm0=");
    	TArray<uint8> KeyBase64Ary;
    	FBase64::Decode(KeyStr, KeyBase64Ary);
    	char* KeyU8 = TCHAR_TO_UTF8(*KeyStr);
    	FMemory::Memcpy(Key, KeyBase64Ary.GetData(), FAES::FAESKey::KeySize);
    }
    

擴展工具


參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM