UE4资源热更打包工具HotPatcher

UE4资源热更打包工具HotPatcher

https://imzlp.me/posts/17590/

 

Z's Blog

 

UE4资源热更打包工具HotPatcher

发表于 2020-01-15 09:41 | 更新于 2020-06-04 23:49 | 分类于 UE4 HotPatch | 字数统计 6.2k

HotPatcher是我最近写的用于打包UE项目资源热更的工具,用于追踪工程版本的资源变动来打出Patch。支持一键Cook多平台,一键打包多平台Patch,编辑器支持Windows和MacOS,再写一套从服务器下载patch的流程就是一套完整的游戏热更方案。HotPatcher在项目里已经使用了一段时间,目前比较稳定,今天整理了一下文档,开源出来,会持续更新,欢迎提issus。

HotPatcher与UnrealFrontEnd中的Patch不同,UE的Patch是基于Cook出的资产作为版本管理的内容,这样在管理工程时存在问题:同样的工程版本,很难在不同的电脑上打出相同的Patch(除非把Cooked同步提交,很难管理),也无法基于Patch的版本再打出一个Patch,而且我们还需要能够方便地能够把外部文件打包到pak中(如lua文件),并且方便管理工程和Patch版本,这个插件就是为了解决上面这样的问题。

目前支持的引擎版本为UE4.21-UE4.25,最近有很多朋友私信来问插件相关的问题,我创建了个群来讨论UE4热更新和HotPatcher插件的问题(QQ群958363331),欢迎加入。

注意:该插件只能打出包含UE的资源以及添加的外部文件作为热更的内容(支持lua),修改的C++代码无法热更,需要自己设计好架构。如果是纯蓝图项目则可以完全使用这个工具进行热更。

HotPatcher插件支持根据选择只打包指定的资源(可以指定包含过滤器以及忽略过滤器以及可以指定单个资源),支持资源的递归依赖分析(如只打包某个地图及其所有依赖的资源),打包的Path中可以选择不包含未引用的资源,也不会包含未改动的资源,还会分析项目中的无效资产以及忽略重定向器的资源,实现了基于项目资产的版本追踪而无需管理Cooked的内容,只需要在打Patch之前Cook一遍保证Cook的内容是基于最新工程版本的即可。而且还支持Chunk、支持bMonilithic模式,配置化的方式支持随意组合,支持多线程打包支持导出资源的依赖关系,而且还支持通过Commandlet来执行Cook和Patch的生成,可以随意组合自己的出包流程。

除了包含UE的资源文件外,额外的支持:

  • 支持包含项目Cook出的非资源文件。如AssetRegistry.bin/GlobalShaderCache*.bin/ShaderBytecode*.ushaderbytecode;
  • 支持包含引擎、项目、和插件的ini文件;
  • 支持包含外部的文件夹和文件(如lua文件,视频文件等),并且可以自定义挂载点,供运行时访问;
  • 打出的pak中可以不包含任何UE的资源文件(只要在HotPatcher中不添加任何资源即可),方便只更新lua的代码或者只更新Ini之类的配置文件;

插件的其他功能:

  • 支持基于上一个patch版本再打出一个patch版本;
  • 支持检测未cook的资源;
  • 支持版本间的diff,可以看到新增、修改、删除(但是删除的资源在之前的版本的pak中是无法删除的,只是diff展示用)的资源信息;
  • 支持检测重复的文件包含;
  • 支持导出该插件所有的中间生成信息和配置;
  • 支持自定义UnrealPak的参数(可以自己指定加密参数与项目统一);
  • 支持同时打出多个平台的patch;
  • 支持Patch的Chunk,指定在一个Patch版本中把资源分别打包到多个Pak中;
  • 支持检测Chunk的文件包含进行错误处理
  • 支持把Patch中的每个资源单独打包为pak,支持任意资源(包括但不限于UE asset/外部文件/各种cooked的bin数据、ini)只要是hotpatcher里可以添加的都可以单独打成pak。
  • 支持多线程打包pak,不启动UrealPak.exe,提高执行效率。
  • 支持导出所选资源的依赖关系

同时,我也写了一个批量Cook的工具,用于一键Cook指定的多个平台(当然使用命令行也可以),目的就是使用最少的步骤完成任务。

我录了一个插件使用说明的视频(汗,第一次录视频还有点紧张):

 

如果不能翻墙可以看B站的链接:UE4热更新:HotPatcher插件使用教程

插件使用流程

为了方便版本管理,项目一定要使用某种版本控制工具,建议Git.

  1. 打开HotPatcher,选择ByRelease,导出*_Release.json,其中记录了所指定的每个资源的信息;
  2. 使用UE直接打包任意平台的项目(如windows/android/ios)
  3. 在工程中修改/添加/删除资源,修改引擎/项目/插件的设置等;
  4. 打开HotPatch,在Cook项选择你要打Patch的平台并执行Cook;
  5. 打开HotPatcher,选择ByPatch,以上面导出的*_Release.json为基础版本,根据需求选择你需要打到Pak中的内容;
  6. 点击GeneratedPatch,会生成Pak文件和各种信息(其中也包含当前版本的*_Release.json,使Patch可以增量更新)
  7. 生成的Pak中就包含了与上次打出的包中所有差异的内容。

Cook参数说明

HotPatcher中的Cook部分是为了打Patch时方便Cook多个平台,以及方便指定地图(插件会扫描整个项目中的所有地图并列出),不用每次Cook都使用命令行。

 

Cook可选的分为Platforms/Map(s)/Settings

  • Platforms:选择Cook 的平台,可以多选;
  • Map(s):选择要Cook的Map,该选项下会列出当前工程里所有的Map,可以多选(代码里我也提供了列出引擎和插件目录下Map的选项,如果需要可以在HotPatcherEditor.build.cs中通过控制ENABLE_COOK_ENGINE_MAPENABLE_COOK_PLUGIN_MAP的值来自行开启);
  • Filter(s):可以选择只Cook指定的目录,可以添加多个;
  • Settings:选择Cook设置,默认提供了Iterator/UnVersioned/CookAll/Compressed四个选项,我也提供了OtherOptions可以自己指定要Cook 的参数。

注意:Map(s)中的地图和Settings中的CookAll必须要选中其中的一个或者Filters中具有指定的目录才可以执行Cook,如果只选了CookMap,则只会Cook该Map所引用到的资源,没有被引用的不会被Cook,这个需要注意。

点击CookContent之后会将Cook的log输出到UE的OutputLog中。

ByRelease参数说明

ByRelease操作导出的是一个json的文件,记录了导出时所选择的每个Asset资源的HASH值,基于此HASH值我们可以在后续的Patch中知道该资源是不是被修改了。

 

Release Settings

  • VersionId:指定当前导出的资源信息是什么版本。
  • ByPakList:从PakList导入来生成Release的配置。
  • PakListFile:打基础包生成的PakList*.txt文件。

在不通过指定PakList*.txt导出Release的情况下,导出的release.json中只包含项目中有引用的资源,没有引用的不会包含。但是引擎默认打包时会把一些没有引用的资源也打包到里面,这就会导致一些资源在基础包中事实上已经存在了,但是在release.json中没有记录,有用到这些资源的话会导致重复包含(使用时没有问题,只是这些资源在pak中会有两份)。使用PakList*.txt就不会存在这个问题。

  • IncludeFilter:当前Release扫描哪些目录下的资源。
  • IgnoreFilter:当前Release忽略哪些目录下的资源。
  • bAnalysisFilterDependencies:对所选过滤器的资源进行依赖分析
  • AssetRegistryDependencyTypes:对所选过滤器中得资源进行依赖分析时要包含的引用资源类型,依赖于bAnalysisFilterDependencies是否启用。
namespace EAssetRegistryDependencyType
{
	enum Type
	{
		// Dependencies which don't need to be loaded for the object to be used (i.e. soft object paths)
		Soft = 0x01,

		// Dependencies which are required for correct usage of the source asset, and must be loaded at the same time
		Hard = 0x02,

		// References to specific SearchableNames inside a package
		SearchableName = 0x04,

		// Indirect management references, these are set through recursion for Primary Assets that manage packages or other primary assets
		SoftManage = 0x08,

		// Reference that says one object directly manages another object, set when Primary Assets manage things explicitly
		HardManage = 0x10,

		// Note: Also update FAssetRegistryDependencyOptions when adding more flags
	};

	static const Type None = (Type)(0);
	static const Type All = (Type)(Soft | Hard | SearchableName | SoftManage | HardManage);
	static const Type Packages = (Type)(Soft | Hard);
	static const Type Manage = (Type)(SoftManage | HardManage);
}

Soft是具有FSoftObjectReference的资源引用,Hard是直接的资源引用,如果想要Soft和Hard都包含,可以选择Package,这个选项默认情况下选Package就好,除非你自己来处理资源引用关系。

  • IncludeHasRefAssetsOnly:对选中的过滤器中的资源文件进行依赖分析(递归分析至Map),如果资源没有被引用则不会打包到Patch中。
  • IncludeSpecifyAssets:结构的数组,可以指定当前Release中的单个资源,该结构的第一个参数需要指定资源,第二个参数控制是否分析并包含当前指定资源的依赖到pak中。
  • AddExternFileToPak:记录Release中包含的非资源文件
  • AddExternDirectoryToPak:记录Release中包含的非资源文件

AddExternFileToPakAddExternDirectoryToPak对应的是Project Settings-Packing中的Additional Non-Asset Directories To Package等设置,用于标记本地包中所包含的非资源文件。

SaveTo

  • SaveAssetDependency:是否存储当前Release版本中所选资源的依赖关系。
  • SaveReleaseConfig:是否存储当前Release的所有选项信息。
  • SavePath:本次的Release信息存储位置。会在当前目录下创建出名字为VersionId的文件夹,所有的文件在此文件夹中。

注意:导出Release时,资源的包含需要与UE直接打包时的设置一致,因为这里导出的Release是记录使用UE直接打出的包所包含的资源。

ByPatch参数说明

ByPatch是真正执行打包出Pak的工具,可以基于之前导出的版本(通过ByRelease导出的Json文件),也可以包含外部文件/文件夹、配置文件(ini)、Cook出的非资源文件(AssetRegistry.bin等),并且可以指定多个平台,支持输入UnrealPak的参数,可以导出当前Patch的各种信息。

 

支持指定资源过滤器:

 

HotPatcher打Patch的选项解析:

BaseVersion

  • bByBaseVersion:是否是基于某个基础版本的Patch,若为false,则只打包选择的过滤器文件(依然会分析依赖)和添加的外部文件,若为true则必须要指定一个基础版本,否则无法执行Patch。同时该属性也会控制是否生成Diff信息,若为false则不生成Diff(没有基础版本diff也无意义)。
  • BaseVersion:该选项应选择Patch所基于的版本文件,可以ByRelease或者上次一的Patch生成,默认为*_Release.json

PatchSettings

  • VersionId:当前Patch的版本的ID
  • IncludeFilter:当前Patch扫描哪些目录下的资源变动。
  • IgnoreFilter:当前Patch忽略哪些目录下的资源变动。
  • bAnalysisFilterDependencies:对所选过滤器的资源进行依赖分析
  • AssetRegistryDependencyTypes:与Release中描述的含义相同。
  • IncludeHasRefAssetsOnly:对选中的过滤器中的资源文件进行依赖分析(递归分析至Map),如果资源没有被引用则不会打包到Patch中。
  • IncludeSpecifyAssets:结构的数组,可以指定需要打到Pak中的单个资源,该结构的第一个参数需要指定资源,第二个参数控制是否分析并包含当前指定资源的依赖到pak中,第三个参数AssetRegistryDependencyTypesRelease中描述的含义相同。。
  • IncludeAssetRegistry:在当前的Patch打出的Pak中包含AssetRegistry.bin文件。
  • IncludeGlobalShaderCache:在当前的Patch打出的Pak中包含GlobalShaderCache-*.bin文件。
  • IncludeShaderBytecode:在当前Patch打出的Pak中包含PROJECT_NAME\Content\ShaderArchive*.ushaderbytecode文件。
  • IncludeEngineIni:在当前打出的Patch中包含引擎目录下的ini,也会包含平台相关的ini
  • IncludePluginIni:在当前打出的Patch中包含所有启用的插件中的ini(引擎目录和项目目录的插件都会包含)
  • IncludeProjectIni:在当前的Patch打出的Pak中包含项目的ini文件(不会包含DefaultEditor*.ini
  • bEnableExternFilesDiff:是否对添加的外部文件进行Diff比对,用于只打包修改或者新增的外部文件。
  • AddExternFileToPak:添加外部的非资源文件到Pak中,如txt、视频。

AddExternFileToPak的元素要求:

  1. FilePath需要指定所选文件的路径。
  2. MountPath为该文件被打包到Pak中的挂载路径,默认是../../../PROJECT_NAME/下。

在游戏运行时可以通过FPaths::ProjectDir来访问。
如,AAAA.json的MountPath../../../HotPatcherExample/AAAAA.json,在运行时加载的路径:

FPaths::Combine(FPaths::ProjectDir(),TEXT("AAAAAA.json"));

Pak中的所有文件可以通过IPlatformFile来访问。

  • AddExternDirectoryToPak:结构的数组,添加外部文件夹到Pak中,该结构第一个参数(DirectoryPath)为指定系统中的文件夹路径,第二个参数(Mount Point)指定该路径在Pak中的挂载路径;指定文件夹下的所有文件会被递归包含,并且挂载路径均相对于所指定的MountPoint

  • IncludePakVersionFile:是否在当前打出的Patch中存储版本信息。(已废弃)

  • PakVersionFileMountPoint:由IncludePakVersionFile控制是否可以编辑,用于指定*_PakVersion.json文件在Pak文件中的挂载点,默认为../../../PROJECT_NAME/Extention/Versions。(已废弃)

ChunkOptions

我为HotPatch增加了Chunk的功能,支持把一个Patch中的资源分别打包到不同的Pak中去。如把一个Patch中的所有Package打包到一个pak里(或者把当前Patch的指定地图打包到某个pak里),所有的lua打包到另一个pak里。

 

Chunk支持的参数如下:

  • bEnableChunk:是否对当前的Patch执行Chunk
  • ChunkInfos:Chunk信息的列表,用于指定Chunk中应该包含哪些资源。

ChunkInfos的是一个FChunkInfo的结构数组,其结构的成员为:

  • ChunkName:当前Chunk的名字
  • bMonolithic:是否为当前Chunk里的每个资源打出Pak(已支持),在开启bMonolithic模式时,会禁止添加外部文件和ini/Cook的内部数据,不然存放路径会有些歧义。
  • MonolithicPathMode:单片模式的pak存储路径模式,MountPathMount的方式,PackagePath是资源的LongPackageName的路径。
  • bSavePakCommands:是否存储当前Chunk的PakCommand.txt
  • AssetIncludeFilters:指定Chunk中的资源过滤器(注意所选过滤器中的资源不会进行依赖分析)
  • AssetIgnoreFilters:指定Chunk的忽略过滤器
  • bAnalysisFilterDependencies:对所选过滤器的资源进行依赖分析
  • AssetRegistryDependencyTypes:与Release中描述的含义相同。
  • IncludeSpecifyAssets:指定Chunk中包含哪些单个资源,支持进行依赖分析
  • AddExternFileToPak:添加外部文件到Chunk
  • AddExternDirectoryToPak:添加外部目录到Chunk,支持递归分析
  • InternalFiles:用于指定Chunk中是否包含AssetRegistry.binIni等文件

基本上Chunk的参数和Patch选择的参数的一致,可以按照需求配置。

注意:Chunk的原理是:先在Patch的设置中选择资源,会执行一遍整个Patch的资源分析,分析出来的结果用于Chunk配置的过滤,意思就是Chunk中所包含的资源必须是本次Patch的中具有的,一定要注意AssetIncludeFilters不会进行依赖分析,如果你Patch中的过滤器中的资源引用到了其他模块,比如引擎或者插件,在Chunk中也需要指定相应的目录到过滤器。

每个Chunk中所指定的资源可以重复,一份资源可以在ChunkA中包含也可以被ChunkB包含。

而且我还给Chunk增加了错误提示,如果开启了Chunk模式,但是Patch中的所有资源没有在Chunk中全部指定,会在HotPatcher底部的Infomations中提示有哪些资源没有在Chunk中被包含,方便进行错误处理。

bMonolithic模式

  • 会把Chunk中所有的单个资源、文件都单独打包为一个pak
  • 存放路径为该资源的mount point路径

PakOptions

  • PakCommandOptions:该数组可以指定*PakCommand.txt中每条要打包到pak中资源的的参数。
  • ReplacePakCommandTexts:用于替换PakCommand.txt中的文本

 

  • UnrealPakOptions:该数组为UnrealPak.exe程序的参数。如果什么都不指定,默认的配置为UnrealPak.exe PAKFILE.pak -create=PAK_LIST.txt
  • PakTargetPlatforms:该数组为选择要打出的Patch的平台,可以多选,一定要注意所选的平台已经被Cook。

SaveTo

  • SavePakList:是否存储UnrealPak.exe-Create参数文件。
  • SaveDiffAnalysis:是否存储当前的Patch版本与Base版本的差异信息。
  • SaveAssetDependency:是否存储当前Patch版本中所选资源的依赖关系。
  • SavePatchConfig:是否存储当前Patch的所有选项信息。
  • SavePath:本次的Patch信息存储位置。会在当前目录下创建出名字为VersionId的文件夹,所有的文件在此文件夹中。

Commandlet

我给插件提供了两个Commandlet,分别是HotCookerHotPatcher,用于Cook和打Patch,使用方法:

Cooker使用方法:

UE4Editor.exe PROJECT.uproject -run=HotCooker -config="cook-config.json"

在编辑器中导出cook配置的时候如果选中了所有地图,会在导出的配置文件里会把bCookAllMap为true,在Cook的Commandlet里执行就会Cook所有地图了,而且只要bCookAllMap为true就会Cook所有地图,和CookMaps里的地图数量没关系。

Patcher使用方法:

UE4Editor.exe PROJECT.uproject -run=HotPatcher -config="patch-config.json"

他们的-config参数所接收的文件都可以从编辑器中通过插件导出。

Update Log

2020.06.04 Update

 

hxhb

HotPatcher

d1194b , 12 commits behind

87 commits

d1194b, referenced in this article

11 commits

3abfaa, latest

  • 增加Cook导出配置的bCookAllMap属性,当为true时,在Commandlet模式下会Cook工程目录下中所有的地图。
  • 增加ByRelease支持通过PakList*.txt来生成配置,从而可以完全匹配基础包中的所有资源。

2020.06.03 Update

 

hxhb

HotPatcher

2d9552 , 18 commits behind

81 commits

2d9552, referenced in this article

17 commits

3abfaa, latest

  • 增加插件Cook的Commandlet
  • 增加插件Patch的Commandlet

2020.04.27 Update

 

hxhb

HotPatcher

f660157 , something is wrong

N/A commits

f660157, referenced in this article

N/A commits

N/A, latest

Up-to-date

  • 增加Chunk的bMonolithic模式下的MonolithicPathMode,用于指定单片模式下的pak存储路径规则。

2020.04.24 Update

  • 增加是否对过滤器中的资源进行依赖分析的选项

2020.04.23 Update

  • 增加可选引用资源的类型

2020.04.18 Update

  • UnrealOptions默认添加-compressionformats参数。
  • 增加PreviewChunk的选项,在开启Chunk的情况下可以方便地知道哪个chunk中有哪些资源。

2020.04.10 Update

  • 增加ReplacePakCommandTexts选项,可以自己根据需求替换PakCommand.txt中的文本,如替换打到pak中的资源的MountPath

2020.04.09 Update

  • 修复在没有选择过滤器时从PatchSetting生成Chunk的问题/对资源重定向器的溯源操作
  • 修复转换Cooked路径时的问题
  • 支持导出所有pak的信息、删除pakversion选项
  • 支持Release和Patch导出资源的依赖关系
  • 给ExportRelease增加FScopeSlowTask进度显示
  • 增加可以指定PakCommand参数的选项

2020.04.08 Update

  • 支持多线程打包Pak,直接调用ExecuteUnrealPak而不是启动UnrealPak.exe,极大提升效率。
  • 修复PreviewPatch在选中BaseVersion的情况下与Diff信息不一致的问题

2020.04.07 Update

  • 支持bMonolithic模式,可以把所有引用每个资源单独打到一个pak中。
  • 统一了Asset、Cooked的bin、外部文件、ini等所有文件的pak方式。

 

 

2020.04.03 Update

  • 完成Patch的Chunk功能,统一Patch和Chunk的打包流程
  • 代码优化、流程梳理
  • 去除IncludePakVersionFilePakVersionFileMountPoint选项

2020.04.02 Update

  • 增加Patch的Chunk功能
  • 修复FPatcherSpecifyAsset序列化与反序列化的问题
  • 优化组织结构

2020.03.28 Update

  • 修复当基于基础版本打patch时导出的*Release.json不全的问题。

2020.03.05 Update

  • 修复当Cook的进程异常退出时没有清掉任务状态的问题。
  • 在代码中增加Cook时可选Engine或Plugin中的地图,在HotPatcherEditor.build.cs中通过控制ENABLE_COOK_ENGINE_MAPENABLE_COOK_PLUGIN_MAP的值来自行开启。

2020.02.14 Update

  • 增加了Patch和Release配置的导入导出
  • 生成Pak的默认命名改成XXX_TARGET_PLATFORM_001_P.pak
  • 修复了一些潜在问题,建议更新。

2019.12.08 Update

  • 新增是否对资源进行依赖扫描的选项,增加diff预览。

 

2020.02.19 Update

  • 为插件增加了导出release时可以选择添加外部文件和文件夹,对应ue打包时添加的非资源外部文件目录。还支持外部文件的diff(可选),对于指定的外部文件和目录,会检测只有修改或者新增的文件才会打包到pak中。

2020.01.13 Update

  • 新增生成时的错误信息提示,对未Cook资源的扫描以及重复添加的外部文件进行检测,增加可以指定特定资源到Pak中,并且可选是否对该资源进行依赖分析。

 

2020.01.14 Update

  • 修复会扫描到Redirector会提示Redirector的资源未Cooked,为ExportRelease增加IncludeSpecifyAssets,可以指定某个资源了(如只指定某个地图)。

 

2020.01.19 Update

  • 增加指定要Cook的目录

 

Q&A

HotPatcher开源之后有一些朋友陆续找我单独聊到一些问题,有些朋友可能会遇到相同的问题,这里用于收集一些Q&A的内容。

  1. 使用HotPatcher打包出来的pak在挂载时Crash并具有Pak master signature table check failed for pak提示

 

这是由于打出本体包的时候在项目设置中设置了Signing加密,需要在HotPatcher中的UnrealPak参数中添加相同的加密参数。

IPlatformFilePak.cpp中的RegisterPakFile中,同样做了判断:

// Runtime/PakFile/Private/
uint16* RegisterPakFile(FName File, int64 PakFileSize)
{
  uint16* PakIndexPtr = CachedPaks.Find(File);
  if (!PakIndexPtr)
  {
    FString PakFilename = File.ToString();
    check(CachedPakData.Num() < MAX_uint16);
    IAsyncReadFileHandle* Handle = LowerLevel->OpenAsyncRead(*PakFilename);
    if (!Handle)
    {
      return nullptr;
    }
    CachedPakData.Add(FPakData(Handle, File, PakFileSize));
    PakIndexPtr = &CachedPaks.Add(File, CachedPakData.Num() - 1);
    UE_LOG(LogPakFile, Log, TEXT("New pak file %s added to pak precacher."), *PakFilename);

    FPakData& Pak = CachedPakData[*PakIndexPtr];

    if (SigningKey.IsValid())
    {
      // Load signature data
      FString SignaturesFilename = FPaths::ChangeExtension(*PakFilename, TEXT("sig"));
      IFileHandle* SignaturesFile = LowerLevel->OpenRead(*SignaturesFilename);
      ensure(SignaturesFile);
      FArchiveFileReaderGeneric* Reader = new FArchiveFileReaderGeneric(SignaturesFile, *SignaturesFilename, SignaturesFile->Size());
      Pak.Signatures.Serialize(*Reader);
      delete Reader;
      Pak.Signatures.DecryptSignatureAndValidate(SigningKey, PakFilename);

      // Check that we have the correct match between signature and pre-cache granularity
      int64 NumPakChunks = Align(PakFileSize, FPakInfo::MaxChunkDataSize) / FPakInfo::MaxChunkDataSize;
      ensure(NumPakChunks == Pak.Signatures.ChunkHashes.Num());
    }
  }
  return PakIndexPtr;
}
  1. 在本体包中开启signature后,打包出来的Pak无法被挂载
    同样是pak的signature的错误,是因为没有为pak生成对应的.sig文件。
    Log中的内容如下:
LogPakFile: Warning: Couldn't find pak signature file '../../../Pak/Content/Paks/1.0.3_WindowsNoEditor_P.pak'
LogPakFile: Warning: Unable to create pak "../../../Pak/Content/Paks/1.0.3_WindowsNoEditor_P.pak" handle
LogPakFile: Warning: Failed to mount pak "../../../Pak/Content/Paks/1.0.3_WindowsNoEditor_P.pak", pak is invalid

这是因为打出本体包时Project Setting-Crypto中的bEnablePakSigning被设置成了true,这样对打出来的包里的所有pak都会执行校验,目的就是为了确保只有自己打包的pak才可以被加载
 

相关的代码处理在:

// Runtime/PakFile/Private/SignedArchiveReader.cpp
FChunkCacheWorker::FChunkCacheWorker(FArchive* InReader, const TCHAR* Filename)
  : Thread(nullptr)
  , Reader(InReader)
  , QueuedRequestsEvent(nullptr)
  , ChunkRequestAvailable(nullptr)
{
  FString SigFileFilename = FPaths::ChangeExtension(Filename, TEXT("sig"));
  FArchive* SigFileReader = IFileManager::Get().CreateFileReader(*SigFileFilename);

  if (SigFileReader == nullptr)
  {
    UE_LOG(LogPakFile, Fatal, TEXT("Couldn't find pak signature file '%s'"), *SigFileFilename);
  }

  Signatures.Serialize(*SigFileReader);
  delete SigFileReader;
  Signatures.DecryptSignatureAndValidate(Filename);

  const bool bEnableMultithreading = FPlatformProcess::SupportsMultithreading();
  if (bEnableMultithreading)
  {
    QueuedRequestsEvent = FPlatformProcess::GetSynchEventFromPool();
    ChunkRequestAvailable = FPlatformProcess::GetSynchEventFromPool();
    Thread = FRunnableThread::Create(this, TEXT("FChunkCacheWorker"), 0, TPri_BelowNormal);
  }
}

所以,如果在用HotPatcher打包pak时没有与项目指定相同的加密参数,则导致放入包内的pak会加载失败(因为验证失败了)。
解决的办法就是,在使用HotPatcher时指定与项目相同的加密信息,当直接使用UE打出本体包时,会默认在下列路径中生成一个Crypto.json文件:

PROJECT_DIRECTORY\Saved\Cooked\WindowsNoEditor\PROJECT_NAME\Metadata\Crypto.json

它里面的内容是根据Project Setting-Crypto中的选项生产的。
使用方法为:
在HotPatcher的UnrealPak参数项添加参数:-cryptokeys="Crypto.json"(在UE4.23+中还需要添加-sign参数):
 

重新生成Pak就会在Pak的目录里生成与Pak同名的.sig文件了,把paksig文件一同拷贝到挂载目录里就可以了。

UnrealPak的参数可以看我之前的一篇文章:UE4工具链配置与开发技巧#UnrealPak的参数

更新计划

为了使HotPatcher更易用和更强大,我会在这里记录一些不错的更新建议。

  1. 增加支持多线程扫描资源依赖分析,目前在工程内资源数量相当大的情况下(数万个),资源的递归依赖分析会比较慢,开多个线程可以显著减少耗时。
  2. 在UnrealPak下增加直接指定Pak加密参数的选项(开放了可以指定UnrealPak的参数,自己指定加密的参数即可)
  3. 指定Cook单个资源
  4. 把打包出的Pak命名从XX_TARGET_PLATFORM_P.pak改成XX_TARGET_PLATFORM_0_P或者中间的数字可以指定。
  5. Patch和Release配置文件的导入和导出、以及快速地清理配置。
  6. 为release增加包含外部文件的选项,与UE的打包时包含外部文件同步。
  7. 增加对外部文件的Diff,不用每次打包时把所有的外部文件都打包到pak中。
  8. 在一个Patch中打包出多个pak文件,可选哪些资源打到哪个Pak中。
  9. ChunkbMonolithic模式增加多线程支持
  10. 增加Commandlet的支持
本文会持续更新HotPatcher的文档。

 

扫描二维码,分享此文章

本文标题:UE4资源热更打包工具HotPatcher
文章作者:ZhaLiPeng
发布时间:2020年01月15日 09时41分
更新时间:2020年06月04日 23时49分
本文字数:本文一共有6.2k字
原始链接:https://imzlp.me/posts/17590/
专栏链接:https://zhuanlan.zhihu.com/p/103743690/
许可协议: CC BY-NC-SA 4.0
捐赠BTC:1CbUgUDkMdy6YRmjPJyq1hzfcpf2n36avm
转载请保留原文链接及作者信息,谢谢!

您的捐赠将鼓励我继续创作!

# 虚幻引擎 # UE4 # 热更新 # UnrealEngine # 补丁包

UE4项目的设计规范和代码标准

UE4源码分析:修改游戏默认的数据存储路径

 

选择语言​▼

  • 文章目录
  • 站点概览

 

 

  1. 1. 插件使用流程
  2. 2. Cook参数说明
  3. 3. ByRelease参数说明
    1. 3.1. Release Settings
    2. 3.2. SaveTo
  4. 4. ByPatch参数说明
    1. 4.1. BaseVersion
    2. 4.2. PatchSettings
    3. 4.3. ChunkOptions
    4. 4.4. PakOptions
    5. 4.5. SaveTo
  5. 5. Commandlet
  6. 6. Update Log
    1. 6.1. 2020.06.04 Update
    2. 6.2. 2020.06.03 Update
    3. 6.3. 2020.04.27 Update
    4. 6.4. 2020.04.24 Update
    5. 6.5. 2020.04.23 Update
    6. 6.6. 2020.04.18 Update
    7. 6.7. 2020.04.10 Update
    8. 6.8. 2020.04.09 Update
    9. 6.9. 2020.04.08 Update
    10. 6.10. 2020.04.07 Update
    11. 6.11. 2020.04.03 Update
    12. 6.12. 2020.04.02 Update
    13. 6.13. 2020.03.28 Update
    14. 6.14. 2020.03.05 Update
    15. 6.15. 2020.02.14 Update
    16. 6.16. 2019.12.08 Update
    17. 6.17. 2020.02.19 Update
    18. 6.18. 2020.01.13 Update
    19. 6.19. 2020.01.14 Update
    20. 6.20. 2020.01.19 Update
  7. 7. Q&A
  8. 8. 更新计划

 

 

© 2014 - 2020 | 424.6k

Github Pages & Hexo Deploy

 

 

 

 

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页