最近在 UE 5.8 项目里接 UnLua,遇到的主要问题不是“UnLua 怎么用”,而是旧版 UnLua 源码在 UE 5.8 下会碰到一批编译兼容问题。本文把整个配置过程整理一下:先聊聊为什么要用 UnLua,再说 UE 5.8 对这类插件的影响,最后给出一套可以落地的配置步骤。
本文基于 Tencent UnLua 做 UE 5.8 兼容整理。它不是官方发布版本,只是一次面向 UE 5.8 的实践记录。
原项目:https://github.com/Tencent/UnLua
UnLua 的作用,是把 Lua 脚本接入 Unreal Engine,让一部分游戏逻辑可以从 C++ 或蓝图中拆出来,用脚本方式组织。
这件事最直接的好处是迭代快。C 很适合写底层系统、性能敏感逻辑和稳定框架,但如果所有玩法流程、UI 行为、任务脚本、触发器逻辑都放进 C,每次小改动都要经历编译、热重载、重启编辑器,节奏会很重。Lua 文件是普通文本,修改和组织成本低,很适合承载变化频繁的业务逻辑。
UnLua 另一个重要价值是它能和 UE 的对象体系打通。Lua 侧可以访问 UObject、UClass、UFunction、UProperty 等反射对象,也可以和蓝图类绑定。这样项目里可以保持一种比较清晰的分工:
如果项目未来考虑热更新,Lua 也更自然。虽然热更新本身还涉及资源管理、版本控制、下载校验等完整体系,但脚本层逻辑比 C++ 模块更适合做运行时加载和替换。
还有一个越来越现实的点:Lua 文件是文本,对 Agent 或 AI 辅助开发很友好。相比直接修改蓝图资产,生成、审查和回滚 Lua 逻辑都轻得多。
UnLua 官方版本并不是直接为 UE 5.8 准备的。UE 5.8 的构建工具链和引擎 API 有一些变化,旧插件源码直接放进项目里,常见结果就是打开项目时出现:
Missing Modules: UnLua, UnLuaEditor
这个弹窗的意思不是项目坏了,而是 .uproject 已经启用了 UnLua,但 UE 找不到当前引擎版本可用的插件 DLL。通常原因是插件还没编译,或者插件是别的 UE 版本编出来的。
这次适配 UE 5.8 时,主要遇到这些变化:
UE 5.8 使用更新的构建工具链
本地验证时 UE 5.8 使用自带 .NET 10 SDK、VS2022 MSVC 工具链和 Windows SDK。旧版 UnLua 的 UBT/UHT 辅助项目仍按旧框架写,会碰到 net6.0、旧枚举、旧 API 不兼容。
UHT 插件 API 有变化
UnLua 的默认参数收集器依赖 UHT 导出流程。UE 5.8 中需要从 Session.Modules 遍历 module 和 package,旧写法无法直接编译。
UObject 字段链表更多使用 TObjectPtr
UE 5.8 中 UStruct::Children、UField::Next 等字段已经是 TObjectPtr<UField>,旧代码按 UField** 操作链表会类型不匹配。
Delegate API 有调整
多播委托调用需要适配新的 ProcessDelegate<UObject>(Params) 写法。
元数据 API 有变化
UMetaData::CopyMetadata 需要改为 FMetaData::CopyMetadata,并补充对应 include。
格式化字符串检查更严格
FString::Printf 更倾向接受编译期可检查的字面量格式串。旧代码把变量作为 format 传入,容易在 UE 5.8 下失败。
Lua 内部类型名和 UE 类型名冲突
Lua 内部的 TString 会和 UE 5.8 的类型/别名冲突,需要在包含 Lua 内部头文件时做隔离。
所以 UE 5.8 配 UnLua 的关键不是“把插件复制进去”这么简单,而是要先保证 UnLua 源码能被 UE 5.8 工具链完整编译。
需要准备:
如果项目是纯蓝图项目,建议先在 UE 中添加一个空 C++ 类,让项目生成 Source、.Target.cs、.Build.cs 等 C 工程结构。UnLua 是 C 插件,最终需要通过 Unreal Build Tool 编译出对应模块。
配置完成后,项目结构大致如下:
YourProject/
Config/
DefaultUnLuaEditor.ini
Content/
Script/
Main.lua
Plugins/
UnLua/
UnLua.uplugin
Source/
Content/
Config/
Source/
YourProject.uproject
其中:
Plugins/UnLua 是插件本体。Config/DefaultUnLuaEditor.ini 用来配置 UnLua 编辑器行为和启动模块。Content/Script/Main.lua 是默认 Lua 启动入口。把适配过 UE 5.8 的 UnLua 插件复制到项目:
YourProject/Plugins/UnLua
如果项目里已经有旧的 Plugins/UnLua,建议先备份旧目录,再放入新的插件。
注意不要把旧版本编译出来的 Binaries、Intermediate 当成可靠产物。UE 插件最好在当前机器、当前引擎版本下重新编译。
打开项目 .uproject,在 Plugins 数组里加入 UnLua:
{
"Name": "UnLua",
"Enabled": true
}
一个简化示例:
{
"FileVersion": 3,
"EngineAssociation": "5.8",
"Modules": [
{
"Name": "YourProject",
"Type": "Runtime",
"LoadingPhase": "Default"
}
],
"Plugins": [
{
"Name": "UnLua",
"Enabled": true
}
]
}
如果项目中已经有其他插件,不要覆盖原来的 Plugins 数组,只需要追加 UnLua 这一项。
创建或修改:
Config/DefaultUnLuaEditor.ini
写入:
[/Script/UnLuaEditor.UnLuaEditorSettings]
bAutoStartup=True
bEnableDebug=True
HotReloadMode=Manual
LuaVersion=lua-5.4.3
[/Script/UnLua.UnLuaSettings]
StartupModuleName=Main
这里比较关键的是:
StartupModuleName=Main
它表示 UnLua 启动时加载 Content/Script/Main.lua。
创建目录:
Content/Script
然后创建:
Content/Script/Main.lua
写入一个最小启动模块:
local M = {}
function M.Initialize()
print("UnLua initialized")
end
return M
这个文件只是验证 UnLua 启动链路用的。项目真正开始写逻辑后,可以在这里继续拆分模块、初始化系统、加载其他 Lua 文件。
打开 PowerShell,执行:
& "C:\Program Files\Epic Games\UE_5.8\Engine\Build\BatchFiles\Build.bat" -projectfiles -project="C:\YourProject\YourProject.uproject" -game -rocket -progress
把 C:\YourProject\YourProject.uproject 换成自己的项目路径。
这一步会让 UE 重新识别插件、模块和工程结构。
执行:
& "C:\Program Files\Epic Games\UE_5.8\Engine\Build\BatchFiles\Build.bat" YourProjectEditor Win64 Development -Project="C:\YourProject\YourProject.uproject" -WaitMutex -FromMsBuild -NoHotReloadFromIDE
需要替换两处:
YourProjectEditor:项目名加 EditorC:\YourProject\YourProject.uproject:项目 .uproject 完整路径这里建议保留:
-NoHotReloadFromIDE
它可以绕开 Live Coding/Hot Reload 锁定模块导致的编译失败。配置插件时,最好关闭 UE Editor 和 Live Coding Console,再执行完整编译。
编译成功后,项目里应该生成:
Plugins/UnLua/Binaries/Win64/UnrealEditor-UnLua.dll
Plugins/UnLua/Binaries/Win64/UnrealEditor-UnLuaEditor.dll
这两个 DLL 存在后,再打开 .uproject,一般就不会再弹:
Missing Modules: UnLua, UnLuaEditor
如果你是从官方 UnLua 源码自己适配 UE 5.8,下面这些点是这次实际改过的地方。
位置:
Source/ThirdParty/Lua/Lua.Build.cs
旧代码里使用了 WindowsCompiler.VisualStudio2019 之类的枚举判断。UE 5.8 中这个枚举不再适用,可以改成字符串判断:
Target.WindowsPlatform.Compiler.ToString() == "VisualStudio2019"
位置:
Source/UnLuaDefaultParamCollectorUbtPlugin/UnLuaDefaultParamCollectorUbtPlugin.ubtplugin.csproj
将:
<TargetFramework>net6.0</TargetFramework>
改为:
<TargetFramework>net10.0</TargetFramework>
同时移除不需要的 Microsoft.CSharp 包引用,匹配 UE 5.8 自带 .NET 10。
位置:
Source/UnLuaDefaultParamCollectorUbtPlugin/UnLuaDefaultParamCollectorUbtPlugin.cs
UE 5.8 中需要从:
Session.Modules
遍历 module,再遍历 package,旧的 UHT 导出写法不能直接使用。
位置:
Source/UnLua/Public/UnLuaSettings.h
将:
MetaClass="Object"
改为:
MetaClass="/Script/CoreUObject.Object"
位置:
Source/UnLua/Public/UnLuaTemplate.h
补充:
TChooseClass
TIsTriviallyDestructible
TIsTriviallyCopyConstructible
这些是 UnLua 旧代码依赖、但在 UE 5.8 下需要自行兼容的模板类型。
位置:
Source/UnLua/Private/LuaCore.cpp
Source/UnLua/Private/LuaEnv.cpp
在包含 Lua 内部头文件时,用类似方式隔离:
#define TString LuaTString
// include Lua internal headers
#undef TString
位置:
Source/UnLua/Private/LuaEnv.cpp
去掉不兼容的:
AsyncLoading
保留:
Async
位置:
Source/UnLua/Private/LuaFunction.cpp
增加:
#include "UObject/MetaData.h"
并将:
UMetaData::CopyMetadata(...)
改成:
FMetaData::CopyMetadata(...)
位置:
Source/UnLua/Private/ReflectionUtils/FunctionDesc.cpp
多播委托调用改为:
ScriptDelegate->ProcessDelegate<UObject>(Params);
位置:
Source/UnLua/Private/UnLuaConsoleCommands.cpp
不要把变量作为 format 传给 FString::Printf,改为直接传 TEXT(R"(... )") 这样的字面量。
位置:
Source/UnLua/Private/UnLuaBase.cpp
有一处日志格式串需要两个 %s,但只传了一个参数,需要补上:
ANSI_TO_TCHAR(__FUNCTION__)
位置:
Source/UnLua/Private/LuaOverridesClass.cpp
UE 5.8 中:
UStruct::Children
UField::Next
是 TObjectPtr<UField>,链表操作要改成使用:
TObjectPtr<UField>*
而不是旧的 UField**。
说明 UE 仍然没有找到当前引擎版本可用的插件模块。检查:
Plugins/UnLua 是否存在。.uproject 是否启用了 UnLua。YourProjectEditor。UnrealEditor-UnLua.dll 和 UnrealEditor-UnLuaEditor.dll。建议关闭编辑器和 Live Coding Console 后重新编译。
编译命令加上:
-NoHotReloadFromIDE
如果仍然失败,就完全关闭 UE Editor 和 Live Coding Console,再执行 Build.bat。
先在 UE 编辑器里添加一个空 C 类,生成 C 项目结构,再配置 UnLua。否则很多 C++ 插件相关的构建流程会不完整。
一般不建议提交:
Plugins/UnLua/Binaries/
Plugins/UnLua/Intermediate/
它们是当前机器、当前引擎版本生成的构建产物。更推荐提交源码和配置,让每台机器自己编译。
推荐 .gitignore:
Binaries/
Intermediate/
Saved/
DerivedDataCache/
*.pdb
*.dll
*.modules
*.target
在 UE 5.8 中配置 UnLua,真正重要的是三件事:
第一,使用已经适配 UE 5.8 的 UnLua 源码。旧源码直接复制进项目,大概率会在 UBT/UHT、Delegate、TObjectPtr、元数据 API 等地方报错。
第二,把插件接入项目:复制到 Plugins/UnLua,在 .uproject 中启用,添加 DefaultUnLuaEditor.ini,创建 Content/Script/Main.lua。
第三,用 UE 5.8 的 Build.bat 编译 YourProjectEditor Win64 Development,让当前引擎版本生成自己的 UnLua 和 UnLuaEditor DLL。
只要插件模块编译成功,Missing Modules: UnLua, UnLuaEditor 这类弹窗就会消失,后续就可以开始把玩法、UI 或关卡逻辑逐步拆到 Lua 里。