[前言]

关于如何使用生成proto的exe工具, 参考我的另一篇文章:

https://blog.csdn.net/liuyongjie1992/article/details/115185967

我发现生成lua版本的proto和生成C#版的调用方式不太一样,因此开一片文章记录一下

新建一个bat文件执行这一句话即可调用lua的生成工具

.\protoclient.exe --proto_path=./proto --lua_out=./genpath ./proto/TestProto.proto 

.\protoclient.exe是调用当前目录的protoclient.exe文件

--proto_path=./proto是proto的文件夹,请注意是文件夹路径

--lua_out=./genpath 输出后的proto路径

./proto/TestProto.proto找到我们要输入的proto

上述操作不出意外可以顺利生成TestProto_pb.lua文件

很显然lua和C#的exe输入的语句是不一样的

C#版本的执行语句为

 .\protogen.exe -i:xxx.proto -o:.\genpath\xxx.cs

[Lua版本的pb使用方法]

以上文的TestMessage.proto为例

生成的lua版pb长这样子

下面这句话是业务代码如何使用Message,项目里各种UI需要向服务器请求数据展示自己的内容,TestProto_pb.TestMessage()就是消息体,表示你想请求哪个内容。

--这是一个lua函数
function HowUseProtoMessage()--提示:在使用TestProto_pb之前别忘了require,下文会介绍如何在项目中批处理多个requirelocal msg = TestProto_pb.TestMessage()msg.id = 1;msg.name = "测试message"--!!!这句话很关键,把一个message序列化成stringlocal NetString = msg:SerializeToString();--如果你想把这个msg发给服务器,那么就把这个string发过去NetMgr.SendMsg(NetString)
end

下面开始进阶版 lua pb的使用

项目中我们通常会给Proto里面的mssage加上id,这样前后端通信的时候就知道你传的到底是个毛线,从而方便分发,添加id的方式有两种。提示!!!:无论protoid是3个数的组合还是1个数,这个protoid都是批处理工具按照一定规则生成出来的枚举,不要手动去添加这个id。

我们给proto加上一个枚举用来做标识,第一种方式是mrid,groupid,unitid三个数的组合,第二种是protoid一个数的。

前后端在通信的时候可以从包头中提取出 第一种或者第二种 id从而得出该数据包要用哪个message解析。

【项目启动时注册消息回调】

下面的Reg函数是在项目启动时调用,所有业务都要根据protoid记录消息体、回调函数、错误处理函数。

--[[注册消息处理函数
proto           消息类,示例Module_XXX_pb.XX
handler         处理函数
errorHandler    错误处理函数(错误码不为0时会调用)
--]]
function Reg(proto, handler, errorHandler)local mid = proto.protoid  -- proto.MRID; if mMsgCallBacks[mid] thenlocal callBack = mMsgCallBacks[mid];local callBackMeta = getmetatable(callBack.proto());local newCallBackMeta = getmetatable(proto());GameLog.LogModuleError("msg handler repeat %s %s %d", callBackMeta._descriptor.name, newCallBackMeta._descriptor.name, mid);elselocal callBack = {};callBack.proto = proto;callBack.handler = handler;callBack.errorHandler = errorHandler;mMsgCallBacks[mid] = callBack;end
end

可以在项目启动时,调用一个统一的lua文件把所有业务的回调全部注册。

--所有需要接受服务器通讯的协议都要注册哦,下面这个注册只是举个例子GameNet.Reg(Module_Item_pb.SCItemGetDataRe, ItemMgr.OnGetItemData)

上面注册完了协议回调,那么客户端就等待服务器数据啦。

下面的代码就是收到服务器数据后,C#层把数据传递给lua,请注意,lua不支持byte[]数组,因此数据流会被转化成LuaByte,最终就是个string。

--参数解释:--参数1:protoid是我们自定义的id--参数2:data是C#层接收到的byte[]数组转换成的string
function OnRecvMsg(protoid, data)if mMsgCallBacks[protoid] thenlocal callBack = mMsgCallBacks[protoid]; -- mMsgCallBacks是什么在上文注册中已讲明local msg = callBack.proto();--proto()拿到消息体,此时msg是个空消息体if msg == nil thenGameLog.LogModuleError(NetModule.LOG_TAG,"Failed to OnRecvMsg, cannot find proto for protoid= %d",protoid);endlocal flag, errorMsg = xpcall(msg.ParseFromString, traceback, msg, data);--调用了ParseFromString后,上文的msg不再是空消息体啦,服务器数据已经序列化进去了if flag then--没有错误if callBack.handler then--xpcall调用回调函数,并把消息体当做参数传入该函数,该msg就是服务发过来的messagelocal flag, errorMsg = xpcall(callBack.handler, traceback, msg);if not flag thenOnRecvFail(tid, errorMsg, msg);endelseOnRecvFail(tid, "handler is nil", msg);endendend
end

下面是UI业务层随便一个小例子

-- 下面是UI层业务接受proto消息体的回调函数,msg就是proto里的message
function OnGetItemData(msg)local id = msg.idlocal name = msg.name--数据拿到,下面开始刷UI啦
end

本篇文章到此,lua版pb的使用教程已经完成啦。但是!!!还没有说明protoid的生成规则以及pb文件的批处理require

[protoid]批处理生成

protoid的枚举值不要自己生成,这个前文有提到过

先给大家展示一下我们项目的proto,这么多proto如果要手动添加一个唯一的id显然是不可能的。

[生成protoid的本质]

朋友们!生成protoid的本质是什么,其实就是在message里加一个枚举,这样的好处是,当我们拿到这个消息体时,直接通过 TestMessage.protoid就可以拿到这个枚举值。建议大家再回到上面的文章看一下消息回调注册的地方,加深理解。

如何在原有proto的基础上,加上一个枚举?这就很简单啦,直接用批处理工具写入这句话就好

下面就开始介绍如何批处理写入枚举值,我个人首选python写批处理,真的好用,python工程怎么创建以及环境部署看我的另一篇文章:

https://blog.csdn.net/liuyongjie1992/article/details/112378661

顺便安利一下这个系列的文章,Python版本的打表工具

下面开始讲生成protoid的核心思路:

1:哪些message不需要生成protoid?经常用proto的人都应该知道,很多被引用的message是用来做数据包体,而不是消息包体,我们批处理工具里自己定义了一些头标识,当这个message名前两个字母带着两个大写字母且匹配,那么就给改message生成protoid

msgtype = {'CS':1,'SC':1,'SS':1,'SD':1,'DS':1,'CF':1,'FC':1,'SF':1,'FF':1,'RR':1,'RC':1,'CO':1,'SO':1,'FO':1,'OO':1,'WS':1,'TS':1,'TT':1,'ST':1,'SW':1,'CT':1,'WC':1,'OC':1,'OS':1,'FS':1,'TF':1,'WF':1,'FT':1,'CW':1,'TC':1,
}

这是我们项目中的战斗proto为例,可以看到该message是以SC开头的,那么该message就要生成protoid,而该message内的CampData是一个引用数据体,CampData没有以我们定义的message头开始,那么该message就不会生成protoid

//[返回][游戏服]进入战斗结果
message SCEnterBattle
{optional int64 battleId = 1;repeated CampData camps = 2;                // 战斗阵营数据 (仅站位和card_sid)optional int32 totalChapterNum = 3;         // 回目数量optional int32 battleSid = 4;               // 战役配置idrepeated FightPlayerInfo playerInfo = 5; optional int32 result = 6;                  // 结果 0:成功 其他:返回对应错误码optional int32 isReady = 7;                 // 0没准备 1已准备 (用于战前断线重连)optional int32 isFixedArray = 8;          // 是否固定阵容0不是 1是optional int64 bettleBeginTime = 9;         // 0 不限制, > 0 战斗开始时间
}//阵营数据
message CampData
{ optional int32 id = 1;                     //阵营idoptional int32 campType = 2;               //阵营类型   0:玩家  1:怪物  2:裁判optional int32 energyType = 3;             //鬼火类型    0:阵营   1:单体optional int32 energyValue = 4;            //鬼火当前值(阵营鬼火)optional int32 energyProgressValue = 5;    //鬼火进度当前值optional int32 energyRound = 6;               //第几次恢复鬼火repeated UnitData units = 7;              //战斗站位数据repeated UnitData cardpool = 8;            //卡池中数据optional int32 speed  = 9;                  //阵营速度
}

2:在python工程中遍历所有proto(1步骤被引用的除外),遍历每一个proto的每一行,每检测到一个message消息体,就给消息体添加一个枚举,并且protoid+1向上累积。举个例子,假设这个proto里有10个message,那么该协议内的protoid就是1-10,当遍历到下一个proto时,该proto的message内生成的枚举值就要从11开始啦。这样想是不是非常的简单。遍历到最后,每一个message都有一个唯一的protoid啦

3:步骤2的实现方法可以,但非常愚蠢,因为开发者不希望每一次都把所有proto都生成一遍,因为我正在开发一个UI功能,我只修改这一个proto,却导致我需要把所有proto的protoid都生成一遍,因此有一个简单的解决办法,就是给每个proto定义一个段位

def gengid(modulename):gids = {"Module_AiPet.proto" : 1,"Module_Bag.proto" : 2,"Module_Buff.proto" : 3,"Module_Chat.proto" : 4,"Module_Coin.proto" : 5,"Module_DaySign.proto" : 6,"Module_Faction.proto" : 7,"Module_Friend.proto" : 8,"Module_Gem.proto" : 9,}

注意:每创建一个proto的时候就要手动添加一个段,这样我们生成protoid的时候就不会扰动其他的proto里的protoid,python文件定义的段作为千位,如果是第100个proto,那么它的段位就是100000+ ***后面的个十百位可以让你的proto内定义999个消息体,很显然已经够用了。举个例子:假设是第100个proto里的第65个消息体,那么该message的protoid就是100065。到此为止,protoid的生成教程就完成啦。

[protoid]lua批处理require

批量处理require和上述批量处理protoid可以在一个python工程中连续完成,也可以分步完成, 因为他们之间没有必然联系。

#这是一个python函数,该函数会生成一个AllPB.lua文件,当客户端require该lua文件后,会require所有我们批处理生成的XXXX_pb.lua文件

#这是一个python函数,该函数会生成一个AllPB.lua文件,当客户端require该lua文件后,会require所有我们批处理生成的XXXX_pb.lua文件
def export_require(lua_path):outPath = os.path.abspath(lua_path + "/AllPB.lua")fileObj = open(outPath,"wb")fileObj.write("--this file is generated by tools, do not edit\n\n")fileObj.write("module(...,package.seeall)\n")fileObj.write("function InitModule()\n")fileObj.write("    ------------register NetMsg pb------------\n")for file in os.listdir(lua_path + "\\NetMsg"):if file[-3:] == "lua":fileObj.write("\trequire \"Logic/Proto/NetMsg/"+ file[:-4] +"\"\n")fileObj.write("end\n")fileObj.close()

分析上述代码,也不难看出该函数干了啥

--this file is generated by tools, do not editmodule(...,package.seeall)
function InitModule()------------register NetEnum pb------------------------register NetStruct pb------------------------register NetMsg pb------------require "Logic/Proto/NetMsg/Module_Achievement_pb"require "Logic/Proto/NetMsg/Module_AsyncArena_pb"require "Logic/Proto/NetMsg/Module_Award_pb"require "Logic/Proto/NetMsg/Module_Buildings_pb"require "Logic/Proto/NetMsg/Module_CenturyAdventure_pb"require "Logic/Proto/NetMsg/Module_Chat_pb"require "Logic/Proto/NetMsg/Module_ClientConfig_pb"require "Logic/Proto/NetMsg/Module_CommonInfo_pb"require "Logic/Proto/NetMsg/Module_Condition_pb"require "Logic/Proto/NetMsg/Module_Cross_pb"require "Logic/Proto/NetMsg/Module_Currencys_pb"require "Logic/Proto/NetMsg/NetStruct_Item_pb"require "Logic/Proto/NetMsg/NetStruct_Math_pb"require "Logic/Proto/NetMsg/NetStruct_Thing_pb"
end

最后展示一下AllPB.lua长这样,在项目启动的时候require该文件,则自动require所有生成的pb,是不是很nice!!!!

[完结语]

到此为止,lua版Proto生成与使用教程全部结束,并且还补充了protoid的生成方式。

生成 lua版本的proto 与使用相关推荐

  1. 5-(基础入门篇)学会刷Wi-Fi模块固件(刷LUA版本固件)

    http://www.cnblogs.com/yangfengwu/p/9065559.html 基础教程源码链接请在淘宝介绍中下载,由于链接很容易失效,如果失效请联系卖家,谢谢 https://it ...

  2. 1-添加自己的Lua执行函数(ESP8266-SDK开发(lua版本))

    基础 lua_pushnumber (L, 1); lua_pushnumber (L,3); lua_pushnumber (L,4); return 3; c_sprintf(temp, &quo ...

  3. git commit规范 、CHANGELOG生成 和版本发布的标准自动化

    长期以来,大家是不是受限于这种情况:团队中每位成员提交代码时填写的信息随意,没有一定的规范,在出问题后想要定位到某次提交记录时更是难上加难,或者是加上了 commitlint之类的规范,也没有添加ch ...

  4. lua版本base64加密和解密

    特别注意 Base64 主要不是加密,它主要的用途是把一些二进制数转成普通字符用于网络传输.由于一些二进制字符在传输协议中属于控制字符,不能直接传送需要转换一下就可以了 原理 将文件读入内存,由于读入 ...

  5. AndroidStudio如何打包生成realease版本的arr包,并上传到Nexus搭建的maven仓库,供项目远程依赖(二)

    AndroidStudio如何打包生成realease版本的arr包,并上传到Nexus搭建的maven仓库,供项目远程依赖(二) AndroidStudio如何打包生成realease版本的arr包 ...

  6. 高效查表判断胡牌算法的lua版本

    来源于日本论坛的一套用于麻将的判断胡牌算法,运用查表方式实现.原文链接(http://hp.vector.co.jp/authors/VA046927/mjscore/mjalgorism.html) ...

  7. 【Groovy】xml 序列化 ( 使用 StreamingMarkupBuilder 生成 xml 数据 | mkp.xmlDeclaration() 生成 xml 版本数据 )

    文章目录 一.使用 StreamingMarkupBuilder 生成 xml 数据 二.mkp.xmlDeclaration() 生成 xml 版本数据 三.完整代码示例 一.使用 Streamin ...

  8. Beyond compare 生成word版本的对比报告

    Beyond compare 生成word版本的对比报告 亲测两个c文件的对比报告可按此方法生成 下以两个txt文本文件为例 共两种方法,此为第一种, 1.按下图中序号依次动作 2.按下图中序号依次动 ...

  9. Cmake生成debug版本和release版本

    在Visual Studio中我们可以生成debug版本和release版本的程序,使用Cmake我们也可以达到同样的效果.debug版本的项目生成的可执行文件需要有调试信息并且不需要进行优化,而re ...

最新文章

  1. java中数组的含义_数组
  2. Transformer 会接管人工智能?
  3. m.soudashi.cn 地图_SEO人员怎样挖掘大量关键词库
  4. 《秋暮登北楼》王武陵
  5. 【Kubernetes系列】Kubernetes组件介绍
  6. Python基本语法[二],python入门到精通[四] (转)
  7. 今天你写控件了吗?----ASP.net控件开发系列之(一)开篇
  8. Oracle Statspack分析报告详解(一)
  9. left join 一对多只取一条_Python爬虫教程:验证码的爬取和识别详解
  10. MegaRAID Storage Manager RAID管理工具实用教程
  11. Java中List,ArrayList、Vector,map,HashTable,HashMap区别用法
  12. ATF(ARM Trusted firmware)完成启动流程
  13. Python实现数据技术|爬虫便可获取免费百度文库付费文档
  14. 伍斯特理工学院计算机科学硕士,美国伍斯特理工学院数据科学硕士录取
  15. Android 自定义Drawable实现圆角矩形图片和圆形图片
  16. 阅读笔记:利用Python进行数据分析第2版——第8章 数据规整:聚合、合并和重塑
  17. Linux 服务具体解释
  18. iOS根据生日判断星座
  19. m8 windows android,M8刷M9 Android ROM完全教程
  20. Dubbo的介绍以及Dubbox的区别

热门文章

  1. HTML5+规范:gallery(管理系统相册)
  2. 基于SVM的图像二分类算法
  3. 平面设计点线面在设计中的运用
  4. 用户画像洞察分类模型 - 前端页面展示
  5. elk搭建与简单的线上应用
  6. 常用开源软件开发平台和仓库(学生的福利)
  7. Oracle服务连接不上 ORA-12514 ORA-01034 ORA-27012
  8. 四大世界权威大学排名指标及侧重点
  9. 绘本计算机,阅芽绘本电脑版
  10. Python异常处理-查成绩