最优雅的C++跟lua交互.
我先来吐槽一下我们这个项目.
我是做手机游戏的, 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交互.的更多相关文章
- C++与Lua交互(四)
引言 通过前几篇,我们已经对Lua的C API有了一定的了解,如lua_push*.lua_is*.lua_to*等等.用C++调用Lua数据时,我们主要运用lua_getglobal与lua_pus ...
- C++与Lua交互(一)
引言 之前做手游项目时,客户端用lua做脚本,基本所有游戏逻辑都用它完成,玩起来有点不爽,感觉"太重"了.而我又比较偏服务端这边(仅有C++),所以热情不高.最近,加入了一个端游项 ...
- C++与Lua交互之配置&交互原理&示例
|Lua 简介 Lua 是一种轻量小巧的脚本语言,也是号称性能最高的脚本语言,它用C语言编写并以源代码形式开放. 某些程序常常需要修改内容,而修改的内容不仅仅是数据,更要修改很多函数的行为. 而修改函 ...
- C++与Lua交互(三)
通过上一篇的热身,我们对C++调用lua变量有了一个认识,现在让我们再深入一点,去探索一下如何调用lua的函数.表. Lua与宿主通讯的关键--栈 lua是个动态脚本语言,它的数据类型如何映射到C++ ...
- C++与Lua交互(二)
上一篇我们搭建好了整个的项目环境,现在,我们一起探索一下如何将lua寄宿到C++中. 宿主的实现 我们在LuaWithCPPTest项目下,查看Source.cpp代码如下: #include < ...
- C++与lua交互
项目开发的脚本层用的是Lua,引擎用的是C++.但是经理不给开放引擎层的代码.刚好最近项目空闲,安排了学习C++跟Lua的通信. 一.C++与Lua数据交互 数据交互主要是通过C API来实现 首先, ...
- Linux下C/C++和lua交互-Table
本来这些文章都是在我的个人网站www.zhangyi.studio,目前处在备案状态,暂时访问不了,所以搬到这边. 最近这两天需要弄清楚C++和lua间相互调用和数据传递,废话不多说,直接上过程. ...
- Cocos 2d-X Lua 游戏添加苹果内购(二) OC和Lua交互代码详解
这是第二篇 Cocos 2d-X Lua 游戏添加苹果内购(一) 图文详解准备流程 这是前面的第一篇,详细的说明了怎样添加内购项目以及填写银行信息提交以及沙盒测试员的添加使用以及需要我们注意的东西,结 ...
- 教程二 网页和lua交互修改openwrt
硬件 http://zhan.renren.com/h5/entry/3602888498044209332 GL-iNet 1 首先安装 webserver之lighttpd ,openwrt自带 ...
随机推荐
- 【转】patch命令
原文网址:http://bbs.chinaunix.net/thread-1945698-1-1.html patch给文件1应用补丁文件变成另外一个文件2(需要先用"diff 文件1 文件 ...
- Delphi 6 Web Services初步评估
Delphi 6 Web Services初步评估这是我刚到现在公司的时候(2001年8月份)所作的一份测试报告,现公布出来,希望能对大家有所帮助.因为当时d6刚刚发行,Web Service方面还存 ...
- GPUImage实现过程
GPUImage就是一个函数的类库,用于对图片实现滤镜的效果. 下面是实现一个最简单的GPUImage的程序和讲解: 首先新建一个项目,导入GPUImage类库(导入过程在我的另一个博客里面有写). ...
- MVC 5 第二章 项目结构
通过本章学习,你将了解到一个MVC 5应用程序的项目组成以及项目文件的相关信息,从而更好地架构设计出自己的项目结构. 单从MVC的字面意思我们便能够注意到M-模型, View-视图, Controll ...
- 数据结构学习笔记——stack实现(数组篇)
一 栈:是一种表,限制插入和删除只能在一个位置,也即是表的末端(也是栈的顶)进行. 基本操作:push 和 pop. 二 栈的数组实现: 运用数组来存储元素,和栈操作先关的是theArray(一个数组 ...
- 从Java视角理解CPU缓存(CPU Cache)
从Java视角理解系统结构连载, 关注我的微博(链接)了解最新动态众所周知, CPU是计算机的大脑, 它负责执行程序的指令; 内存负责存数据, 包括程序自身数据. 同样大家都知道, 内存比CPU慢很多 ...
- linux驱动开发之HelloWorld
最近实习,公司项目搞的是平板开发,而我分配的任务是将驱动加载到内核中. 准备工作,必要知识了解:加载有两种方式,一种是动态加载和卸载即模块加载,另一种是直接编译进入内核:Linux内核把驱动程序划分为 ...
- Selenium+Java+TestNG环境配置
1. JDK 2.eclipse+TestNG >TestNG安装. Name:testng Location:http://beust.com/eclipse.如图: 3.seleniu ...
- C语言学习_一个简单程序的解释与C学习方法概括
简单计算器程序示例: # include <stdio.h> //1.头文件 //2.加法函数 int add(int a,int b)//3.函数定义方式 { //4.函数体 retur ...
- uvalive4513
https://vjudge.net/problem/UVALive-4513 终于做出来了......... 各种sb错误,最后对拍出来了,还没改对..................... 快半天 ...