跳到主要内容

为什么选择 ZLua

xLua、tolua 已是 Unity Lua 绑定的成熟选择。ZLua 不是「多一个绑定库」,而是面向 Il2Cpp Player 极致互操作性能C# 语义统一 的重新设计——把 Lua 当作另一种 Native,互操作类比 P/Invoke。


一句话

更少生成与配置、更贴近 C# 的 Lua 访问方式、Player 侧 C++ 直桥(目标态)与多路径低 GC struct 传递;代价是 Alpha 阶段Il2Cpp Player 尚未全量、以及 libil2cpp 集成维护成本


30 秒结论

#理由一句话Editor (Mono) 今天Player (Il2Cpp) 今天
1设计易用[LuaInvoke] 声明式 C#→Lua,CSharp 懒加载 Lua→C#✅(MVP 子集)
2C# 支持全泛型、数组、重载、ref/out/in、Event✅ 全量❌ 逐步对齐
3互操作更快C++ 直桥、无 libxlua 折返、字段 offset 直读✅(Mono 已优化)🚧 目标态,MVP 未体现
4GC 更省Opaque / 字段展开 / StructUserData 多路径✅ 规范+实现🚧 逐步对齐
5无 C# Wrap不 Generate 海量 Wrap,签名复用原生桥🚧 Codegen 进行中

:::info 读前须知

  • 上表 Player 列以 项目状态 为准;性能/GC 的 设计目标 不等于 当前 MVP 实测
  • 路径级性能倍数为 理论推演,尚无官方 benchmark → 与 xLua 对比
  • Il2Cpp 完整版预计 2026 年 8 月路线图。 :::

我是谁?该不该继续读

你是谁建议
新项目、性能敏感、愿跟路线图读本页 → 5 分钟快速开始zlua-demo
已有 xLua/tolua 存量、近期上线先看 不适合迁移草稿
架构 / 性能 reviewer本页 + 与 xLua 对比 + Il2Cpp 架构
只关心 API 能不能用兼容性矩阵 + Mono Editor 开发

1. 设计易用:Lua 当作 Native

痛点(xLua / tolua)

  • C#→Lua 常是 命令式LuaEnvGetInPath<LuaFunction>Call、Delegate 类型匹配
  • Lua→C# 要配 生成列表LuaCallCSharp 等),改 API 要重新 Generate
  • 心智模型是「Lua 插件 API」,不是「另一种 native 调用约定」

ZLua 怎么做

C# 互操作ZLua作用
P/Invoke[LuaInvoke]C# static extern 调 Lua 模块函数
MarshalAs[LuaMarshalAs]覆盖编组
CSharp 根表Lua 侧懒加载类型,语法贴近 C#
// C# → Lua:声明即可,编译期注入桥接
[LuaInvoke("app", "add")]
private static extern int AppAdd(int a, int b);
-- Lua → C#:无需预生成 Wrap
CSharp['AC'] = CSharp['Assembly-CSharp']
print(CSharp.AC.Demo.Add(3, 5))

Workflow 对比:新增「C# 调 Lua 函数 add(a,b)」

步骤xLuaZLua
1. Lua 写函数app.lua 里定义同左,return { add = add }
2. C# 侧绑定GetInPath / 生成 Delegate[LuaInvoke("app","add")] static extern
3. 生成配置常涉及 Generate / 路径约定
4. 调用func.Call(10, 20)AppAdd(10, 20)

今天能用吗

环境状态
Editor (Mono)✅ 与文档一致
Player (Il2Cpp)[LuaInvoke] + 基础模块加载(MVP);复杂 marshal 见 兼容性

C# 调用 Lua 指南 · 设计概览


2. C# 支持完整

痛点

  • 泛型、ref/out/in、Event、多维数组等在 Lua 绑定里常是 边角能力,依赖生成配置或 C# 包装层中转
  • 团队要在「Lua 能写什么」与「生成白名单」之间反复拉扯

ZLua 怎么做(Mono 已实现)

能力Lua 侧要点
泛型类zlua.make_generic_type
泛型方法make_generic_inst
数组make_szarray_type / new_szarray_*
重载obj:Run(x) dispatch;热路径 [LuaAlias] / get_method
ref / out / inzlua.new_ref(T) 真 ref;裸 number 为拷贝语义
Event / DelegateEvent 表;delegate 形参直传 function
-- 重载 + 显式绑定(Mono)
local run_i32 = zlua.get_method(demo, "Run", zlua.signature(zlua.types.int32), false)
run_i32(demo, 10)

与 xLua 差异(能力层)

场景xLua 常见做法ZLua
List<int>包装类或避免 Lua 侧闭合泛型Lua 侧 make_generic_type
ref int有支持,语义因版本/生成而异规范统一 + new_ref
重载热路径生成 Wrap 内分派dispatch + 别名 / 显式 get_method

今天能用吗

环境状态
Editor (Mono)路线图 v1.0 清单 已实现
Player (Il2Cpp)❌ 泛型 / Event / ref / 重载 dispatch 等 尚未;仅 Demo 级

兼容性矩阵


3. 互操作性能:更少的「折返」

痛点

xLua / tolua 典型路径:Lua VM → C# Wrap → LuaDLL (P/Invoke) → C#,栈操作多次跨界;读字段常经 Wrap/getter。热循环里 函数体极短 时,互调固定开销占主导。

ZLua 原理(Il2Cpp 目标态)

环节xLua 类方案ZLua 目标
Lua 引擎独立 libxlua嵌入 libil2cpp
Lua → C#C# Wrap + 多次 LuaDLLC++ 内联 lua API + methodPointer
C# → LuaC# 循环 LuaDLL[LuaInvoke] 一次 InternalCall
int 字段常经 Wrapoffset 直读(规范)
桥接体积每类型大量 Wrap按签名复用 MethodBridge

为何有机会快数倍(热路径、理论值): 消灭 libxlua 往返与 C# Wrap 层;具体场景倍数见 与 xLua 对比 §4非实测)。

今天能用吗

环境状态
Editor (Mono)✅ Expression 编译桥,对标 xLua CodeEmit 档(见 性能报告
Player (Il2Cpp)🚧 MVP 不能代表设计目标;勿用当前 Player 做 xLua 性能对比

调用路径概览 · Il2Cpp 架构


4. GC 优化:互调不只是 CPU

痛点

struct、坐标、战斗公式中间值若走 table 或 boxing,热路径会产生 大量 GC Alloc,Profiler 里互操作「又慢又抖」。

ZLua 三条路径(选型表)

路径GC适用场景
OpaqueLightUserData零 GC(lightuserdata)C#→Lua 同步链内临时 struct / 形参槽
ComposeFromStack / LuaStackFields零 GC(多个 number)Vector2 等 blittable 小 struct 热路径
StructUserData仅 userdata 自身持有、改字段、ref 传参
table 默认有 table 分配脚本便捷写法
-- 热路径:两个 number,无 userdata
Foo(1.0, 2.0) -- C# void Foo(Vector2),ComposeFromStack

-- 长生命周期 + ref
local p = CSharp.AC.Point2D(1, 2)
Demo.Process(ref p)

规范命名:ComposeFromStack(从栈上标量构造 struct)≈ ConstructorFromUnpackedFields;LuaStackFields解构为多值)≈ DeconstructorToUnpackedFields。

与 xLua

xLua 传 Vector2 等常见为 table 或 Wrap 属性,易分配;ZLua 允许在热路径 显式选零 GC 路径(细节 → Struct 编组)。

今天能用吗

环境状态
Editor (Mono)✅ Opaque / StructUserData / ref 等已实现
Player (Il2Cpp)🚧 随 v1.0 对齐

编组模型概览


5. 不需要配置 Wrapper 生成

痛点(xLua / tolua 共性)

N 类型 × M 成员 → 海量 Wrap / binding 代码 → 工程体积膨胀、CI 必跑 Generate、合并冲突

tolua 依赖 导出的 binding 代码;xLua 依赖 Generate + LuaCallCSharp 白名单。两者都是「先生成,再调用」模型。

ZLua 怎么做

  • public 类型 首次访问自动 EnsureBinding LuaCallCSharp 列表
  • Player 侧生成 C++ MethodBridge(按签名复用),膨胀 C# Wrap
  • 改 C# public API → 下次访问自动更新绑定(Editor);Player 走 Codegen 重建

Workflow 对比:新增 C# 类型给 Lua 用

步骤xLua / toluaZLua
标记可导出[LuaCallCSharp] / 导出列表不需要(public 即可)
生成Generate / 跑 tolua 工具无 C# Wrap 步骤
Lua 访问CS.Foo / 生成命名空间CSharp.asm.Foo()
发 Player确认 Wrap 进包确认 Codegen + MVP 能力清单

今天能用吗

环境状态
Editor (Mono)✅ 无 Wrap 生成
Player (Il2Cpp)🚧 Codegen 覆盖范围随 MVP → v1.0 扩大

不适合选 ZLua

情况更稳妥的选择
现在就要上生产,不能接受 Player 能力缺口xLua(成熟生态)
已有大量 xLua/tolua 资产,短期无迁移预算维持现状;评估 迁移草稿
不愿维护 libil2cpp fork / 升级 Unity 要 merge 引擎层xLua 插件形态更轻
Player 性能对比 xLua 作为立项依据等 Il2Cpp v1.0 + 官方 benchmark(当前 MVP 不具代表性)
只需要 Lua 跑逻辑、极少 C# 互调任意方案差异不大,成熟度优先

两者 不是 插件级替换;迁移需单独评估。


典型场景速查

场景ZLua 优势点注意
战斗公式 / 每帧上千次 int 互调§3 少折返 + §4 少分配Player 需等 v1.0;Editor 可验证 API
UI 事件 / 低频 C#↔Lua§1 声明式 [LuaInvoke]Player MVP 通常够用
Vector2 / 碰撞 struct 热路径§4 ComposeFromStack 零 GC需显式 [LuaMarshalAs]
复杂泛型容器 Lua 侧构造§2 完整类型系统仅 Mono 今天可用
新项目从零接入§1 + §5 无 Generate接受 Alpha 与双运行时差异

下一步

  1. 5 分钟上手快速开始 + zlua-demo
  2. 确认 Player 边界项目状态 · 兼容性
  3. 深度对比与 xLua 对比(路径与理论性能)
  4. 已有 xLua迁移对照草稿

延伸阅读

文档内容
与 xLua 对比调用栈、ns 量级推演
设计概览L/Invoke 与自动生成流水线
Il2Cpp 架构Player C++ 实现
Struct 编组GC 路径完整规范
路线图v1.0 功能与时间线