我先来吐槽一下我们这个项目.

我是做手机游戏的, cocos2dx引擎, lua编码.

这本来是一件很欢快的事情, 因为不用接触C++.

C++写久了的人写lua, 就会感觉任督二脉被打通了, 代码写起来都不用太多考虑,

就像涉世太深的人吹起牛逼肆无忌惮, 总是可以自圆其说.

然而, 事与愿违, 我们客户端的兄弟仍然要编写大量C++代码,

其原因是, 配置文件, 数据结构统统由后端决定,

而后端没有人会lua, 因此数据全部放在C++,

客户端每一次存取数据都会接触到C++.

然后, 就出现了今天的这篇随笔.

主要是解决了, lua和C++交互的问题.

当然tolua可以解决这些问题, 但是相比之下, 太麻烦, 因为C++那一块太庞大, 我并不需要整个都导入lua.

先来看看, 最原始的代码.

 typedef struct
 {
     USHORT                MapID;                                //地图ID
     ];                        //地图名称
     ];                    //地图数据文件
 }ScenceMapConfig;

我从在lua中取C++里的这么一个结构.

 lua_newtable(lua);
 lua_pushstring(lua, "MapID");
 lua_pushinteger(lua, pConfig->MapID);
 lua_settable(lua, -);
 lua_pushstring(lua, "MapName");
 lua_pushstring(lua, pConfig->MapName);
 lua_settable(lua, -);
 lua_pushstring(lua, "MapDataFile");
 lua_pushstring(lua, pConfig->MapDataFile);
 lua_settable(lua, -);

这里假设, pConfig 是指向这个结构的指针.

取了三个字段, 写了这么多代码, 重复的还有好几行.

 lutils::luaOpenTable(lua);
 LUA_PUSHPAIR(pConfig, MapID);
 LUA_PUSHPAIR(pConfig, MapName);
 LUA_PUSHPAIR(pConfig, MapDataFile);

效果跟上面一样.

上面说的是从lua取C++的值.

下面说从lua传值到C++.

 ScenceMapConfig config;
 lua_pushstring(lua, "MapID");
 lua_gettable(lua, -);
 config.MapID = lua_tointeger(lua, -);
 lua_pop(lua, );

 lua_pushstring(lua, "MapName");
 lua_gettable(lua, -);
 strcpy(config.MapName, lua_tostring(lua, -));
 lua_pop(lua, );

 lua_pushstring(lua, "MapDataFile");
 lua_gettable(lua, -);
 strcpy(config.MapDataFile, lua_tostring(lua, -));
 lua_pop(lua, );

这里也是取了三个字段, 弊端跟上面一样.

下面看看怎么简化.

 ScenceMapConfig config;
 config.MapID = lutils::luaGetValueByTable<);
 strcpy(config.MapName, lutils::luaGetValueByTable<std::).c_str());
 strcpy(config.MapDataFile, lutils::luaGetValueByTable<std::).c_str());

干净利落, 相当简洁.

接下来是手动注册C++函数到lua.

如果直接注册全局函数, 命名污染太严重.

可以把函数按模块来划分.

 auto lua = LuaEngine::getInstance()->getLuaStack()->getLuaState();
 lutils::luaBeginModule(lua);
 LUA_ADDMODULE(getSceneMapVecType);
 LUA_ADDMODULE(getCityMapVecType);
 LUA_ADDMODULE(getBuildingUpgradeConfig);
 LUA_ADDMODULE(getSiverToCurrentConfig);
 lutils::luaEndModule(lua, "config");

在lua里就可以直接用 config.* 来调用这些函数了.

并且, 这个 config 可以在lua里扩展.

比如:

 config = config or {};

 function config.func()

 end

接下来, 睁大你们的双眼, 我要出王炸了.

     template <class T>
     inline T luaGetValue(lua_State *lua, int idx)
     {
 #ifdef _MSC_VER
         static_assert(, "");
 #else
         CC_ASSERT();
 #endif
     }
     template <>
     inline int luaGetValue(lua_State *lua, int idx)
     { return lua_tointeger(lua, idx); }

     template <>
     inline short luaGetValue(lua_State *lua, int idx)
     { return lua_tointeger(lua, idx); }

     template <>
     inline float luaGetValue(lua_State *lua, int idx)
     { return lua_tonumber(lua, idx); }

     template <>
     inline bool luaGetValue(lua_State *lua, int idx)
     { ; }

     template <>
     inline std::string luaGetValue(lua_State *lua, int idx)
     { return SFStringHelper::setUtf8ToGbk(lua_tostring(lua, idx)); }

 //
     template<class T>
     inline void luaPushValue(lua_State *lua, const T &value)
     {
 #ifdef _MSC_VER
         static_assert(, "");
 #else
         CC_ASSERT();
 #endif
     }
     inline void luaPushValue(lua_State *lua, const int &value)
     { lua_pushinteger(lua, value); }

     inline void luaPushValue(lua_State *lua, const u_int &value)
     { lua_pushinteger(lua, value); }

     inline void luaPushValue(lua_State *lua, const long &value)
     { lua_pushinteger(lua, value); }

     inline void luaPushValue(lua_State *lua, const u_long &value)
     { lua_pushinteger(lua, value); }

     inline void luaPushValue(lua_State *lua, const short &value)
     { lua_pushinteger(lua, value); }

     inline void luaPushValue(lua_State *lua, const u_short &value)
     { lua_pushinteger(lua, value); }

     inline void luaPushValue(lua_State *lua, const char &value)
     { lua_pushinteger(lua, value); }

     inline void luaPushValue(lua_State *lua, const u_char &value)
     { lua_pushinteger(lua, value); }

     inline void luaPushValue(lua_State *lua, const float &value)
     { lua_pushnumber(lua, value); }

     inline void luaPushValue(lua_State *lua, const double &value)
     { lua_pushnumber(lua, value); }

     inline void luaPushValue(lua_State *lua, const bool &value)
     { lua_pushboolean(lua, value); }

     inline void luaPushValue(lua_State *lua, const char *value)
     { lua_pushstring(lua, SFStringHelper::setGbkToUtf8(value).c_str()); }

     inline void luaPushValue(lua_State *lua, const std::string &value)
     { luaPushValue(lua, value.c_str()); }

     inline void luaPushValue(lua_State *lua, const lua_CFunction call)
     { lua_pushcfunction(lua, call); }

     template <class T>
     inline void luaOpenTable(lua_State *lua, const T &key)
     {
         luaPushValue(lua, key);
         lua_newtable(lua);
     }

     inline void luaOpenTable(lua_State *lua)
     { lua_newtable(lua); }

     inline void luaCloseTable(lua_State *lua)
     { lua_settable(lua, -); }

     template<class T1, class T2>
     inline void luaPushPair(lua_State *lua, const T1 &key, const T2 &value)
     {
         luaPushValue(lua, key);
         luaPushValue(lua, value);
         luaCloseTable(lua);
     }
 #define LUA_PUSHPAIR(ptr, member) lutils::luaPushPair(lua, #member, (ptr)->member)
 #define LUA_PUSHARRAY(ptr, member, n) \
     lutils::luaOpenTable(lua, #member); \
     ; i != n; ++i) \
     { \
         lutils::luaPushPair(lua, i+, (ptr)->member[i]); \
     } \
     lutils::luaCloseTable(lua);

 #define LUA_ADDMODULE(member) lutils::luaPushPair(lua, #member, member);

     //    从lua表获取元素.
     template <class T1, class T2>
     T1 luaGetValueByTable(lua_State *lua, const T2 &key, int idx)
     {
         luaPushValue(lua, key);
         lua_gettable(lua, idx);
         T1 ret = luaGetValue<T1>(lua, -);
         lua_pop(lua, );
         return ret;
     }

     //    添加模块到lua.
     inline void luaBeginModule(lua_State *lua)
     { lua_newtable(lua); }

     inline void luaEndModule(lua_State *lua, const char *name)
     { lua_setglobal(lua, name); }

其实, 在所有的 luaPushPair 上面都有一行 template<>,

后来被一个同事误以为是多余的一行代码, 把它删除了...

把特化当作重载, 我也是醉了. 战 五 渣 .

好了, 全部代码上完, 坐等下班~~

最优雅的C++跟lua交互.的更多相关文章

  1. C++与Lua交互(四)

    引言 通过前几篇,我们已经对Lua的C API有了一定的了解,如lua_push*.lua_is*.lua_to*等等.用C++调用Lua数据时,我们主要运用lua_getglobal与lua_pus ...

  2. C++与Lua交互(一)

    引言 之前做手游项目时,客户端用lua做脚本,基本所有游戏逻辑都用它完成,玩起来有点不爽,感觉"太重"了.而我又比较偏服务端这边(仅有C++),所以热情不高.最近,加入了一个端游项 ...

  3. C++与Lua交互之配置&交互原理&示例

    |Lua 简介 Lua 是一种轻量小巧的脚本语言,也是号称性能最高的脚本语言,它用C语言编写并以源代码形式开放. 某些程序常常需要修改内容,而修改的内容不仅仅是数据,更要修改很多函数的行为. 而修改函 ...

  4. C++与Lua交互(三)

    通过上一篇的热身,我们对C++调用lua变量有了一个认识,现在让我们再深入一点,去探索一下如何调用lua的函数.表. Lua与宿主通讯的关键--栈 lua是个动态脚本语言,它的数据类型如何映射到C++ ...

  5. C++与Lua交互(二)

    上一篇我们搭建好了整个的项目环境,现在,我们一起探索一下如何将lua寄宿到C++中. 宿主的实现 我们在LuaWithCPPTest项目下,查看Source.cpp代码如下: #include < ...

  6. C++与lua交互

    项目开发的脚本层用的是Lua,引擎用的是C++.但是经理不给开放引擎层的代码.刚好最近项目空闲,安排了学习C++跟Lua的通信. 一.C++与Lua数据交互 数据交互主要是通过C API来实现 首先, ...

  7. Linux下C/C++和lua交互-Table

    本来这些文章都是在我的个人网站www.zhangyi.studio,目前处在备案状态,暂时访问不了,所以搬到这边.  最近这两天需要弄清楚C++和lua间相互调用和数据传递,废话不多说,直接上过程. ...

  8. Cocos 2d-X Lua 游戏添加苹果内购(二) OC和Lua交互代码详解

    这是第二篇 Cocos 2d-X Lua 游戏添加苹果内购(一) 图文详解准备流程 这是前面的第一篇,详细的说明了怎样添加内购项目以及填写银行信息提交以及沙盒测试员的添加使用以及需要我们注意的东西,结 ...

  9. 教程二 网页和lua交互修改openwrt

    硬件 http://zhan.renren.com/h5/entry/3602888498044209332 GL-iNet 1 首先安装 webserver之lighttpd  ,openwrt自带 ...

随机推荐

  1. Apache Hadoop RPC Authentication 安全绕过漏洞

    漏洞名称: Apache Hadoop RPC Authentication 安全绕过漏洞 CNNVD编号: CNNVD-201308-425 发布时间: 2013-08-28 更新时间: 2013- ...

  2. 在ASP.NET MVC中对手机号码的验证

    在ASP.NET MVC中,可以使用RegularExpression特性来验证手机号码. public class Customer { [Required(ErrorMessage = " ...

  3. HDOJ 1995 汉诺塔V

    Problem Description 用1,2,-,n表示n个盘子,称为1号盘,2号盘,-.号数大盘子就大.经典的汉诺塔问 题经常作为一个递归的经典例题存在.可能有人并不知道汉诺塔问题的典故.汉诺塔 ...

  4. 《Numerical Methods》-chaper4-一元非线性方程的解

    在许多生产时间问题中,我们根据已知条件往往会列出一个一元非线性方程,一个最典型的例子就是银行存款的问题,由于其利息需要基于前一年的本息和,因此列出来的方程x的指数往往是高次的.还有物理问题当中一系列用 ...

  5. GitHub上整理的一些资料(转)

    技术站点 Hacker News:非常棒的针对编程的链接聚合网站 Programming reddit:同上 MSDN:微软相关的官方技术集中地,主要是文档类 infoq:企业级应用,关注软件开发领域 ...

  6. InfoSphere BigInsights 安装部署

    InfoSphere BigInsights 有三个版本:基础版.企业体验版.企业版.基础版是免费的,但是少了一些功能:企业体验版是在购买企业版之前又来体验测试的:如果要部署企业版,应该购买企业版.安 ...

  7. Linq to sql语法

    LINQ to SQL语句(1)之Where Where操作 适用场景:实现过滤,查询等功能. 说明:与SQL命令中的Where作用相似,都是起到范围限定也就是过滤作用的,而判断条件就是它后面所接的子 ...

  8. Python 函数的参数知识汇总

    函数搞不熟,后边就晕头转向了,在此重新归纳一下廖大神的函数教程,加深记忆 一.函数的参数分为: 位置参数 def power(x): # x 就是power(x)的一个位置参数,我们调用power(x ...

  9. docker 实战---部署tomcat\weblogic集群 (二)

    安装tomcat镜像 准备好须要的jdk tomcat等软件放到home文件夹以下 启动一个虚拟机 docker run -t -i -v /home:/opt/data  --name mk_tom ...

  10. [每日一题] 11gOCP 1z0-052 :2013-09-1 RMAN-- repair failure........................................A20

    转载请注明出处:http://blog.csdn.net/guoyjoe/article/details/10859315 正确答案:D 一.模拟上题的错误: 1.删除4号文件 [oracle@myd ...