UE As Lib机制初探

UE4.27推出了一项新的机制,可以把UE编译成库,能够嵌入到外部程序中,由其他的程序来驱动引擎的执行与消息通信。但是目前官方还没有放出任何有价值的文档,我分析了引擎中的相关代码,提出一个UE as Lib的实践方案,理论上也能在4.27之前的引擎版本实现,或许会与后续官方发布的文档不一致,权当抛砖引玉。相关的研究内容也会在本篇文章中持续更新。

首先,我认为UE as Lib并不是以静态链接库的方式提供的,因为引擎内具有大量依赖UHT和UBT的代码,而且还具有大量的模板实现,想要编译出一个独立的Lib是非常麻烦的,并且使用时还需要抽取大量的代码,所以我认为UE as Lib是将引擎编译成DLL的形式提供的,外部程序通过DLL的导出符号驱动引擎。

注意:目前UE as Lib只能用于Windows平台。

UE在4.27中加入了一个新的Runtime Module:UELibrary,用于导出外部驱动引擎的符号。

其导出的符号为:

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
extern "C"
{
/**
* Initializes UE as a library.
*
* @param hInst The instance of the outer application which wants to embed UE.
* @param hWnd The window of the outer application into which UE is to be embedded.
* @param CmdLine The command line to pass to UE - should contain a .uproject file and map to load at minimum.
*
* @return Zero if creation was successful, non-zero if an error occurred.
*
* @note UE can currently only be embedded in a single window.
* @note There is an A and W overload for different character widths of the command line argument. Typical usage
* should be to use the UELibrary_Init function which maps to the appropriate overload for the outer
* application's Unicode setting.
*/
UELIBRARYAPI int UELibrary_InitA(HINSTANCE hInst, HWND hWnd, const char* CmdLine);
UELIBRARYAPI int UELibrary_InitW(HINSTANCE hInst, HWND hWnd, const wchar_t* CmdLine);

#ifdef UNICODE
#define UELibrary_Init UELibrary_InitW
#else
#define UELibrary_Init UELibrary_InitA
#endif


/**
* Ticks the UE library. This should be called frequently by the outer application.
*
* @return Zero if ticking was successful, non-zero if an error occurred.
*/
UELIBRARYAPI int UELibrary_Tick();


/**
* Passes windows messages from the outer application to the UE library.
*
* @param hWnd As per WndProc.
* @param message As per WndProc.
* @param wParam As per WndProc.
* @param lParam As per WndProc.
*
* @return As per WndProc.
*/
UELIBRARYAPI LRESULT UELibrary_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);


/**
* Shuts down the UE library.
*
* @return Zero if shutdown was successful, non-zero if an error occurred.
*
* @note UE cannot be started up again once shut down.
*/
UELIBRARYAPI int UELibrary_Shutdown();
}

提供了四个到处函数用于初始化引擎、Tick、传递消息、关闭引擎,符合前面的推断,将引擎编译成DLL,外部程序通过调用这四个函数来实现驱动引擎。

关于如何编译UE as Lib,我提供一个思路。首先要明确需求:

  1. 将引擎编译成一个独立的DLL
  2. 依赖UELibrary模块的导出符号
  3. 必须通过UE的编译系统来编译引擎

为了实现这几个需求,需要了解UE的构建系统。

注意:UE的UE as Lib也可以将游戏项目编译为DLL,由外部程序来驱动引擎启动游戏,只需要将下面的操作从Program换到游戏项目的Target即可。

UE的Module,需要被Target依赖才能够通过UE的构建系统进行编译。之前我写过一篇文章,可以将UE作为一个库来实现console或WinGUI程序:Create A Standalone Application in UE4,在这篇文章中我提供了一个开源工具ue4program,可以方便地创建一个StandaloneApplication程序,由Program依赖UELibrary模块,然后编译这个Program,将UELibrary模块和依赖的Module编译其中。

然后,Pogram默认是编译成exe的,想要实现UE as Lib编译成DLL,其实就是将Program的Target编译成DLL!

首先需要通过hxhb/ue4program创建一个Standalone Application模板:

1
2
# ue4program.exe ProgramName
$ ue4program.exe UEProgram

将创建出的目录放到引擎的Source/Programs下,执行GenerateProjectFiles.bat刷新sln,即可在UE4.sln中看到创建的Program项目。

UELibrary模块添加至UEProgram的依赖:

1
PrivateDependencyModuleNames.Add("UELibrary");

然后编辑UEProgramTarget.cs,需要修改LinkType:

1
LinkType = TargetLinkType.Monolithic;

这样会把所有的代码都编译到一个最终的二进制中,UE默认的则是Modular,通过DLL方式访问其他的模块。

还需要修改bShouldCompileAsDLL

1
2
// Whether this target should be compiled as a DLL. Requires LinkType to be set to TargetLinkType.Monolithic.
bShouldCompileAsDLL = true;

默认为false,会把Program编译成一个exe,但是我们的目标就是DLL。
添加UE_LIBRARY_ENABLED=1宏,在UELibrary中只有这个宏为1,才包含了前面导出符号的实现代码:

1
GlobalDefinitions.Add("UE_LIBRARY_ENABLED=1");

修改之后编译UEProgram这个项目即可,编译完成之后即可在引擎的Binaries/Win64下看到UProgram.dll

它包含了引擎代码、以及UELibrary的导出符号,可以在外部程序中通过OpenLibrary来加载和执行,就是常规的C++调用动态链接库的用法了。编译出DLL之后,就实现了UE as Lib,使用方就可以脱离UE的编译系统,在普通的程序中调用了。

简单总结一下,目前UE as lib其实并不是一个完全全新的东西,只是UE把驱动引擎的API做了符号导出,在4.27之前的引擎版本中,也可以通过实现一个UELibrary的模块导出符号,通过文中的这种方式实现引擎的动态链接库化。

时间问题,暂时只分析到这里,至于编译出的DLL如何嵌入第三方程序由外部来驱动引擎,有时间再来补充。

相关链接:

未完待续。

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

本文标题:UE As Lib机制初探
文章作者:查利鹏
发布时间:2021年08月24日 09时34分
本文字数:本文一共有1.8k字
原始链接:https://imzlp.com/posts/26475/
许可协议: CC BY-NC-SA 4.0
文章禁止全文转载,摘要转发请保留原文链接及作者信息,谢谢!
您的捐赠将鼓励我继续创作!