HotPatcher的模块化改造和开发规划

HotPatcher Modular Transformation and Development Planning

随着HotPatcher的开发以及我对于资源管理方面的技术的研究,围绕着HotPatcher实现的功能越来越多,实现也越来越复杂,加上引擎的不断更新,一个大而全的插件对引擎的兼容性越来越难以维护。

随着新一代引擎UE5的到来,HotPatcher同样会跟进UE5中支持,并针对UE5的特性开发新的功能。我希望它不仅仅只是一个资源打包工具,而是包含资源管理、审计、打包、热更新、包体优化、构建提升等等全方位的资源管理方案,并且作为一个开放式的资源处理框架。

本篇文章会介绍HotPatcher的模块化进展,对现有功能的支持。以及如何利用HotPatcher强大的打包能力根据项目需求进行自定义的模块化扩展。最后,会介绍HotPatcher项目后续的开发计划。

目前HotPatcher的大部分核心功能都是同时支持UE4.21-UE5.1的。但每次引擎新版本的发布带来的插件适配工作耗费了太多精力和时间。而且之前大多数功能都集成在一个插件之内,功能扩展也有一定的局限性。

所以,针对这些问题,我对HotPatcher项目开启了模块化改造计划。HotPatcher本身只提供核心的打包功能,其他的扩展独立实现,也可以按需下载启用。当然,功能模块化不是一蹴而就的过程,从2021年时,我就在考虑把非核心功能剥离出来,作为单独的模块按需下载和使用,但没有进行完全的模块化改造。

2023年了,是时候来做这个事情了。时光荏苒,在2019年11月22日,我对该项目进行了第一次提交,到现在已有3年的时间过去了,经历了700多次提交和十几篇的博客文章介绍,很高兴见到HotPatcher被应用于大量的项目,同时插件功能也在进行着不断的更新与迭代。

模块化改造

首先,HotPatcher是一个独立的UE插件,如果想要在UE之内再额外实现类似的能够进行编译的模块化框架,有点得不偿失。

所以,我的实现是同样基于UE的插件机制,基于HotPatcher开发的模块也是一个UE的代码插件,只是它会依赖HotPatcher并能够包含它的代码。

以已经模块化改造完成的GameFeaturePacker模块为例,我将介绍HotPatcher模块的机制和能够实现的功能。

GameFeaturePacker是我之前实现的,可以用来打包UE5新的GamePlay机制GameFeature的功能,具体介绍详见之前的文章:UE5:Game Feature 预研

首先,前面已经讲到了,它也是一个UE插件,其uplugin文件为:

GameFeaturePacker.uplugin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
{
"FileVersion": 3,
"Version": 1,
"VersionName": "1.0",
"FriendlyName": "GameFeaturePacker",
"Category": "Other",
"CreatedBy": "lipengzha",
"CreatedByURL": "https://imzlp.com/",
"CanContainContent": true,
"IsBetaVersion": false,
"IsExperimentalVersion": false,
"Installed": false,
"Plugins": [
{
"Name": "HotPatcher",
"Enabled": true
}
],
"Modules": [
{
"Name": "GameFeaturePacker",
"Type": "Runtime",
"LoadingPhase": "Default"
},
{
"Name": "GameFeaturePackerEditor",
"Type": "Editor",
"LoadingPhase": "PostDefault"
}
]
}

它依赖了HotPatcher插件,往HotPatcher中注册模块,需要有一个Editor的模块,并且它的LoadingPhase要为PostDefault,在Editor模块的Build.cs中包含HotPatcher的Module:

GameFeaturePackerEditor.cs
1
2
3
4
5
6
7
8
PublicDependencyModuleNames.AddRange(
new string[]
{
"HotPatcherRuntime",
"HotPatcherCore",
"HotPatcherEditor"
}
);

这样就能在这个独立的插件中使用HotPatcher的功能。

GameFeaturePackerEditor模块的C++定义也要遵循规范,需要继承自FHotPatcherModBaseModule,并重写GetModDesc接口:

1
2
3
4
5
6
7
8
9
class FGameFeaturePackerEditorModule : public FHotPatcherModBaseModule
{
public:

/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
virtual FHotPatcherModDesc GetModDesc()const override;
};

.cpp中实现模块的注册:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void FGameFeaturePackerEditorModule::StartupModule()
{
FHotPatcherModBaseModule::StartupModule();
}

void FGameFeaturePackerEditorModule::ShutdownModule()
{
FHotPatcherModBaseModule::ShutdownModule();
}

FHotPatcherModDesc FGameFeaturePackerEditorModule::GetModDesc() const
{
FHotPatcherModDesc TmpModDesc;
TmpModDesc.ModName = MOD_NAME;
TmpModDesc.CurrentVersion = MOD_VERSION;
TmpModDesc.bIsBuiltInMod = IS_INTERNAL_MODE;
TmpModDesc.MinHotPatcherVersion = 80.0f;
TmpModDesc.Description = TEXT("Plugin/GameFeature Packager");
TmpModDesc.URL = TEXT("https://imzlp.com/posts/17658/");
TmpModDesc.UpdateURL = TEXT("https://github.com/hxhb/HotPatcher/Mods/GameFeaturePacker");
TArray<FHotPatcherActionDesc> ActionDescs;
TmpModDesc.ModActions.Emplace(
TEXT("Patcher"),MOD_NAME,TEXT("ByGameFeature"), TEXT("Create an Game Feature Package."),
CREATE_ACTION_WIDGET_LAMBDA(SGameFeaturePackageWidget,TEXT("ByGameFeature")),0
);
return TmpModDesc;
}

注意:一定要在模块的StartupModuleShutdownModule中调用基类FHotPatcherModBaseModule的函数。

GetModDesc函数中对当前插件进行模块注册。

一个HotPatcher的Mod定义能够具有以下属性:

1
2
3
4
5
6
7
8
9
10
11
struct HOTPATCHEREDITOR_API FHotPatcherModDesc  
{
FString ModName;
bool bIsBuiltInMod = false;
float CurrentVersion = 0.f;
FString Description;
FString URL;
FString UpdateURL;
float MinHotPatcherVersion = 0.0f;
TArray<FHotPatcherActionDesc> ModActions;
};

支持指定Mod名字、是否是内置Mod(HotPatcher自身包含的核心Mod),以及Mod的版本、描述信息、URL、更新链接、以及最低支持的HotPatcher版本

最后是FHotPatcherActionDesc,HotPatcherAction,它描述的是HotPatcher界面中的可操作逻辑,包含Slate界面。
如插件中原来的ByPatch/ByRelease等等,都是HotPatcherAction。

Mod中包含Action就会在这个列表中创建一个选项,并包含一个专属的界面,该界面的Slate控件可以自定义。

通过以下方式添加Action:

1
2
3
4
TmpModDesc.ModActions.Emplace(  
TEXT("Patcher"),MOD_NAME,TEXT("ByGameFeature"), TEXT("Create an Game Feature Package."),
CREATE_ACTION_WIDGET_LAMBDA(SGameFeaturePackageWidget,TEXT("ByGameFeature")),0
);

这样一个HotPatcher的模块就注册完成了,可以在这个独立的插件中实现特殊的功能,并能注册到HotPatcher的面板中去。

并且,打开HotPatcher的界面就能看到已安装的Mod:

Mod具有以下几种分类:

  1. Built-In,插件内置模块;
  2. Installed,已安装的,由HotPatcher作者开发的模块;
  3. ThirdParty,已安装的,由用户自己创建的模块;
  4. Not-Installed,HotPatcher开发者维护的模块,但本地未安装的模块列表。
  5. Unsupport,已安装的,但它们对HotPatcher版本的依赖高于工程中的HotPatcher版本,它们不会被注册到HotPatcher中。

内置模块

目前,我对HotPatcher原有支持的功能,已经拆分了多个模块。目前开放的模块有:

  1. HotPatcherCore,插件的内置模块,随着HotPatcher版本发布,包含最新的核心功能,具有ByPatchByRelease两个Action。
  2. GameFeaturePacker,打包GameFeature的模块,支持的最低HotPatcher版本是v80,后续会主要更新UE5的主线版本。
  3. ShaderPatcherUE,进行ShaderLibrary的Patch,详见文章:UE 热更新:Create Shader Patch

HotPatcherCore包含在主仓库中,其余的模块都是独立的仓库。

在下载时可以把它们一起clone下来,它们默认都在Mods目录下。

安装模块

HotPatcherCore就包含在HotPatcher插件本体中,其余的模块都是以git submodule的形式管理的。

可以在Github的hxhb/HotPatcher/Mods下查看目前已有的模块。

因为模块都是以git submodule进行管理的,所以模块的下载和更新都要使用submodule的对应命令。

如,初始下载公共模块,在HotPatcher插件的根目录下执行:

1
git submodule update --init --recursive

后续更新模块:

1
2
3
git submodule foreach git fetch
# 或
git submodule update --remote

我有一篇讲解git命令的文章,里面也有针对submodule的详细描述,详见:Git快速上手指南#submodule

注意:并非上面图片中的模块都能拉取下来,有些模块目前未公开,拉取时会有权限错误。但对功能无影响。

目前开放下载的模块可以从HotPatcher Star分类中查看:hxhb/list/HotPatcher

创建新模块

前面提到了,我希望HotPatcher是一个开放的资源管理框架,任何人都能够根据项目的实际需要,基于HotPatcher的功能进行模块的开发。

为此,我提供了一个Mod Template插件,可以在此模板的基础上进行修改:hxhb/HotPatcherModTemplate

它分别包含了一个Editor和Runtime的Module,Module声明和定义都已按照HotPatcherMod的规范创建,只需要在GetModDesc接口中实现对应的注册信息即可。

版本发布

因为对功能进行了模块化改造,所以后续HotPatcher的发布流程会有一些变化。

  1. HotPatcher的版本发布,仅包含HotPatcherCore的模块。
  2. 独立Mod的更新会单独发布

对于已有的功能并无影响,基础的功能如ByPatchByRelease还是内置在插件本体中。

其余的模块就需要手动更新了,并需要注意Mod依赖的HotPatcher版本。

未来计划

目前HotPatcher支持的功能:

目前HotPatcher已经支持了大量功能的Mod,并且一些新的运行时优化机制也在酝酿与开发当中。

大部分的模块目前暂未开放,以后或许会以合适的时机和方式开放出来。如果您的项目希望使用这些模块和技术,也欢迎进行商业合作的技术咨询。

HotPatcherCore的开发计划目前有几项重要内容,主要是针对UE5引擎的:

  1. World Partion的支持
  2. IoStore的适配支持
  3. 优化GameFeature的支持
  4. 提升打包效率
  5. 优化模块开发的能力,方便介入到打包流程的各个阶段

目前HotPatcher的开发和更新都是我个人在进行维护和支持。个人的精力有限,只有业余的时间做开源的事情,欢迎有兴趣加入到HotPatcher开发者的朋友对项目进行开源共建。

捐赠

几年来,HotPatcher一直以免费工具开放使用,开发和更新的过程耗费了我挺多精力和时间。

但我依然坚持免费和持续更新,只因为我热爱写代码,希望把我的技术带给更多人使用,提升UE社区的技术共享,兴趣的价值不是钱能够衡量的。

以后HotPatcher的核心功能也会一直作为免费工具发布,并进行持续更新。

如果HotPatcher项目有帮助到你,并希望HotPatcher以后能够做的更好,可以扫描下方的捐赠二维码。

微信支付 支付宝

您捐赠后可以点击HotPatcher捐赠者信息收集表,提交您的捐赠信息。

如果您捐赠后提交了捐赠信息,我会不定期地进行整理,在项目页面内展示,对您的捐赠表示感谢。

全文完,若有不足之处请评论指正。

微信扫描二维码,关注我的公众号。

本文标题:HotPatcher的模块化改造和开发规划
文章作者:查利鹏
发布时间:2023年01月07日 11时25分
本文字数:本文一共有3.8k字
原始链接:https://imzlp.com/posts/30178/
许可协议: CC BY-NC-SA 4.0
文章禁止全文转载,摘要转发请保留原文链接及作者信息,谢谢!
您的捐赠将鼓励我继续创作!