标签:
我先来吐槽一下我们这个项目.
我是做手机游戏的, 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<>,
后来被一个同事误以为, 那是多余的一样代码, 把它删除了...
妈蛋, 用重载的眼光来看特化, 战 五 渣 .
好了, 全部代码上完, 坐等下班~~
标签:
原文地址:http://www.cnblogs.com/mmc1206x/p/4624785.html