关于protobuf的cocos2d-x lua的集成,参考过网上的一些资料,考虑过用google官方实现,但感觉过于臃肿,且没有直接的lua接口,实际应用需要做的框架级的工作较多,再有就是protoc-gen-lua(https://code.google.com/p/protoc-gen-lua/),这个感觉就比较轻量了,但是还是有需要proto转换lua的前置操作,另外就是据说某些protobuf的使用方式还不被支持,最后发现了云风做的一个实现:pbc(https://github.com/cloudwu/pbc)感觉思路很不错,而且有lua binding,决定尝试下cocos2d-x的集成。
参考百度到的两篇文章:
cocos2d-x 3.1 集成 云风pbc – http://blog.csdn.net/kaitiren/article/details/28865349
在Quick-cocos2d-x中使用云风pbc解析Protocol Buffers – http://www.cnblogs.com/Erainbj/p/3618535.html
发现这些集成方法都是对cocos2d-x框架部分做了修改,可以说是直接从引擎底层进行了整合,而我则希望以上层应用代码的角度进行整合,这样在引擎升级时和其它项目复用时都能方便一些。
首先从最没有问题的平台入手,Mac和iOS,直接在Xcode项目中加入pbc的src和lua binding的pbc-lua.c并且设置好include搜索路径,当然,也可以用pbc源码中的Xcode项目预编译成库文件再引入,我还是倾向于对开源项目进行源代码整合,这样一旦发现问题还可以方便进行调试。然后在lua引擎加载入口脚本之前(默认是AppDelegate.cpp中),也就是
lua_State* lState = engine->getLuaStack()->getLuaState();
之后,加入pbc的lua函数注册:luaopen_protobuf_c(lState)。最后记得把protobuf.lua复制到cocos2d-x可以找到的位置,然后按着示例用.pb测试就可以了。
然后是Win平台,使用VS2013,添加好include还有所有src的引用编译后,遇到了编译不能通过的问题,看了一下错误,发现pbc的.c在VS中不能按C代码编译,而应该按照C++编译,在所有.c的属性页中的“C/C++ => 高级”中,设置“编译为C++代码”后编译通过。
最后是Android平台,按照项目结构和pbc源码的位置设置好mk文件中的src和include后,编译ok,但是运行时却出现了注册.pb文件出错的问题,看了一下pbc的lua代码,发现注册.pb文件是通过lua函数库中的io.open进行文件读取的,而cocos2d-x中的这部分的lua实现并没有重写过,就是直接封装的fopen, fread, fclose等,这样自然无法读取到被打包进Android asset文件夹中的.pb文件了!最开始考虑使用cocos2d-x的FileUtils替换掉pbc-lua中的io.open加载文件,想法就是既不修改cocos2d-x框架层的io.open实现,也不去重写pbc-lua的文件io操作,尽量都在用户应用层解决。看了一下FileUtils的lua导出,发现能够进行文件读取操作的只有一个getStringFromFile可以用,测试了一下发现还是不能正常完成pbc-lua的注册pb操作,断点调试了一下FileUtils的getStringFromFile以及pbc-lua的相关实现代码,发现问题出在文件读取后的数据传递给lua的过程中,由于cocos2d-x直接实现getStringFromFile的lua-binding中,对加载后的const char*进行了lua_pushlstring(L, s, strlen(s))的操作(由tolua的封装间接调用),而就是因为最后的strlen,导致读取.pb二进制文件时,错误的以文件中的0作为字符串结束标记错误的传递了整个二进制文件的长度,最终导致pbc-lua register时的错误。明确问题后解决就好办了,自己注册一个通过FileUtils实现的专门负责io二进制文件的c函数给lua调用:
static int bsReadFile(lua_State *L) { const char *buff = luaL_checkstring(L, -1); Data data = CCFileUtils::getInstance()->getDataFromFile(buff); lua_pushlstring(L, (const char*)data.getBytes(), data.getSize()); return 1; /* number of results */ } ... lua_register(tolua_S, "bsReadFile", bsReadFile);
然后在pbc-lua注册pb时使用自己的io方法:
pb = require "protobuf" local pbFilePath = cc.FileUtils:getInstance():fullPathForFilename("res/addressbook.pb") cclog("PB file path: "..pbFilePath) -- local f = assert(io.open(pbFilePath , "rb")) -- local buffer = f:read "*a" local buffer = bsReadFile(pbFilePath) pb.register(buffer) -- f:close()
这样Android上就可以正常加载asset中的.pb文件了。
最后的最后,还有一个小问题,就是之前提到的VS需要将pbc的.c作为C++代码编译,这样就产生了一个问题:在其他平台上都是c方式编译的生成的符号都是c规范的,而win平台上则是c++规范的符号,用一样的调用代码的话,会导致找链接时找不到符号的问题,这个我的解决方法是分平台编译:
extern #if CC_TARGET_PLATFORM != CC_PLATFORM_WIN32 "C" #endif int luaopen_protobuf_c(lua_State *L);
在win平台上以c++方式引用,其它平台以c方式引用。
博主友情提示:
如您在评论中需要提及如QQ号、电子邮件地址或其他隐私敏感信息,欢迎使用>>博主专用加密工具v3<<处理后发布,原文只有博主可以看到。
最近我再弄这个,一直没弄好,方便给个QQ请教下么
好的,发你新浪微博私信了
我弄了很久一直不成功,方便给个QQ请教下么
ok,我给你微博私信
你好,我也是弄了好久没成功,方便给个qq请教下么
const char *buff = luaL_checkstring(L, -1);4Data data = CCFileUtils::getInstance()->getDataFromFile(buff);5lua_pushlstring(L, (const char*)data.getBytes(), data.getSize());6return 1; /* number of results */这里有内存泄露,需要 data.clear()
你好,请看下CCData.cpp的源码:https://github.com/cocos2d/cocos2d-x/blob/v3/cocos/base/CCData.cpp#L58Data类析构时会执行clear释放内存,data对象在bsReadFile函数执行完后会由此释放内存,不会造成内存泄漏,不放心可以断点跟踪一下试试。
写教程写详细点啊
你好,如果有问题可以贴出来大家一起研究。博文以记录思路为主,仅供参考,谢谢。
你好按照教程继承到win环境了测试的时候报错啊pb.register_file(“res/proto/Service.pb”) local sss = {testid2 = 1,} local stringbuffer = pb.encode(“Service.Mytest”,sss)执行到encode的时候报错错误信息LUA ERROR [../protobuf.lua] 365:textid2
你好按照教程继承到win环境了测试的时候报错pb.register_file(“res/proto/Service.pb”)local sss = {testid2 = 1,}local stringbuffer = pb.encode(“Service.Mytest”,sss)执行到encode的时候报错错误信息LUA ERROR [../protobuf.lua] 365:textid2执行register_file到没错
你好,请问用github上pbc-lua的test.lua和测试用的.pb可以正确执行么?看起来可能是.pb和要encode的table关键字对应不上导致的,先确认一下原生代码部分集成的是否正确。
你好测试了一下是可以的。对比了一下云风的proto文件,我的proto文件第一行没有写package xxx,加上package xxx后,编译成pb文件。再测试就没问题了。
你好 又来打扰你了 我在protobuf.lua里的 register_file 函数里调用CCFileUtils:sharedFileUtils():getFileData。报错说attempt to index global CCFuileUitls
没有require “Cocos2d”?
用require “Cocos2d”报错说attempt to index global ‘require’我的protobuf.lua就放在项目里的script文件夹里
protobuf.lua的位置应该没关系,你是在register_file里require的?其它.lua文件里面调用cocos2d的FileUtils会报错么?
不是在函数里require的。在别的地方调用没有问题的
我在protobuf.lua里调用 任何cocos2d的api 都会说attempt to index global
ok,吧protobuf.lua里的module声明那行改成:module (“protobuf”, package.seeall) 这样试试。
试了一下可以了 。
module的全局访问性问题
module (“protobuf”, package.seeall) 添加了还是会报错attempt to index local ‘protobuf’ (a boolean value)
你好,请问这段你是添加在哪里了?
添加在protobuf.lua下,我把protobuf.lua放在man.lua同级文件夹下,可以了,之前我路径都有写就是不行,谢谢你得回答
客气了!
我这几天一直在搞,还没搞定,方便给给QQ请教下吗,我的是37327927
无法解析的外部符号 _luaopen_protobuf_c,该符号在函数 “void __cdecl quick_module_register(struct lua_State *) 集成编译player3的时候报这个错,请问怎么解决
请检查一下你的pbc源码是否作为c++代码编译了
是的。 具体要怎么解决呢?
那就把quick_module_register函数所在的代码也作为c++编译就行了
请问具体步骤是?刚接触C++,对VS不熟~
右键源码文件->Properties->C/C++->Advanced->Compile As,这里控制源码作为C代码还是C++代码编译,不同编译方式对导出符号以及引用的外部符号命名方式不同,就会导致互相引用时找不到符号的问题。另外你对_luaopen_protobuf_c这个符号是不是做了extern “C”的修饰了?
H文件的声明 extern “C” 了。只是按照你的教程来的。 我所有的文件都是都是Compile As C++了
那就去掉extern “C”,这样所有源文件生成的符号都是按C++形式命名的,但是引用pbc时却按C命名方式引用的,所以链接时会找不到符号
还是不行
提示什么错误?
无法解析的外部符号 _luaopen_protobuf_c,该符号在函数 “void __cdecl quick_module_register(struct lua_State *)
那这还是没有去掉extern “C”的效果,这是C方式的符号命名
hi,博主你好。我最近也在整合这个,编译没有问题,在Android平台,调试时发现都是在require “protobuf”时提示无法找到模块。。
你好,请确认一下云风的pbc lua binding的luaopen_protobuf_c是否正确执行了库函数注册
你好,想问下你的测试案例是怎么写的?能发我一份吗 qq 2441774570
你好,现在没有只包含这部分功能的示例项目。如果按我的方法集成时遇到问题可以回复我会尽量帮助解决。
想请教下你 方便加个QQ么279559878
你好,请问遇到什么问题了?
我是在xcode下面 编译的时候 提示找不到protobuf.c 这个文件
protobuf.lua这个文件里面 有个 required“protobuf.c” 提示找不到这个模块 求大神帮忙看下 呵呵
这个问题是pbc lua-binding的pbc-lua.c中luaopen_protobuf_c没有成功执行,也就是没注册成功lua库导致的
你加下 小弟的 QQ吧 279559878
哦哦 那要如何解决
“然后在lua引擎加载入口脚本之前(默认是AppDelegate.cpp中),也就是lua_State* lState = engine->getLuaStack()->getLuaState();之后,加入pbc的lua函数注册:luaopen_protobuf_c(lState)。最后记得把protobuf.lua复制到cocos2d-x可以找到的位置,然后按着示例用.pb测试就可以了。”按我上面写的这样就可以,抱歉我现在不方便用QQ…
我就是按照这个方法做的, “把protobuf.lua复制到cocos2d-x可以找到的位置”这一句怎么理解?
这个protobuf.lua是给”local pb = require “protobuf””这个用的,既然能到 required“protobuf.c”,那这个protobuf.lua应该没问题..确认一下luaopen_protobuf_c是不是正确执行了吧
兄弟 ,在不在?
嗯,请问有什么问题?
protobuf ,怎么集成 socket啊 我集成好了,socket这边你有案例么
可以看下luasocket,cocos2d-x新版本都内置了的
好的
搞了2天了都没搞定。求发我一份源码!qq2300563522
不好意思,目前没有完整项目源码可以发,这里只是记录了实现思路,如果有什么问题的话可以提出来,我会尽量帮助解决。
“最后是Android平台,按照项目结构和pbc源码的位置设置好mk文件中的src和include后,编译ok”请问一下,这里需要修改哪些mk呢?如何修改呢?我尝试了半天,在编译pbc-lua.c的时候说找不到lua.h,请问这个怎么解决?我用的是3.3版本
你好,这个问题是include路径中没有添加pbc源码路径导致的:LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes $(LOCAL_PATH)/../../Classes/manual $(LOCAL_PATH)/../../Classes/auto $(LOCAL_PATH)/../../../pbc $(LOCAL_PATH)/../../../cocos2d-x/external $(LOCAL_PATH)/../../../cocos2d-x/tools/simulator/libsimulator/lib $(LOCAL_PATH)/../../../cocos2d-x/tools/simulator/libsimulator/lib/protobuf-lite
非常感谢,已经搞定了
客气了
你好,win32下面运行起来了,也出现了和你一样的问题,asset无法读取pb文件,但是按照你的方法注册函数之后lua无法调用到,显示a nil value
你好,请问是win32没问题,Android下无法读取asset中的pb么?是的话那请检查一下lua全局函数的注册代码是否都正常执行了(断点运行跟踪确认下)。
问题已解决,我在protobuf.lua里面调用2dx注册的函数无法使用,在其他lua文件里使用是ok的,不知道是什么原因,个人猜测protobuf.lua和其他lua文件不在同一个栈里?
理论上不会,我写的注册函数的方式并没有用到cocos2d-x的东西,只是最基本的lua c api的注册全局c函数。请问具体是如何在protobuf.lua里添加的bsReadFile函数调用?
function register_file(filename) local f = assert(io.open(filename , “rb”)) local buffer = f:read “*a” — local buffer = readProtobufFile(filename) –不能在这里用 c._env_register(P, buffer) f:close()end
local function registerProto(path) local buf = readProtobufFile(path) protobuf.register(buf) end registerProto(cc.FileUtils:getInstance():fullPathForFilename(“res/pb/person.pb”))在protobuf.lua之外的文件调用是没有问题,后来想了一下应该是加载顺序的问题,注册pbc的时候已经把这个文件加载进来了,2dx自定义的c++函数是在之后的,所以会出现找不到的情况
对。我测试的时候lua加载pb代码肯定是在c++部分注册过函数之后执行的。
请问proto嵌套,怎么解决,网上查了资料,add()总是报错require (“src.app.Base_pb”)require (“src.app.Player_pb”)local playerMsg = Player_pb.PlayerMsg()local baseMsg = playerMsg.msglocal base1 = baseMsg:add()请教怎么解决~,恳请帮助
你好,请问是pbc lua对proto嵌套的支持么?是的话,这方面我也没有测试过,有问题还是去咨询下pbc的作者云风大大吧。
路过看一下!
很好的网站,赞一个,加油!
.pb文件是怎么生成的,我pbc项目里面找不到啊
你好,.pb是用protoc编译.proto文件生成的,protoc可以直接现在编译好的,或者用protobuf源代码自己编译
不错哦,赞一个。求认识,求回访
不错哦,赞一个。求认识,求回访
博主加我下QQ,332676906吧,我现在在window上介入pbc不知道有问题,谢谢了
已加
按照你的文章进行了protobuf整合
我是在windows平台下编译的,已经报pbc-lua.c和pbc.h里面的extern C注释掉了 并将工程已C++形式编译,编译是没有错
但是在阵型过程中报错了
错误内容大体如下
> btxy.exe!luaS_newlstr(lua_State * L, const char * str, unsigned int l) 行 82 C++
btxy.exe!lua_pushlstring(lua_State * L, const char * s, unsigned int len) 行 448 C++
btxy.exe!luaL_findtable(lua_State * L, int idx, const char * fname, int szhint) 行 364 C++
btxy.exe!luaL_openlib(lua_State * L, const char * libname, const luaL_Reg * l, int nup) 行 247 C++
btxy.exe!luaL_register(lua_State * L, const char * libname, const luaL_Reg * l) 行 231 C++
btxy.exe!luaopen_protobuf_c(lua_State * L) 行 1079 C++
btxy.exe!luaopen_lua_game_extensions(lua_State * L) 行 10 C++
btxy.exe!AppDelegate::applicationDidFinishLaunching() 行 59 C++
如果方便的话 能否加下QQ280632307
你好,看调用栈是pbc在注册lua函数库时异常了,请问具体报的是什么异常?
你好,我的编译环境是win7 64位 vs2012
我是根据你的文章处理的 我pbc的所有.c文件都右键-》属性-》C++-》高级-》编译为 C++ 代码 (/TP)
并将pbc-lua.c pbc.h pbc-lua.h 中的extern “C” {和对应的}注释掉了
并使用统一的加载函数进行加载
#include “GameExtensions.h”
#include “pbc-lua.h”
TOLUA_API void luaopen_lua_game_extensions(lua_State *L){
luaopen_protobuf_c(L);
}
能编译成功,但在启动游戏的是有就会报之前说的问题,不知道你那里有没有win7相关的用例可供参考
重新找了个Pbc,编译并测试通过了
[赞]
弄过Ulua里面集成pbc吗?
你好,没有
那抛开Cocos,在随便一个C#工程里面集成pbc,和你这个过程一样吗?
这个我就不清楚了,要是C/C++的话是差不多的
你好,请问你还有现在这个项目的Android.mk文件吗,能全部黏贴出来吗,我一直配置不成功
你好,现在手头没有,请问是遇到什么问题了?
你好,我想问下,是要修改那个Android.mk文件,是只需要修改runtime-src/proj.android这个文件里面的mk文件吗
是,加入pbc相关源码编译就行了
是将pbc里面的src的.c文件都加进去吗
是,src里的和binding里的pbc-lua.c
好的,我试试看
你好,编译通过了,但是运行apk后会报错。
can not get file data of /usr/local/lib/lua/5.1/?/init.luaprotobuf/c.lua
[LUA ERROR] [string "able/net/protobuf/protobuf.lua"]:1: module ‘protobuf.c’ not found:
luaopen_protobuf_c调用成功了么?看报错信息是没向lua虚拟机注册pbc的lua模块
额,android的要加在哪个位置呢
然后在lua引擎加载入口脚本之前(默认是AppDelegate.cpp中),也就是
lua_State* lState = engine->getLuaStack()->getLuaState();
之后,加入pbc的lua函数注册:luaopen_protobuf_c(lState)。
AppDelegate.cpp是xcode的吧,我android的是AppActivity.java
AppDelegate.cpp是Cocos2d-X的
额,看到了,luaopen_protobuf_c,加进去后编译提示这方法没定义,还要做什么处理吗
没定义还是没声明?没声明要不自己写个.h吧pbc-lua.c里这个函数的原型写进去,要不就加个extern声明一下这个函数,没定义是pbc-lua.c没参加编译或者编译方式和你的声明不一致,比如是作为c代码编译就要加extern "c"声明
编译是编译了,但是好像要include这个luaopen_protobuf_c函数的.h文件,是哪一个
恩,我直接在里面#include "pbc-lua.h"就可以了
无语,弄完了这个问题,又出现.pb文件找不到的问题。。。。
没有,云风的源码只有.c中的实现,函数声明可以自己补全.h或者直接以extern "C"的方式声明在你调用代码的源码文件里,看我写的最后那部分
我想请问下,你的加载.pb的那些修改,是在哪个文件上修改,没看出来
bsReadFile写在哪都可以只要跟注册pbc-lua一样用lua_register注册给脚本就可以了
都是在AppDelegate.cpp文件加吗
嗯,可以
pb = require "protobuf"
2
local pbFilePath = cc.FileUtils:getInstance():fullPathForFilename("res/addressbook.pb")
3
cclog("PB file path: "..pbFilePath)
4
— local f = assert(io.open(pbFilePath , "rb"))
5
— local buffer = f:read "*a"
6
local buffer = bsReadFile(pbFilePath)
7
pb.register(buffer)
8
— f:close()
这段代码写在哪里
这段是lua脚本代码,写在你要加载注册.pb协议文件的地方
bsReadFile这个函数编译的时候提示很多没声明。。。
Cocos2d-X相关的头文件都include了么?这个函数里用了Cocos2d-X的文件操作CFileUtils了
CCFileUtils::getInstance()->getDataFromFile(buff);
这个是CCFileUtils::getInstance()->getDataFromFile(buff);才对。。
嗯,这个博客有html转码,自己改一下就是了
tolua_S这个值应该是L才对吧
你看下lua_register参数类型,根据你自己的代码逻辑相同类型的变量名填就行了,这个不能照抄啊
bsReadFile为什么我在lua里面log这个的返回值有部分是乱码
你好,我已经解决好了,没问题了,谢谢了
lua_register(tolua_S, "bsReadFile", bsReadFile);
这个是什么来的,tolua_S这个变量好像都没有
我在protobuf.lua文件里面用bsReadFile函数会说是一个空的值