码迷,mamicode.com
首页 > 编程语言 > 详细

C++跟lua的交互.

时间:2015-07-06 17:31:10      阅读:134      评论:0      收藏:0      [点我收藏+]

标签:

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

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

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

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

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

 

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

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

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

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

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

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

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

 

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

1 typedef struct 
2 {
3     USHORT                MapID;                                //地图ID
4     char                MapName[32];                        //地图名称
5     char                MapDataFile[128];                    //地图数据文件
6 }ScenceMapConfig;

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

 1 lua_newtable(lua);
 2 lua_pushstring(lua, "MapID");
 3 lua_pushinteger(lua, pConfig->MapID);
 4 lua_settable(lua, -3);
 5 lua_pushstring(lua, "MapName");
 6 lua_pushstring(lua, pConfig->MapName);
 7 lua_settable(lua, -3);
 8 lua_pushstring(lua, "MapDataFile");
 9 lua_pushstring(lua, pConfig->MapDataFile);
10 lua_settable(lua, -3);

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

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

1 lutils::luaOpenTable(lua);
2 LUA_PUSHPAIR(pConfig, MapID);
3 LUA_PUSHPAIR(pConfig, MapName);
4 LUA_PUSHPAIR(pConfig, MapDataFile);

效果跟上面一样.

 

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

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

 1 ScenceMapConfig config;
 2 lua_pushstring(lua, "MapID");
 3 lua_gettable(lua, -1);
 4 config.MapID = lua_tointeger(lua, -1);
 5 lua_pop(lua, 1);
 6 
 7 lua_pushstring(lua, "MapName");
 8 lua_gettable(lua, -1);
 9 strcpy(config.MapName, lua_tostring(lua, -1));
10 lua_pop(lua, 1);
11 
12 lua_pushstring(lua, "MapDataFile");
13 lua_gettable(lua, -1);
14 strcpy(config.MapDataFile, lua_tostring(lua, -1));
15 lua_pop(lua, 1);

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

下面看看怎么简化.

1 ScenceMapConfig config;
2 config.MapID = lutils::luaGetValueByTable<int>(lua, "MapID", -1);
3 strcpy(config.MapName, lutils::luaGetValueByTable<std::string>(lua, "MapName", -1).c_str());
4 strcpy(config.MapDataFile, lutils::luaGetValueByTable<std::string>(lua, "MapDataFile", -1).c_str());

干净利落, 相当简洁.

 

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

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

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

1 auto lua = LuaEngine::getInstance()->getLuaStack()->getLuaState();
2 lutils::luaBeginModule(lua);
3 LUA_ADDMODULE(getSceneMapVecType);
4 LUA_ADDMODULE(getCityMapVecType);
5 LUA_ADDMODULE(getBuildingUpgradeConfig);
6 LUA_ADDMODULE(getSiverToCurrentConfig);
7 lutils::luaEndModule(lua, "config");

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

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

比如:

1 config = config or {};
2 
3 function config.func()
4 
5 end

 

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

  1     template <class T>
  2     inline T luaGetValue(lua_State *lua, int idx)
  3     {
  4 #ifdef _MSC_VER
  5         static_assert(0, "");
  6 #else
  7         CC_ASSERT(0);
  8 #endif
  9     }
 10     template <>
 11     inline int luaGetValue(lua_State *lua, int idx)
 12     { return lua_tointeger(lua, idx); }
 13 
 14     template <>
 15     inline short luaGetValue(lua_State *lua, int idx)
 16     { return lua_tointeger(lua, idx); }
 17 
 18     template <>
 19     inline float luaGetValue(lua_State *lua, int idx)
 20     { return lua_tonumber(lua, idx); }
 21 
 22     template <>
 23     inline bool luaGetValue(lua_State *lua, int idx)
 24     { return lua_toboolean(lua, idx) != 0; }
 25 
 26     template <>
 27     inline std::string luaGetValue(lua_State *lua, int idx)
 28     { return SFStringHelper::setUtf8ToGbk(lua_tostring(lua, idx)); }
 29 
 30 //    
 31     template<class T>
 32     inline void luaPushValue(lua_State *lua, const T &value)
 33     {
 34 #ifdef _MSC_VER
 35         static_assert(0, "");
 36 #else
 37         CC_ASSERT(0);
 38 #endif
 39     }
 40     inline void luaPushValue(lua_State *lua, const int &value)
 41     { lua_pushinteger(lua, value); }
 42 
 43     inline void luaPushValue(lua_State *lua, const u_int &value)
 44     { lua_pushinteger(lua, value); }
 45 
 46     inline void luaPushValue(lua_State *lua, const long &value)
 47     { lua_pushinteger(lua, value); }
 48 
 49     inline void luaPushValue(lua_State *lua, const u_long &value)
 50     { lua_pushinteger(lua, value); }
 51 
 52     inline void luaPushValue(lua_State *lua, const short &value)
 53     { lua_pushinteger(lua, value); }
 54 
 55     inline void luaPushValue(lua_State *lua, const u_short &value)
 56     { lua_pushinteger(lua, value); }
 57 
 58     inline void luaPushValue(lua_State *lua, const char &value)
 59     { lua_pushinteger(lua, value); }
 60 
 61     inline void luaPushValue(lua_State *lua, const u_char &value)
 62     { lua_pushinteger(lua, value); }
 63 
 64     inline void luaPushValue(lua_State *lua, const float &value)
 65     { lua_pushnumber(lua, value); }
 66 
 67     inline void luaPushValue(lua_State *lua, const double &value)
 68     { lua_pushnumber(lua, value); }
 69 
 70     inline void luaPushValue(lua_State *lua, const bool &value)
 71     { lua_pushboolean(lua, value); }
 72 
 73     inline void luaPushValue(lua_State *lua, const char *value)
 74     { lua_pushstring(lua, SFStringHelper::setGbkToUtf8(value).c_str()); }
 75 
 76     inline void luaPushValue(lua_State *lua, const std::string &value)
 77     { luaPushValue(lua, value.c_str()); }
 78 
 79     inline void luaPushValue(lua_State *lua, const lua_CFunction call)
 80     { lua_pushcfunction(lua, call); }
 81 
 82     template <class T>
 83     inline void luaOpenTable(lua_State *lua, const T &key)
 84     {
 85         luaPushValue(lua, key);
 86         lua_newtable(lua);
 87     }
 88 
 89     inline void luaOpenTable(lua_State *lua)
 90     { lua_newtable(lua); }
 91 
 92     inline void luaCloseTable(lua_State *lua)
 93     { lua_settable(lua, -3); }
 94 
 95     template<class T1, class T2>
 96     inline void luaPushPair(lua_State *lua, const T1 &key, const T2 &value)
 97     {
 98         luaPushValue(lua, key);
 99         luaPushValue(lua, value);
100         luaCloseTable(lua);
101     }
102 #define LUA_PUSHPAIR(ptr, member) lutils::luaPushPair(lua, #member, (ptr)->member)
103 #define LUA_PUSHARRAY(ptr, member, n) 104     lutils::luaOpenTable(lua, #member); 105     for (auto i = 0; i != n; ++i) 106     { 107         lutils::luaPushPair(lua, i+1, (ptr)->member[i]); 108     } 109     lutils::luaCloseTable(lua);
110 
111 #define LUA_ADDMODULE(member) lutils::luaPushPair(lua, #member, member);
112 
113     //    从lua表获取元素.
114     template <class T1, class T2>
115     T1 luaGetValueByTable(lua_State *lua, const T2 &key, int idx)
116     {
117         luaPushValue(lua, key);
118         lua_gettable(lua, idx);
119         T1 ret = luaGetValue<T1>(lua, -1);
120         lua_pop(lua, 1);
121         return ret;
122     }
123 
124     //    添加模块到lua.
125     inline void luaBeginModule(lua_State *lua)
126     { lua_newtable(lua); }
127 
128     inline void luaEndModule(lua_State *lua, const char *name)
129     { lua_setglobal(lua, name); }

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

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

妈蛋, 用重载的眼光来看特化, .

 

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

 

C++跟lua的交互.

标签:

原文地址:http://www.cnblogs.com/mmc1206x/p/4624785.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!