xiaozongpeng 发表于 2022-6-14 19:34

UE4 原生热更实现方案

(题图来自于: https://www.lifewire.com/what-is-a-patch-2625960)
前言

对于手游来说,热更是非常重要的一个功能。UE4已经提供了比较完备的热更新机制以及配套的工具链,对于一般的的热更需求或者分包下载需求来说已经足够使用了,不必借助于第三方工具就可以完全实现。与某些厂商提供的基于Package的更新相比,UE4 提供的热更新仅限于Pak文件的内容,也就是说可以热更新脚本代码(Lua、JavaScript等)、UAsset资源等,而无法更新诸如可执行文件、动态链接库等 Pak 内容以外的文件。
网上其实有很多介绍 UE4 热更的文章,但是大多都只介绍了其中的一个侧面,并没有从头到尾形成一个完成的闭环。本文从 Chunk 划分开始,涵盖整个热更方案的流程,直到最后热更结果的测试与验证。
本文假设读者已经有了一定程度的UE4使用经验和版本构建经验,例如:

[*]能够独立阅读 UE4 官方文档(本文中使用的官方文档链接都为英文版,如果需要中文版可以在打开后页面右上角切换语言)
[*]至少理解 Project Settings 中大部分与构建相关的参数;
[*]理解 INI 配置文件的用法及修改方法;
[*]会使用 Project Launcher 进行版本构建;
[*]会使用 RunUAT 等基础构建用的命令行工具。
整体流程

总体上来说可以分为下面几个部分:

[*]Chunk/Pak 划分:使用 Asset Manager 将 Pak 划分为多个 Chunk,主要目的是为了分块下载,而且还可以做到按需下载特定的资源。
[*]生成基础包:热更的基础是必须有一个完整的整包作为基础,后续热更都是基于这个整包进行增量更新。如果整包是个仅仅能启动的小包的话,那么热更也可以作为分包下载来使用,方式是基本一致的。
[*]生成热更包:热更包要多次迭代,后面的热更包是基于基础包和再次之前所有的热更包来生成的。在网上有人说UE4的原生热更机制不支持基于热更包的热更包,这是错误的,可能是他在使用的时候选错了配置。
[*]更新服务器部署:UE4的产出结果还没有完善到最后一公里,所以有些更新需要的数据需要手动创建,官方文档中也有相关的说明,基本上只要按照说明处理就可以了。
[*]客户端更新机制:UE4在多年的迭代中,使用过几种不同的实现方式,现在最新的方式是使用 ChunkDownloader 来实现,需要编写的代码并不多,实现起来非常简单。
[*]更新验证:需要多次进行更新来验证更新的正确性,确保热更包可以迭代更新;并且还需要验证热更包里只有我们需要的内容,而不是将多余的资源也一同打入热更包。
Chunk/Pak 划分

在处理划分之前,需要对一些概念做出区分,否则可能会感觉UE的这一套机制有些难以理解。

[*]Chunk: UE在使用 Chunk 这个词时有些混乱,在这里的含义是将 Pak 分为多个部分。但是在 HTTP Chunk 这个用法中,Chunk 表示一个固定大小的下载块,一个Pak Chunk 可能会划分为多个 HTTP Chunk,从而进行分块下载。好在现在 HTTP Chunk 已经过时了,在现在的语境下将 Chunk 理解为 Pak Chunk 就已经足够了。
[*]Primary Asset: 可以理解为重点资产,或者是会关联一批资产的根资产。例如一个 Level 会引用很多的 Static Mesh、Texture、Material 等,凡是被 Primary Asset 引用的资产,如果其没有被定义为一个 Primary Asset 的话,那么它就是一个 Secondary Asset。当一个 Primary Asset 被加入到某个 Chunk 时,其引用的 Secondary Asset 也会被同时加入到这个相同的 Chunk。一般来说,可以将每个 Primary Asset 都划分到一个单独的 Pak Chunk 之中,这样就可以实现较为细粒度的资源控制。
由于 UE4 中的 Asset Manager 配置只囊括了 UAsset 的部分,所以这里的资源划分分为两个部分,分别是 UAsset 部分,和 Non-UAsset 部分。

[*]UAsset 可以认为是 UE4 认为是资产的那些资源,并且在 Content Browser 中会显示出来,例如 Level、Actor、Mesh 等等;
[*]而 Non-UAsset 可以认为是不受 UE4 直接管理的资源,同时也不会显示在 Content Browser 中,例如 Lua/JavaScript 脚本、JSON 配置文件等等。
UAsset部分

Chunk划分的配置方式可以参考 Cooking and Chunking 官方文档,关于资源的配置方式比较简单,文档里都有介绍,这里只是简要介绍一下。
方法1: 使用 Project Setting 中的 Primary Asset Rules 进行配置,类似下图(来源于官方文档):


方法2:使用 Primary Asset Labels(下图来自官方文档)


Primary Asset Labels 可以选择配置 Apply Recursively 为 true,这样可以把当前 Primary Asset Labels 所在目录及子目录以 Soft Reference 的形式加入进来。但是这样做有一个副作用,那就是如果某些被 Primary Asset Labels 被删除的时候,需要重新保存一下 Primary Asset Labels 资产,否则在加载的时候,会产生资源丢失的 Warning。
另外一个需要注意的是,Primary Asset Labels 不能在 Project Setting 中配置 Priority 和 Chunk ID,只能在 Primary Asset Labels 资产中配置。
Non-Asset 部分

UE并没有提供 Non-Asset 划分 Chunk 的方式,而且以前旧版本 UE 中使用的基于文件名匹配的划分机制在 Asset Manager 出现以后就已经被废弃了。目前无法像 Asset 一样在 Project Setting 中进行配置,这一点在 UDN 上也有相关的讨论,所以目前的比较简单的方案就是使用 Pak File Rules 配置。但是问题在于官方并没有相关文档,只能通过 ini 文件进行猜测。查看 Engine/Config/BasePakFileRules.ini 文件头部的注释内容,基本可以了解其使用方法,其注释部分我摘录到下方:
; These rules are applied in order, the first rule that applies per file is taken and no others are evaluated
;
; bOverrideChunkManifest=false                 ; If true this allows overriding assignments from the cooker
; bExcludeFromPaks=false                         ; If true this removes entirely, cannot coexist with overridepaks
; OverridePaks="pakchunk1"                         ; If set this will override pak list, comma separated
; Platforms="iOS,Android"                        ; If set this rule will only apply to these platforms
; Targets="Shipping,Test"                        ; If set this rule will only apply to these configurations
; bOnlyChunkedBuilds=true                        ; If set this rule will only apply to chunked builds
; bOnlyNonChunkedBuilds=true                ; If set this rule will only apply to non-chunked builds
; +Files=".../*FileMask*.*"                        ; List of file masks to apply to, using the C# FileFilter class可以看出来,组合使用 bOverrideChunkManifest、OverridePaks 和 Files 三个参数就可以构建一个 Non-Asset 的过滤器,用于过滤特定命名或者路径的文件到某个指定的 Chunk。

其他重要配置

在 Project Settings -> Packaging 下也有几个比较重要的配置参数需要考虑:

[*]Use Pak File:打开后才可以使用 Pak 文件,否则所有针对 Pak 的配置都不会生效;
[*]Generate Chunks:打开后才会进行 Pak Chunk 划分,否则只会生成单一的 Pak 文件;
[*]Force One Chunk Per File:是否强制资源只存在于单个 Pak Chunk 中。当同一个资源被多个资源引用时,如果引用它的资源不在同一个 Pak Chunk 的话,这个资源在每个使用到的 Pak Chunk 中保存一份,如果资源引用较多的话,会导致Pak Chunk 总大小变得非常大。选中的话,会根据 Primary Asset 的 Priority 进行分配。
[*]Create compressed cooked package:是否使用压缩后的 Pak 文件。
关于 Asset Audit

多说一点关于 Asset Audit 的问题(下图来自原官方文档),右侧的 Select Platform 按钮需要在这个平台构建一次才能选择。如果配置好了 Primary Asset 以后,选择 Add Primary Asset Type 按钮可以将配置的Primary Asset 添加到下方的列表,可以看到一些统计信息;选择 Add Chunks 按钮,可以将划分好的 Chunks 添加到下方列表,但是我在测试时总是有些问题,比如 Size 总是不匹配等等,暂时没有时间去调查。


生成基础包

配置完成 Chunk 以后,就可以进行构建基础包了。本文以 WindowsNoEditor 为例进行介绍要介绍,其他平台方法类似,没有本质的区别。生成基础包时,最终的是要生成 Releases 目录,这是后续生成 Patch 的基础。
同样在构建前也要先了解一下 UE4 构建的几个主要流程,也是 Project Launcher 中的几个重点配置项目,以下步骤按顺序依次完成:

[*]Build:构建 Editor 和 Game 的可执行部分,在 Windows 平台上,这一步骤的结果一般都是 .exe、.dll、.pdb 文件。
[*]Cook:将编辑器资源转化为平台相关的资源,会进行资源压缩、裁剪等事情,Cook 后的资源在 Editor 下是不可读的。生成 Pak、加密等操作也是在一个步骤完成,如果不使用 Pak,那么这一个步骤的结果就是一堆 Cook 后的散文件,放置在 Saved\Cooked 目录下;如果使用 Pak 文件,那么结果就是单一的 Pak 文件或者多个 Chunk Pak 文件。
[*]Staging:将 Cook 步骤的产出物统一复制到指定的目录,一般是在 Saved\StagedBuilds 下。
[*]Package:将 Staging 的结果与 Build 的结果整合在平台相关的框架结构中,然后处理平台包构造,签名等事情。
[*]Deploy:将 Package 的结果部署到设备上,例如 Apk、ipa 安装到手机上等等。
Project Launcher 的使用方法可以参考官方文档,生成基础包重要参数请参考下面的表格:
Project Launcher 参数RunUAT 参数功能描述Create a release version of the game for distribution没有对应打开下面参数的开关Name of the new release to create-createreleaseversion=设置基础包的版本名称,格式没有要求,只要是一个字符串即可,一般使用版本号即可,例如:
-createreleaseversion=1.0Store all content in a single file (UnrealPak)-pak使用 Pak 进行打包,在 Project Setting 中设置好 Chunks 以后,会自动拆分为多个 Pak ChunkSave Packages Without Versions-unversionedcookedcontent以无版本号形式保存 Cook 后的内容或者使用类似下面的命令行(我使用的是官方版引擎,注意修改路径参数):
"C:\Epic Games\UE_4.27\Engine\Build\BatchFiles\RunUAT.bat" -ScriptsForProject=D:/UE4PatchDemo/UE4PatchDemo.uproject BuildCookRun -project=D:/UE4PatchDemo/UE4PatchDemo.uproject -noP4 -clientconfig=Development -serverconfig=Development -nocompile -nocompileeditor -installed -ue4exe="C:\Epic Games\UE_4.27\Engine\Binaries\Win64\UE4Editor-Cmd.exe" -utf8output -platform=Win64 -targetplatform=Win64 -build -cook -map= -unversionedcookedcontent -pak -createreleaseversion=1.0 -manifests -SkipCookingEditorContent -compressed -stage -package构建完成以后,会有两个重要的目录:

[*]在游戏目录下(在我的例子中是 D:\UE4PatchDemo)会出现 Releases 目录,里面应当包含与刚才构建版本号一致的目录,内容为构建好的 Pak 文件,注意此时只有基础包用到的 Pak 文件。
[*]在 Saved\StagedBuilds\WindowsNoEditor\UE4PatchDemo\Content\Paks 下会有与上述相同改的 Pak 文件。
此时执行 Saved\StagedBuilds\WindowsNoEditor\UE4PatchDemo 下的可执行文件,应该可以正常运行游戏,基础版本构建完毕。
生成热更包

热更包的生成方式与基础包类似,除了一定要在基础包构建完毕的情况下构建热更包以外,还有会有一些参数的变动。同样重要的参数列在下面的表格中:
Project Launcher 参数RunUAT 参数功能描述Create a release version of the game for distribution没有对应打开下面参数的开关Name of the new release to create-createreleaseversion=设置热更包的名称,格式同基础包,但是注意一定不能与基础包或者其他的热更包相同。Release version this is based on-basedonreleaseversion=这里填写基础包的版本名称,例如基础包是1.0,然后构建出了1.2和1.3,现在要构建1.4的话,这里也是要填写 1.0。Generate Patch-generatepatch生成 Path,如果不使用的话,UnrealPak不会计算差量Stage base release pak files-stagebasereleasepaks将基础包中的 Pak文件也复制到 Staging 目录Add a new patch tier-addpatchlevel增加 Patch Level,也就是会递增热更包的 _P 计数,可能有些文章说不能打热更包的热更包就是忽略掉了这个参数。或者使用类似下面的命令行:
"C:\Epic Games\UE_4.27\Engine\Build\BatchFiles\RunUAT.bat" -ScriptsForProject=D:/UE4PatchDemo/UE4PatchDemo.uproject BuildCookRun -project=D:/UE4PatchDemo/UE4PatchDemo.uproject -noP4 -clientconfig=Development -serverconfig=Development -nocompile -nocompileeditor -installed -ue4exe="C:\Epic Games\UE_4.27\Engine\Binaries\Win64\UE4Editor-Cmd.exe" -utf8output -platform=Win64 -targetplatform=Win64 -build -cook -map= -unversionedcookedcontent -pak -createreleaseversion=1.1 -generatepatch -basedonreleaseversion=1.0 -stagebasereleasepaks -addpatchlevel -manifests -SkipCookingEditorContent -compressed -stage -package同样,构建完成以后检查一下重点目录:

[*]在 Saved\StagedBuilds\WindowsNoEditor\UE4PatchDemo\Content\Paks 会出现一批新的以 _X_P.pak 结尾的一批热更文件,注意热更包文件大小应当与构建前增加的资源数量相匹配。按照逻辑,应当基础包中的 Pak 都会生成一个对应的热更 Pak 文件,即使没有任何资源修改,其大小是个固定值(339字节),也就是一个空 Pak 的头部数据大小。
[*]在 Releases 目录下,会出现以新版本号为名称的子目录,但是上述热更包的Pak会出现在 Releases 下基础包版本号的子文件夹中,这也就是为什么 -baseonreleaseversion 这个参数要一直使用基础包版本号才可以。
此时执行 Saved\StagedBuilds\WindowsNoEditor\UE4PatchDemo 下的可执行文件,应该可以正常运行游戏,并且构建前的修改应该可以正常反映到游戏之中,热更版本构建完毕。
热更包服务器部署

热更数据构建完以后,需要部署到服务器上才能让客户端可以进行下载,使用不同的客户端更新机制需要部署的内容也不相同,本文主要介绍 ChunkDowloader 的方式来进行实现,所以服务器部署的内容也是与 ChunkDownloader 有关的。至于其他的实现方式,我会在客户端更新机制这一节中简要介绍。
服务器的配置方式在 ChunkDownloader 官方文档 中介绍的比较清楚了,也可以参考知乎上的这篇文章,主要分为两个步骤

[*]手动生成 Manifest 文件
[*]在 HTTP 服务器上进行部署
生成 Manifest 文件

我觉得 ChunkDownloader 是个半成品功能主要是因为 Manifest 文件没有自动生成,从理论上来说,这个文件在 Cook 或者 Staging 的时候完成是完全没有问题的,然而 UE4 并没有进行处理,让我很费解。
下面是 Manifest 文件的内容(来源于官方文档):
$NUM_ENTRIES = 3
$BUILD_ID = PatchingDemoKey
pakchunk1001-WindowsNoEditor.pak    922604157   ver 1001    /Windows/pakchunk1001-WindowsNoEditor.pak
pakchunk1002-WindowsNoEditor.pak    2024330549ver 1002    /Windows/pakchunk1002-WindowsNoEditor.pak
pakchunk1003-WindowsNoEditor.pak    1973336776ver 1003    /Windows/pakchunk1003-WindowsNoEditor.pak下面解释一下这个文件的内容:

[*]$NUM_ENTRIES 表示这个 Manifest 文件中有多少个 Pak 文件,要与下面的 Pak 文件行数对应;
[*]$BUILD_ID 就是当前这个版本的版本号,与上面的 -createreleaseversion 一致, 在这个例子中,并没有用版本号的格式。
[*]从第三行开始,每行描述一个 Pak 文件的信息:
[*]第一列是 Pak 的文件名,在这个例子中使用的是基础包的文件名,这种用法一般是作为分包下载使用的,如果做热更的话,这里应该是名字形如 _*_P.pak 这种类型的 Pak 文件。
[*]第二列是文件大小,以字节为单位。
[*]第三列是版本号,因为每个热更版本都会对应一个独立的 Manifest 文件,这个 Manifest 文件要包含从基础包到目前热更版本的所有热更 Pak 的信息,这样才可以从任何一个版本升级到当前的最新版本。所以需要用版本号来指示当前这个 Pak 文件是属于那一个热更版本的。在这个例子中他使用 ver 作为占位信息。
[*]第四列是 Chunk Id,应当与 Pak 文件名中的 Chunk Id 一致,
[*]第五列是路径,相对于当前 Manifest 文件所在目录的相对路径地址。


下面是我们测试时使用的 Manifest 文件内容,可以用作参考
$NUM_ENTRIES = 4
$BUILD_ID = 1.2
pakchunk1-WindowsNoEditor_0_P.pak                21557                1.1        1        /Paks/pakchunk1-WindowsNoEditor_0_P.pak
pakchunk1-WindowsNoEditor_1_P.pak                38307                1.2        1        /Paks/pakchunk1-WindowsNoEditor_1_P.pak
pakchunk2-WindowsNoEditor_0_P.pak                339                1.1        2        /Paks/pakchunk2-WindowsNoEditor_0_P.pak
pakchunk2-WindowsNoEditor_1_P.pak                339                1.2        2        /Paks/pakchunk2-WindowsNoEditor_1_P.pak可以看到当前 Manifest 文件描述的是 1.2 版本的热更信息,也可以看出来在此版本之前有一个 1.1 的热更版本。
补充一个生成 Manifest 的工具,但是使用起来不是很好用,有兴趣的同学可以试试,地址在:nobandegani/CD-BuildManifest-G: ChunkDownloader BuildManifest Generator
在 HTTP 服务器上进行部署

HTTP 服务器的部署方式我不再讲解,在上面给出的两个参考链接中都有比较清晰的说明。主要注意的是,如果使用 IIS 部署的话,注意添加 MIME Type,否则很多文件都会返回 404 错误。
部署时要注意目录划分,以下是一个可以参考的目录层级方案,()中的内容为注释:

[*]http://patch.yourcompay.com/

[*]Patch/

[*]BuildManifest-Windows.txt(上面示例中的 Manifest 文件)
[*]Paks/

[*]pakchunk1-WindowsNoEditor_0_P.pak
[*]pakchunk1-WindowsNoEditor_1_P.pak
[*]pakchunk2-WindowsNoEditor_0_P.pak
[*]pakchunk2-WindowsNoEditor_1_P.pak



Version 文件

服务器上还差最后一个需要部署的内容,那就是最新版本的 Version 文件。这一点在官方文档上没有说明,需要项目自行处理。可以使用在某个 Web 服务器上部署一个文本文件,也可以选择用游戏服务器去返回当前最新的版本号,方法都是可以的,只要在客户端启动后,可以很方便的进行获取即可。
客户端更新机制

几种不同的更新方案比较

UE4提供了几种不用的更新或者资源下载方案,ChunkDownloader是其中最新的,而且在5.0以后,可能只会保留 ChunkDownloader 这一种方案。以下对互联网上可以找到的集中方案进行一下简单对比。

[*]ChunkDownloader:最新的一种的方案,放弃了以前使用 HTTP Chunk 的形式,采用直接按照 Pak Chunk 进行下载的方式。我猜测和现在 Epic 的资源管理思路变化有一定的关系,以前的Pak划分粒度较粗,可能每个 Pak 有几百M,所以需要拆分为 HTTP Chunk 方便断点续传和并行化;现在的思路是把 Pak 进行细致划分,可能每个 Character 都是一个单独的 Pak Chunk,使得 HTTP Chunk 的划分失去了意义,还不如直接下载 Pak Chunk 更加方便。有兴趣的同学可以解包一下 Fornite 的 Android 版本,会发现有非常多的 pak 文件,每个 pak 文件都很小,已经接近以前 HTTP Chunk 的粒度了。
[*]HTTPChunkInstaller:UE4 热更新:HTTPChunkInstaller 这篇文章介绍了如何使用 HTTPChunkInstaller 进行下载的方法,但是目前在 UE 官方文档上已经没有相关的资源了,而且这种方法更像是提供了一种按需加载的方式,而不是常规理解的热更机制。另外使用 HTTPChunkInstaller 的话,再进行热更包构建的时候,需要使用 HTTPChunk 相关的选项,UE会自动将 Pak 拆分为固定大小的 HTTP Chunk 文件,使客户端可以增量下载。
[*]MobilePatchService:UE4 旧版本使用的一种方式,我前一个项目使用 UE 4.18 还在使用这个工具做热更新和分包下载,现在虚幻官方已经找不到相关文档了。同样的,服务器的部分同 HTTPChunkInstaller,也是要使用 HTTPChunk 相关的选项。这套机制在 4.27 版本应该还是可用的,而且相对来说在服务器的层面比较完善,客户端层面有些需要访问的接口默认并没有暴露到Blueprint 这一层,可能需要修改一下。如果 Pak 拆分的粒度比较粗,希望使用 HTTP Chunk 来拆分的话,这个机制也是很成熟的,理解以后也比较容易上手。
[*]HotPatcher:注意这不是 Epic 官方提供的机制,而是腾讯的 zlp 同学做的一套热更系统。文档地址在:UE 资源热更打包工具 HotPatcher。我曾经简单试用过,最后还是不太想引入第三方的工具,所以最后还是放弃了。有兴趣的同学可以去文档地址看看。
使用 ChunkDownloader 的更新方案

这个部分的内容在 ChunkDownloader 官方文档 和 UE4 DLC下载与加载相关 这篇文章中也有详细的介绍,本文也是在这里说一下重点的部分,不会覆盖完整的流程。
在 UE 定义的概念中,将 DLC 机制和热更机制合二为一了,所以对只考虑热更需求的人来说会有一些复杂。先来区分一下涉及到的重点概念,其实这些概念在官方文档中没有明确定义,基本上都是结合文档和代码分析出来的:

[*]Deployment Name:这个最高级的配置,每个项目中可以有多个 Deployment,通俗的理解可以认为是多个DLC或者扩展包。每个 Deployment 是一个独立的链条,可以单独更新或者下载。如果只有热更需求的话,只使用一个 Deployment Name 即可。命名方式随意,按照一般变量命令的方式就可以。
[*]CDN Base Urls:每个 Deployment 可以对应多个 CDN Base Url,也就是下载基础地址,Manifest 地址以及 pak 的地址都是基于这里配置的地址依次拼接出来的。在下载的时候,会依次尝试这里配置的每个地址。
[*]Content Build Id: 可以理解为版本号,但是格式不限制,类似于上面的 -createreleaseversion 参数。
配置 CDN Base Urls
在 DefaultGame.ini中配置 CDN Base Urls,也就是下载热更包的基础 URL,注意这里使用的地址与上面热更包服务部署目录结构中使用的是一致的,可以使用域名根目录也可以使用子目录。
下面是配置的一般性格式,用<>包围的表示占位符:

+CdnBaseUrls=<BaseUrl1>
+CdnBaseUrls=<BaseUrl2>


+CdnBaseUrls=<BaseUrl3>
+CdnBaseUrls=<BaseUrl4>下面是一个热更配置的例子,只使用了一个 Deployment 以及1个 Url,与上面的展示的目录结构相对应:

+CdnBaseUrls="http://patch.yourcompay.com/"有两个个小坑需要注意:

[*]当配置的URL里面带有 https:// 时,一定要用引号把地址包起来,否则 INI 读取会失败。
[*]对于 HTTP 地址,如果不加上 http:// 的话,在 iOS 平台上会报错,表示没有定义协议头。
实现 ChuckDownloader

具体代码在上面提到的两个参考链接中都已经实现过了,这里简单介绍一下主要流程:

[*]游戏启动后获取 Version 文件,如上所说,可以使用 Web Server 上的文件形式,也是采用自有服务器的形式;
[*]使用获取到的 Version 与本地 Version 做对比,如果一致则跳过更新,直接进入游戏;
[*]如果Version 不同,则初始化 ChunkDownloader,ChunkDownloader 会自动获取 Manifest 并调用 Manifest 下载完成回调;
[*]在回调用进行一些信息展示,并调用 ChunkDownloader 开始下载 Pak 文件;
[*]下载成功后 ChunkDownloader 会自动 Mount 成功下载的 Pak 文件;
[*]进入游戏。
有一点需要注意的是,FChunkDownloaderModule 在 Shutdown 的时候,会 Unmount 所有 mount 过的 Pak,所以注意不要在运行期间关闭这个 FChunkDownloaderModule。
测试方案与验证

到此为止,应该所有的热更流程已经走通了,热更测试是一个比较繁琐的过程。如果在测试期间出现了问题,可以参考下面的方法来进行调试。
热更构建验证

构建基础包后,应当验证的内容:

[*]Chunk Pak 划分是否符合配置要求(注意区分 Asset 和 Non-Asset),可以使用 UnrealPak 进行解包验证(UnrealPak 我会在写一篇文件来介绍使用方法和详细参数);
[*]基础包是否可以正常运行;
[*]基础包是否有正确的热更版本判断机制。
修改资源并构建热更包后,应当验证的内容:

[*]修改的资源是否被正确的划分到对应的 Chunk Pak 中。
[*]热更 Pak 文件大小是否合理,是否包含必须的增量/减少文件,可以使用 UnrealPak 进行解包验证;
[*]二次热更包构建后,Patch 编号应当增加,并且检查上面的1和2。
客户端更新验证


[*]基础包是否有正确的热更版本判断机制;
[*]客户端可以正常更新到热更版本,并且可以再次更新到最新的热更版本(二次更新);
客户端更新调试

如果客户端更新失败,但是感觉配置都一切正常的话,建议使用 Fiddler 进行 HTTP 抓包测试,访问的 URL 和 服务器返回消息都很清晰,能够快速定位问题。
示例工程

如果工程较大不好测试,或者一直无法成功构建出热更包的话,可以参考我的这个测试工程,使用方法已经写在 README 文件中。
参考文档与工程


[*]Implementing ChunkDownloader Ingame | Unreal Engine Documentation
[*]Hosting a Manifest and Assets for ChunkDownloader | Unreal Engine Documentation
[*]nobandegani/CD-BuildManifest-G: ChunkDownloader BuildManifest Generator (github.com)
[*]关于 ChunkDownloader 和 HTTPChunkInstaller 的热更方案
[*]ChunkDownloader解释| 虚幻内幕_哔哩哔哩_bilibili
[*]UE4 DLC下载与加载相关 - 知乎 (zhihu.com)
[*]UE4 热更新:HTTPChunkInstaller
[*]hxhb/HotPatcher: Unreal Engine hot update manage and package plugin. (github.com)
[*]UE 资源热更打包工具 HotPatcher | 循迹研究室 (imzlp.com)
[*]b1gm0use/UE4PatchDemo (github.com)

zifa2003293 发表于 2022-6-14 19:38

请问怎样通过Priority来更好控制冗余资源呢?
如下情况:有Map A与B,需要将A B共有的资源打包到一个Chunk(Pak)中,两个Map独有的文件分别打包到两个Chunk中。
目前的解决方式是,每一个Map作为一个Chunk,并且递归的查找Map引用的资源,这些Chunk的Priority保持一致。
发现有Chunk间有冗余的资源时,通过手动或工具将其移动到一个Priority更高的Chunk中。
不知道大佬有没有好的解决方案?

DungDaj 发表于 2022-6-14 19:45

Force One Chunk Per File:是否强制资源只存在于单个 Pak Chunk 中。当同一个资源被多个资源引用时,如果引用它的资源不在同一个 Pak Chunk 的话,这个资源在每个使用到的 Pak Chunk 中保存一份,如果资源引用较多的话,会导致Pak Chunk 总大小变得非常大。选中的话,会根据 Primary Asset 的 Priority 进行分配。
选中这个参数以后,可以自动划分。Map的 Chunk在设置的时候可以把Priority 设置的有差异一些。不知道是不是回答了你的问题?

XGundam05 发表于 2022-6-14 19:50

但这样做后,被多个资源引用的资源被打包进了Priority最高的Pak Chunk中,我觉得不太好。希望是有一个Common Assets Pak Chunk,单独存放共用资源的Pak Chunk。
之前我的做法是这样的,Maps Asset Label的Priority设置为一致且递归索引资源,存放共有资源的文件夹AssetLabel Priority设置为最高。但这样做会让ComonAssets Pak Chunk中会有一些未被引用的资源。

unityloverz 发表于 2022-6-14 19:52

据我所知官方应该没有处理这种需求的办法。把公有的资源放到单独一个 chunk 里的意义是什么呢?

pc8888888 发表于 2022-6-14 19:55

目的是控制Pakchunk 的颗粒度,减少热更的下载量
这部分我实验下来的确找不到比较简便的方法

TheLudGamer 发表于 2022-6-14 19:59

那我觉得可以把一些 Actor 也做成 Primary Asset 单独分到一些 Chunk 更自然一些,调高他们的优先级,这样就不会被分到 level 里了,应该也能满足粒度的要求。

mypro334 发表于 2022-6-14 20:09

嗯嗯,这也是官方案例中的做法,感谢回复![赞同]

APSchmidt 发表于 2022-6-14 20:15

不客气~[握手]
页: [1]
查看完整版本: UE4 原生热更实现方案