Lua C++ Binding之Lunar, Luna

服务端引擎的脚本, 我们项目在老端游项目上发展, 采取的是Lua脚本. 当前服务端的发展趋势是瘦引擎, 胖脚本模式, 基本上引擎负责的功能非常少, 主要是网络, 定帧, 定时器, 引擎通过导出相应的接口给脚本层调用, 数据基本上都是放在脚本层里, 引擎层只记录一些相关功能必须的数据, 如我们的引擎层里面记录了断线重连相关的验证信息, 玩家所在battle信息用于转发battle和client之间的通讯数据等. 瘦引擎胖脚本的好处是基础设施架设好之后, 可以很快的铺玩法, 而且由于脚本虚拟机的存在, 服务端代码的稳定性和健壮性有一定的保证, 缺点可能就是老大难的脚本执行效率问题.

我们的引擎入口是在C++, 也可以认为C++这一层次就是引擎层, 而Lua这一层是脚本层. 回到主题, 引擎层和脚本层需要能够自由切换, 可以方便的从引擎层调用进入脚本层, 脚本层也需要方便的使用引擎层提供的数据对象和接口, 我们服务端采取的是一个很轻量级的binding方案, 就是lunar.h(http://lua-users.org/wiki/CppBindingWithLunar), 可以看到, 这是一个比较古老的方案, 支持Lua5.0, 5.1版本, 5.2, 5.3版本可能需要修改一些接口调用才能编译通过.

对于lunar.h, 它提供了以下功能:

1. 提供了定义机制, 可以在Lua层声明C++对象

2. 提供了push接口, 可以在C++层传入C++对象(唯一的userdata, 就是对同一对象多次调用push, 传入的是同一个userdata对象), 在Lua层可以调用该对象注册给Lua层调用的接口

3. 提供了call接口, 可以在C++层调用Lua层定义的扩展函数, 或者是调用对象的Lua函数接口(http://lua-users.org/wiki/CallingLuaFromCpp), 调用对象的Lua函数接口是指从C++层调用该对象注册给Lua层的接口, 从而达到不用重复实现函数的目的, 但是理论上来说效率会下降, 距离来说, 对象sugar有一个taste接口, 一个c_taste接口(注册给Lua层使用), 两者功能重复, call可以让你只实现c_taste接口, 当C++层需要调用这个接口的时候, 调用c_taste接口, 而不需要重复编写一个taste接口.

4. 对于对象的生命周期, Lunar的默认处理是对象由C++层来销毁, 但是对于在C++层创建的对象, 可以通过在push时设置gc参数为true, 将销毁的行为交由Lua层处理. 而对于在Lua层创建的C++对象, 一定是由C++层来进行销毁的, 这部分要特别特别注意, 我们的做法是这类对象要么是全局对象, 声明周期从创建到服务器关闭, 例如db对象, 要么是一个函数调用中使用, 不会被缓存下来放到别处使用, 而函数调用末进入引擎层接口后, 引擎层会回收这个对象, 如buffer对象, 底层发送完这个网络buffer之后就会delete, 而脚本层不会缓存住这个buffer对象, 之后在某个时刻再次使用(无法判断底层是否已经回收了这个对象), 算是潜规则.

对于Lunar, 其代码注释写的已经不错, 接口不多容易理解, 其实现代码翻译为Lua代码如下(以实现一个Sugar的C++类为例)

 1 methods = {
 2     new = new_T,
 3     func1 = thunk, --with upvalue func1 RegType
 4     func2 = thunk, --with upvalue func2 RegType
 5     -- ...
 6 }
 7 userdata_mt = {
 8     __metatable = methods,
 9     __index = methods,
10     __tostring = tostring_T,
11     __gc = gc_T,
12     userdata = { __mode = "v", lightuserdata = fulluserdata, ... }
13     ["do not trash"] = { __mode = "k", fulluserdata = true, ... }
14 } -- 存在注册表当中
15 mt = { __call = new_T }
16 setmetatable( methods, mt )
17 _G["Sugar"] = methods

Luna.h也是Lua C++ binding的一种方式, 最新的Luna版本是LunaFive(http://lua-users.org/wiki/LunaFive), LunaFive个人认为还未能达到Lunar的使用级别, 它具有一些Lunar没有的优点, 包括

1. 直接支持Lua5.3

2. 支持命名空间, Register接口的第二个参数, 默认为全局表

3. 提供了获取属性的接口函数, 而Lunar需要直接写set/get函数

4. 支持将C函数作为对象保存, 比如local func = obj.func, 之后func()是合法的, 而Lunar不能

相对于Lunar的缺点有:

1. gc行为是默认delete, 也就是说对象生命周期由Lua gc控制, 回收时机不确定

2. 没有考虑同一对象的多次push, 会产生多个userdata, Lunar只会产生一个

LunaFive的代码实现翻译为Lua代码如下, 利用了__index是function时会传入原始的table/userdata来获取C++对象指针, 通过index来对应记录成员变量和成员函数, 最多支持128个变量和128个函数.

 1 userdata_mt = {
 2     __gc = gc_obj,
 3     __tostring = to_string,
 4     __eq = equals,
 5     __index = property_getter,
 6     __newindex = property_setter,
 7     ["prop_name1"] = 1,
 8     ["prop_name2"] = 2,
 9     ...
10     ["func_name1"] = 1 | ( 1 << 8 ),
11     ["func_name2"] = 2 | ( 1 << 8 ),
12     ...
13 } -- 存在注册表当中
14 _G["Sugar"] = constructor

我们项目使用的是Lunar, 虽然古老, 但是起码经受了端游项目和手游项目的考验, 虽然没有很花哨的功能, 需要遵守一些潜规则, 但是如果不是追求极致, Lunar这个解决方案应该也是够用了.

现在我在看一个新的解决方案, 是github上的一个开源项目lua-intf(https://github.com/SteveKChiu/lua-intf), 利用了一些C++11的新特性, 看起来蛮优雅的, 搜了一下似乎资料不多, 等细心研读之后有机会再分享.

时间: 2024-08-07 02:14:33

Lua C++ Binding之Lunar, Luna的相关文章

Free Lua Scripting Interpreter Library For Delphi XE7 Firemonkey On Android And IOS

http://www.fmxexpress.com/free-lua-scripting-interpreter-library-for-delphi-xe7-firemonkey-on-android-and-ios/ http://blog.spreendigital.de/tag/delphi/ http://blog.spreendigital.de/2015/02/18/verysimple-lua-2-0-a-cross-platform-lua-5-3-0-wrapper-for-

c++对象与lua绑定

2015.1.29 wqchen. 转载请注明出处 http://www.cnblogs.com/wqchen/ 本文主要探讨c++的类对象和lua脚本的绑定使用,读者需要有一定的lua以及lua的c api接口知识:). 如果你使用过c/c++和lua混合编程,那么肯定会熟悉宿主(c/c++)与脚本(lua)之间函数的注册与调用.userdata等等方面知识.宿主对象与脚本的绑定使用,其实可以看作是userdata与注册函数的整合,只不过多了一层语法糖.下面我们一起来分析一下这层语法糖是怎样实

所有的GUI Toolkit,类型之多真开眼界

The GUI Toolkit, Framework Page User interfaces occupy an important part of software development. This page provides a comprehensive reference on toolkits for building graphical user interfaces (GUIs), with emphasis on resources for Free Software (Op

[ISSUE]Lambda binding for lua is not supported.

环境: cocos2d-x + lua 3.0beta2 想使用CCNotification, 发现3.0已经替换为CCEvent, 晃了一眼设计,不错 原来在C++ 上自己也实现了一套Event,因为不满意CCNotification 没有优先级,没有自定义分类(比如UI,Logic),不能携带数据,现在3.0的设计基本满足了需求 使用中还是发现一点问题 (self is a CCLayer): self:getEventDispatcher():addCustomEventListener(

Cocos2d-x 3.1 Lua Binding

Cocos2d-x 3.1 Lua Binding 参考:http://www.cocos2d-x.org/docs/manual/code-ide/binding-custom-class-to-lua/en 添加需要绑定的C++类 在xcode中,把my文件夹拖到cocos2d_libs.xcodeproj中 HNLuaTest.h // // HNLuaTest.h // cocos2d_libs // // Created by Eleven Chen on 14-8-5. // //

cocos2d-x LUA Binding实现C++里访问LUA的自定义对象

LUA Binding比JSBinding要简单,无论是使用脚本自动绑定还是手动写绑定代码,都能很轻松实现在LUA访问C++的类和对象.但如果想在C++里访问LUA里的自定义类和对象,则需要再自己修改一下C++的代码了. 应用场景: 1.  假设在LUA里有一个类MyLayer,继承了CCLayer,并添加了a,b,c,d这4个属性. 2.在LUA里,创建一个MyLayer的实例对象,并添加到当前的Scene中,然后通过Scene.getChildByTag方法拿出这个MyLayer的实例对象时

lua luna工具库

luna工具库 概述 luna库提供了几个lua开发的常见辅助功能: lua/c++绑定 lua序列化与反序列化 变长整数编码,用于lua序列化,当然也可以方便的用于其他场合 这里把代码编译成了动态库,由于代码非常简单,实际使用时也可以简单的复制文件到自己的工程.lua_archiver引用了lz4库用于数据压缩(lz4.h+lz4.c). lua/c++绑定库(luna.h, luna.cpp)支持Windows, Linux, macOS三平台,默认的luna.h实现需C++14支持.如果编

浅析C++绑定到Lua的方法

注:原文也在公司内部论坛上发了 概述 尽管将C++对象绑定到Lua已经有tolua++(Cocos2d-x 3.0用的就是这个).LuaBridge(我们游戏client对这个库进行了改进)和luabind等各种库能够直接使用了(lua-users.org上有对各种语言绑定到lua库的汇总),但弄清楚C++对象绑定到Lua的常见方法,不但有助于更深的了解Lua的机制,还能够方便改动第三方库以满足实际项目需求. 本文通过分析第三方库Lunar(我们游戏服务端用的是Luna,Lunar是Luna添加

cocos进阶教程(1)Lua调用自定义C++类和函数的最佳实践

第一层:纯C环境下,把C函数注册进Lua环境 a.lua 文件 print(foo(99)) a.c 文件 #include <lua.h> #include <lualib.h> #include <lauxlib.h> int foo(lua_State *L) { int n = lua_tonumber(L, 1); lua_pushnumber(L, n + 1); return 1; } int main() { lua_State *L = lua_ope