服务端引擎的脚本, 我们项目在老端游项目上发展, 采取的是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的更多相关文章

  1. cpgf如何实现lua script binding的?

    Lib: https://github.com/cpgf/cpgf/tree/master 代码 以下是operator的实现函数 int UserData_operator(lua_State * ...

  2. Lua与javascript的差异

    Lua与javascript的差异 2010-03-08 Lua模拟器js方案 1.语法级模拟 lua与js语言差异 1.1注释 js 为//,lua为--. 1.2变量 js利用var来声明全局变量 ...

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

    The GUI Toolkit, Framework Page User interfaces occupy an important part of software development. Th ...

  4. C++ 100款开源界面库 (10)

    (声明:Alberl以后说到开源库,一般都是指著名的.或者不著名但维护至少3年以上的.那些把代码一扔就没下文的,Alberl不称之为开源库,只称为开源代码.这里并不是贬低,像Alberl前面那个系列的 ...

  5. 仿迅雷播放器教程 -- C++ 100款开源界面库 (10)

      (声明:Alberl以后说到开源库,一般都是指著名的.或者不著名但维护至少3年以上的.那些把代码一扔就没下文的,Alberl不称之为开源库,只称为开源代码.这里并不是贬低,像Alberl前面那个系 ...

  6. cocos2dx 3.x 集成protobuf

    vs2013+cocos2dx 3.13.1 这篇博文是集成Lua版本的protobuf,集成C++版本的过程也可参考. 主要参考博文地址<cocos2dx 3.x C++搭建protobuf环 ...

  7. 【转】cocos2dx 3.x 集成protobuf

    http://www.cnblogs.com/chevin/p/6001872.html vs2013+cocos2dx 3.13.1 这篇博文是集成Lua版本的protobuf,集成C++版本的过程 ...

  8. cocos2dx lua binding ,cocos2dx 绑定lua测试

    前面2篇分别简单介绍 手动bind C++ 类和lua:http://blog.csdn.net/chenee543216/article/details/12074771 使用tolua++简化工作 ...

  9. lua luna工具库

    luna工具库 概述 luna库提供了几个lua开发的常见辅助功能: lua/c++绑定 lua序列化与反序列化 变长整数编码,用于lua序列化,当然也可以方便的用于其他场合 这里把代码编译成了动态库 ...

随机推荐

  1. C# WebBrowser控件使用教程与技巧收集

    常用的方法 Navigate(string urlString):浏览urlString表示的网址 Navigate(System.Uri url):浏览url表示的网址 Navigate(strin ...

  2. python 中x%2 x&1 判断偶数奇数 性能对比

    本文使用非常好用的python交互解释器ipython操作演示, 使用命令pip install ipython安装,输入ipython即可.比python自带的好用. python中有两种方法判断一 ...

  3. 从C++转向Java的第一课

    序:计算机语言的学习,最快捷的方法是从一种语言映射到另一种语言.Java和C++作为最通用的面相对象高级语言,不论从语法或者编程上都极具相似性和可效仿行,这里的可效仿包括——语法理解可效仿和编程规范可 ...

  4. java EE中使用PO和VO的注意事项

    1.基本定义  PO(Persistence Object 持久化对象)是直接跟持久层数据库打交道的java Bean (model,entity,bean等叫法都是可以的),里面除了私有的成员变量之 ...

  5. Apache Server Status主机状态查看

    10月30日,国外安全研究人员发现由于对apache设置不严,导致服务器状态暴露于公网.本来apache有一个叫server-status 的功能,为方便管理员检查服务器运行状态的.它是一个HTML页 ...

  6. 学习SVG系列(1):SVG基础

    什么是SVG? 1.指可伸缩矢量图形 2.用来定义用于网络的基于矢量的图形 3.使用XML格式定义图形 4.图像在放大或改变尺寸的情况下其图形不会有所损失 5.万维网联盟的标准, 用于描述二维矢量图形 ...

  7. c++ boost (递归)遍历目录

    c++ 终于有办法跨平台访问文件系统了,虽然还是要借助boost.不多说,上代码 /** visitdir.cpp **/#include <iostream> #include < ...

  8. target和currentTarget的区别

    target在事件流的目标阶段:currentTarget在事件流的捕获,目标及冒泡阶段.只有当事件流处在目标阶段的时候,两个的指向才是一样的, 而当处于捕获和冒泡阶段的时候,target指向被单击的 ...

  9. NSOperationQueue的基本使用

    NSOperationQueue的作用 NSOperation可以调用start方法来执行任务,但默认是同步执行的 如果将NSOperation添加到NSOperationQueue(操作队列)中,系 ...

  10. Longest Increasing Path in a Matrix -- LeetCode 329

    Given an integer matrix, find the length of the longest increasing path. From each cell, you can eit ...