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++类为例)
methods = { new = new_T, func1 = thunk, --with upvalue func1 RegType func2 = thunk, --with upvalue func2 RegType -- ... } userdata_mt = { __metatable = methods, __index = methods, __tostring = tostring_T, __gc = gc_T, userdata = { __mode = "v", lightuserdata = fulluserdata, ... } ["do not trash"] = { __mode = "k", fulluserdata = true, ... } } -- 存在注册表当中 mt = { __call = new_T } setmetatable( methods, mt ) _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个函数.
userdata_mt = { __gc = gc_obj, __tostring = to_string, __eq = equals, __index = property_getter, __newindex = property_setter, [, [, ... [ | ( << ), [ | ( << ), ... } -- 存在注册表当中 _G["Sugar"] = constructor
我们项目使用的是Lunar, 虽然古老, 但是起码经受了端游项目和手游项目的考验, 虽然没有很花哨的功能, 需要遵守一些潜规则, 但是如果不是追求极致, Lunar这个解决方案应该也是够用了.
现在我在看一个新的解决方案, 是github上的一个开源项目lua-intf(https://github.com/SteveKChiu/lua-intf), 利用了一些C++11的新特性, 看起来蛮优雅的, 搜了一下似乎资料不多, 等细心研读之后有机会再分享.
Lua C++ Binding之Lunar, Luna的更多相关文章
- cpgf如何实现lua script binding的?
Lib: https://github.com/cpgf/cpgf/tree/master 代码 以下是operator的实现函数 int UserData_operator(lua_State * ...
- Lua与javascript的差异
Lua与javascript的差异 2010-03-08 Lua模拟器js方案 1.语法级模拟 lua与js语言差异 1.1注释 js 为//,lua为--. 1.2变量 js利用var来声明全局变量 ...
- 所有的GUI Toolkit,类型之多真开眼界
The GUI Toolkit, Framework Page User interfaces occupy an important part of software development. Th ...
- C++ 100款开源界面库 (10)
(声明:Alberl以后说到开源库,一般都是指著名的.或者不著名但维护至少3年以上的.那些把代码一扔就没下文的,Alberl不称之为开源库,只称为开源代码.这里并不是贬低,像Alberl前面那个系列的 ...
- 仿迅雷播放器教程 -- C++ 100款开源界面库 (10)
(声明:Alberl以后说到开源库,一般都是指著名的.或者不著名但维护至少3年以上的.那些把代码一扔就没下文的,Alberl不称之为开源库,只称为开源代码.这里并不是贬低,像Alberl前面那个系 ...
- cocos2dx 3.x 集成protobuf
vs2013+cocos2dx 3.13.1 这篇博文是集成Lua版本的protobuf,集成C++版本的过程也可参考. 主要参考博文地址<cocos2dx 3.x C++搭建protobuf环 ...
- 【转】cocos2dx 3.x 集成protobuf
http://www.cnblogs.com/chevin/p/6001872.html vs2013+cocos2dx 3.13.1 这篇博文是集成Lua版本的protobuf,集成C++版本的过程 ...
- cocos2dx lua binding ,cocos2dx 绑定lua测试
前面2篇分别简单介绍 手动bind C++ 类和lua:http://blog.csdn.net/chenee543216/article/details/12074771 使用tolua++简化工作 ...
- lua luna工具库
luna工具库 概述 luna库提供了几个lua开发的常见辅助功能: lua/c++绑定 lua序列化与反序列化 变长整数编码,用于lua序列化,当然也可以方便的用于其他场合 这里把代码编译成了动态库 ...
随机推荐
- <script type="text/javascript" src="<%=path %>/pages/js/arsis/area.js?v=1.01"></script> 为什么在最后加? v+1.01
不写也可以 是为了js改变以后 ,名字未变 ,如果原来有的浏览器加载 了,遇到相同名字的就是引用缓存,不在从新加载.会出现错误.加上后 会重新加载. css 引用后面也一样.
- 微软MVP衣明志告诉你,小白全方位攻略,逆袭互联网达人
技术专家们的起步之路是不尽相同的,今天我们要介绍的衣明志老师就是一个从普通游戏爱好者修炼成的技术大咖.尽管当时遇到了不少的困难,但是努力坚持自己解决问题让衣明志老师在技术之路上有了自己的特点. 我们先 ...
- 云计算 云服务 hadoop
云:是一种虚拟化的技术,重在资源管理. 云服务是云计算的一种商业模式,有三个层次: Iaas:场外服务器,存储和网络硬件:节省了维护成本和办公场地,公司可以在任何时候利用这些硬件来运行其应用 Paas ...
- C++调用V8与JS交互
C++访问JS函数 C++部分: /** * COMPILE foo.js AT THE FIRST COMMAND PROMPT TO RUN foo.js */ #include <v8.h ...
- mac平台多个php版本快速切换
mac平台多个php版本快速切换 要求所有php版本都是由brew安装 使用brew安装php多版本方法 # brew install php56 # brew install php70 安装切换工 ...
- Photoshop制作的海报修改~
经过几天的征求意见,感觉还是要重新制作,于是把颜色删减了不少 . 这次运用了蒙版和渐变,但感觉效果不太好.再改.. 后来觉得给人的单身感有点少.. 不知道感觉如何,但自己觉得比以前好看..
- mysql用户名密码忘记了解决方法
今天想用一下实验室服务器的mysql,发现不记得用户名密码了. 解决方法如下: 1. 保证服务器处于安全的状态,如果可以请拔掉网线...(不过我跳过了这一步,额) 2. 修改/etc/my.cnf文件 ...
- python-tab还是space?
今天把windows下的python代码传到服务器上,结果莫名其妙的报了一堆indent的错误 网上建议说用: python -m tabnanny filename.py 查一下 然后就用space ...
- Android中下载、安装和卸载(原)
应用场景:在检查版本更新的时候经常需要从服务器端下载然后安装到手机中 使用工具: XUtils,这个开源的框架真的是需要花大把时间去阅读和理解的,十分有用的,on the way ! fighting ...
- iOS--时间类date详解
NSDate定义时间的类 NSDate是一个时间类,在编写程序时,我们很少遇到.今天我突然碰到,感觉很生疏. 给大家发个博客,让大家也都温习一下,哈哈! 兄弟用的时候突然发现竟然有一些bug,大家用时 ...