资源管理:重塑 UE 的包拆分方案

资源管理:重塑 UE 的包拆分方案

资源管理:重塑UE的包拆分方案 | 循迹研究室

之前我写了一篇文章,介绍 UE 默认的拆包方式 (UE 热更新:拆分基础包),但 UE 默认的拆包方式在大规模资源项目中不够灵活,无法满足对超大规模资源项目的精细化管理需求。

为了解决 UE 默认打包和资源拆分的痛点,我基于 HotPatcherCore 开发了一个扩展,能够能够解决默认拆包流程的缺点,足够地灵活与强大。博客中有篇文章,介绍它的整体实现机制: 一种灵活与非侵入式的基础包拆分方案

HotChunker 能够非侵入式地集成到 UE 默认的打包流程中,无需手动做任何的处理,只要 UE 默认打包,就会自动拉起 HotChunker 的拆包流程,实现资源的 Cook、打包,以及自动 Copy 到 StagedBuilds 目录中。

本篇文章会着重介绍,使用 HotChunker 在进行资源拆分的配置方式和自动化构建、最大限度地降低资源冗余、以及进行并行打包的实现。

UE 默认打包的问题

UE 默认使用的 CookerOnTheFly-UnrealPak 的模式本身存在一些问题:

  1. 不能够精确地打包和灵活控制自定义拆包的行为
  2. 没有全平台通用的 pak 进包过滤机制(只有安卓的 ObbFilter
  3. 强依赖 Cook 流程,无法单独打包某一个 Chunk
  4. 无法方便地进行程序化的拆包
  5. 无法配置 Chunk 包含 Not-uasset 文件
  6. 所有 Not-uasset 文件均在 0 号 Chunk
  7. 无法基于 chunk 拆分 Metadatas

HotChunker 的实现能够比较好的解决上面的问题,每个 Chunk 都是自包含的:

最终效果,UE 打包的资源配置,只有那些最基础的资源由 UE 自己管理打包,其余的都可以通过 HotChunker 的配置来拆分。

文章的后续部分会介绍如何配置做到这一点。

Chunk 配置

Chunk 的配置,是进行包拆分的最小单元,在 UE 中,每个 Chunk 会打包为一个独立的 pak 文件。

对于 HotChunker 的实现,单个 Chunk 的配置可以包含以下这些属性:

Chunk 的资源的配置提供了两种模式:Rule/Getter,用于指定打包的资源路径从代码中通过程序化的方式获取

每个 Chunk 都可以添加的外部文件,以及控制 Shader 的序列化方式、AssetRegistry 的序列化等等。并且 Chunk 的 metadta 是自包含的,最显著的就是降低安装包内 ShaderLirary 的大小。

默认情况下,UE 打包项目的 Shader 都被序列化到了同一个文件内,并且这个文件是被打包到 pakchunk0 之内的,也就是整个项目完整的 Shader 都在安装包之内。资源规模上来之后 ShaderLibrary 大小非常恐怖,可能会达到数百 M。
让每个 Chunk 的 Shader 自包含,能够比较好地解决这个问题。并且配合上我之前的一种高效的 ZSTD Shader 字典训练方案,组合起来能够最大限度地降低 ShaderLibrary 的大小,实现 Shader 的按需下载。

Rule

Rule 模式的配置和 HotPatcher 的配置类似,可以指定包含路径、资源、忽略的资源。

这种模式适合配置比较固定的资源,如打包某个目录、某个地图等。

Getter

除了直接指定资源之外,我还提供了一种 Getter 的配置模式,可以指定一个继承自 UHPLGetter 的类,从代码中动态地获取 Chunk 管理的资源。

之所以会有这样一种模式,是期望与策划的配置建立起直接的对应关系。基于策划的配置来控制打包。

比如,当前版本包含了哪几个地图、哪些职业的角色等等,这些配置是会随着开发进程不断变化的,而数据源头在策划,在 UE 默认的方式中,还需要在工程中进行修改打包配置。
但,HotChunker 通过 Getter 这种配置方式建立起打包策划配置的对应关系,就能够策划来直接控制打包哪些资源。

Chunk 管理

HPL 资源

与 PrimaryLabel 类似,我给 Chunk 的配置增加了一个等价物,我将其称之为 HPL(HotPatcherPrimaryLabel)。

可以创建一个 HPL 资源用于编辑要打包的资源,每个 HPL 是一个独立的 Chunk。

在打包中,需要在 Project Settings-Plugins-HotChunker 中添加扫描路径:

在 HotChunker 的打包中,会自动扫描所有配置的目录下的 HPL 资源,进行打包。

DataTable

如果想要创建多个 Chunk,可以创建多个 HPL 的资源,但是为了方便管理,我还支持了 DataTable 配置。
选择创建 DataTable,RoleStructure 选择 HPLChunkSetting

打开编辑,每个元素就是一个独立的 HPL 的 Chunk 配置:

并且我为 HPL 的 DataTable 添加了一个专门的打包按钮,可以直接在表格界面中选择打包哪个 Chunk:
 


它会拉起一个单独的进程执行,不会阻塞当前编辑器。

同样的,当创建了一个 HPL 的 DataTable,想要将其参与打包,需要在 Project Settings-Plugins-HotChunker 中添加 ImportRuleTables 配置:

动态注册

为了实现程序化自动进行分包的需要,我为拆分配置增加了动态注册的机制,只需要绑定该 Delegate:

1
FHotChunkerDelegates::OnNotyfyChunkRegister.AddStatic(&FGameEditorModule::OnNotyfyChunkRegister);

在该函数中将 Chunk 注册进去:

通过动态注册或者前面提到的 Getter 机制,可以把策划配置与打包建立起一种对应关系,可以完全按照策划的配置,来自动控制要打包哪些资源,解放程序的配置任务。

编辑器支持

我为 Chunk 的 DT 配置提供了编辑器选项,能够比较方便地选择打包某个 Chunk,在开发过程中,可以让美术同学自己方便地打包自己所需要的资源,避免出包的等待。

  1. 打包单个 Chunk
  2. 打包 DT 中所有的 Chunk
  3. 导入 / 导出 Chunk 的配置
  4. 不阻塞编辑器

全局配置与流程扩展

在 Project Settings-Plugins-HotChunker 中可以进行全局配置,和逻辑替换(ChunkerManager)。

  1. HPL 扫描路径
  2. Chunk 规则 DT 配置
  3. Pak Setting
  4. 功能开关
  5. 替换 ChunkerManager
  6. 全局重载

介入 Chunker 的各个阶段

为了实现足够的灵活性,在实现过程中,我为 Chunk 的打包留了很多可以介入到各个阶段的口子。

  1. 按需对资源资源分析、处理
  2. 获取打包状态、结果
  3. 获取完整的 Manifest 信息
  4. 进行包体审计

在框架之内,可以非侵入式地实现项目的各种分析需求。

冗余控制

我在 UE 热更新:拆分基础包 #Priority 打包时失效中介绍了通过 UE 默认的拆包形式,优先级不生效的情况,并提供了解决方案。

HotChunker 在实现时,就已经规避了这些问题,Chunk 的配置也支持 Priority

如果 Chunk 的 Priority 是平级的,则它们之间就没有依赖关系,统计资源会冗余一些。

打进安装包内的 Chunk 之间是没有资源冗余的,在安装包之外的 Chunk,可以优先级来进行冗余控制。

Commandlet 支持

我为 HotChunker 添加了多种 Commandlet 支持,能够比较方便地使用命令行打包。

  1. 打包工程里所有配置的 Chunk
  2. 打包一组 Chunks
  3. 打包单个 Chunk
  4. 打包某个命名的 Chunk
1
2
3
4
-run=HotChunker -TargetPlatform=IOS
-run=HotMultiChunker -config=G:/HPL/HPL_ChunkerSettings.json -TargetPlatform=IOS
-run=HotSingleChunker -config=G:/HPL/ChunkerSetting.json -TargetPlatform=IOS
-run=HotNamedChunk -ChunkName=XXXX -TargetPlatform=IOS

打包控制与动态开关

Chunk 的打包控制,分为三种类型:

  1. bUseHPL:是否启用 HotChunker 的配置打包 chunk
  2. ALL:所有的 chunk
  3. BASEBUILDS:安装包内的 Chunk
  4. EXTERNAL:安装包之外的 Chunk

在项目设置中可以控制默认打包的类型

除了固定配置之外,还可以在 commandlet 传递命令来覆盖引擎中的配置,能够比较方便地在 CI/CD 上进行控制。

目前支持了两个动态开关:

1
2
3
4
# true/false
-bUseHPL=
# ALL/BASEBUILDS/EXTERNAL
-GenerateType=

在拉起 UE 的 CookCommandlet 时传递,就会自动地控制 Chunker 的打包开关和生成的 Chunk 类型。

如果是自己在 CI/CD 中调用 HotChunkerCommandlet,也可以传递这两个动态开关。
如,只打包非安装包内的 Chunk:

1
-run=HotChunker -TargetPlatform=IOS -GenerateType=EXTERNAL

能够比较方便地集成到 CI/CD 系统中:

通过这种机制,可以实现打包时的精确控制。在一些测试场景中,可以实现快速出包,避免每次打包都要处理完整资源。

Chunk 的加密

使用 HotChunker 方式管理并打包的 Chunk,默认复用项目配置中里 DefaultCrypto.ini 的配置。

在 Project Settings-Plugins-HotChunker-HPLPakSettings-EnceyptSettings 中配置:

bUseDefaultCryptoIni:使用项目设置中的配置。如果不复用,可以通过 CryptoKeys 来指定 crypto.json 进行加密。

通用的包过滤方案

在 UE 热更新:拆分基础包这篇文章里,我介绍了 Android 和 IOS 包过滤的方法。
引擎默认只为 Android 提供了 ObbFilter,但没有为 IOS 提供等价物,需要自己实现。

在 HotChunker 的实现中,我对包过滤的机制做了补充,可以在创建每个 Chunk 时,直接指定它是否进安装包。

并且,可以针对某个平台特殊处理:如,默认情况下进基础包,但在 WindowsNoEditor 平台不进。

如果不想要对每个 Chunk 都单独配置,可以在项目设置中配置全局重载:

这个配置意味着,在打包 WindowsNoEditor 平台时,HotChunker 所有管理的 chunk 都会归档到安装包之内。

流程优化

默认情况下,UE 使用 CookerOnTheFly 的过程,是要把当前工程中所有参与打包的资源都执行 Cook 之后,才进入到 Pak 打包过程。

本质上是一个串行的过程:

但是当资源规模庞大之后,这个过程非常之久。

但实际上,我们并不一定需要把所有的资源处理完,才能打安装包。因为在手游中,安装包内的资源只是一少部分,其余的资源都是热更动态下载下来的。

在 HotChunker 的实现中,可以把安装包内 Chunk 的打包与动态下载的 Chunk 进行并行执行:

这样就能够节省大量的时间,用最快的速度打出安装包,再用一个独立的打包任务并行执行动态下载的 Chunk 的打包。

结语

基于 HotChunker 的包管理方案,是一种强大和精确地包管理机制。能够在精确拆分资源的同时,保证配置的灵活性,并且支持强大的 Commandlet 能力。能够方便地非侵入式扩展流程和进行资源审计。

而且,该方案是非侵入式集成,无需对默认的打包过程做任何处理也不需要修改引擎,整个实现都是插件化的,只要启用插件后拉起 UE 默认的打包就会自动执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值