flatbuffers 在cocos2dx中的应用

前端之家收集整理的这篇文章主要介绍了flatbuffers 在cocos2dx中的应用前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

这篇文章 接着 前面的http://my.oschina.net/chenleijava/blog/423503,继续说说flatbuffers的应用

这里主要说的是flatbuffer 作为以cocos2dx引擎为基础 ,网络部分的序列化方案采用flatbuffers。

之所以考虑flatbuffers,依赖性低 ,性能较好。

这里只谈论设计方案,该设计方案对代码设计和结构上有一定的约定(相对订制):

客户端 会接受来自服务器的响应,解码到消息,进行数据处理。针对flatbuffers生成的类和对应处理该消息事的方案映射

在以前protbuffer中有提过(http://my.oschina.net/chenleijava/blog/376560)。这里依旧采用此方案:

注意以下所提及的类或者接口都是代码生成生成(主要适用于这类方案 定制的,采用java编写),会解析fbs文件生成对应的controller 文件。编写逻辑 只在

  1. virtualvoiddispatcherMessage(char*data);

中完成;

fbs测试:

  1. //1.使用genTools生成对应客户端代码你需要严格约定
  2. //2.table命名约定上下行消息xxRequestxxResponse
  3. //3.前后端交互消息存在一个消息ID;命名约定:msgID
  4. //4.命名空间使用gen---主要限制前端
  5.  
  6. namespacegen;
  7.  
  8. tableLoginFlatRequest{
  9.  
  10. msgID:int=1;
  11. username:string;
  12.  
  13.  
  14. }
  15.  
  16. tableLoginFlatResponse{
  17. msgID:int=2;
  18. time:long;
  19. }
  20.  
  21. tableBattleRequest{
  22. msgID:int=3;
  23.  
  24. }
  25.  
  26. tableBattleResponse{
  27. msgID:int=4;
  28.  
  29. }


接口类设计:IController.h

  1. //warnthisisgenfile,don'tmodifyit
  2. #ifndef_ICONTROLLER_H
  3. #define_ICONTROLLER_H
  4. #include<map>
  5. #include"cocos2d.h"
  6. #include"flatgen/Game_generated.h"
  7. usingnamespacecocos2d;
  8. usingnamespacegen;
  9. usingnamespacestd;
  10. #ifndefdelete_array
  11. #definedelete_array(p)do{if(p){delete[](p);(p)=nullptr;}}while(0)
  12. #endif//delete_array
  13. classIController{
  14.  
  15. public:
  16. IController(){}
  17. /**
  18. 注册消息ID和对应处理controller的关系
  19. 以便于快速索引处理
  20. */
  21. staticstd::map<int,IController*>controller_map;
  22. /**
  23. 负责处理数据分发
  24. */
  25. virtualvoiddispatcherMessage(char*data);
  26. /**
  27. *获取对应的消息ID
  28. */
  29. virtualintmsgID()=0;
  30. /**
  31. 转化对应消息为flatbuffers实体
  32. data+4:消息ID占用4字节
  33. */
  34. template<typenameT>constT*getRoot(char*data);
  35. /**
  36. *@Author石头哥哥,15-06-0123:06:26
  37. *
  38. *@brief注册controolerandmapper
  39. */
  40. staticvoidregisterMapperController();
  41. };
  42. template<typenameT>
  43. inlineconstT*IController::getRoot(char*data){
  44. returnflatbuffers::GetRoot<T>(data+4);
  45. }
  46. #endif//_ICONTROLLER_H

.cpp

  1. //thisisgenfile,don'tmodifyit
  2. #include"IController.h"
  3. #include"LoginFlatController.h"
  4. #include"BattleController.h"
  5.  
  6. map<int,IController*>IController::controller_map;
  7. voidIController::dispatcherMessage(char*data){}
  8. /**
  9. *注册controllermapper
  10. */
  11. voidIController::registerMapperController(){
  12. log("%s","registerMapperController开始注册controller......");
  13. controller_map[LoginFlatController::controller->msgID()]=LoginFlatController::controller;
  14. controller_map[BattleController::controller->msgID()]=BattleController::controller;
  15. }


生成对应的子类:LoginFlatController.h

  1. //thisisgenfile,don'tmodifyit
  2. #ifndefLoginFlatController_h
  3. #defineLoginFlatController_h
  4. #include"IController.h"
  5. classLoginFlatController:publicIController{
  6. public:
  7. staticLoginFlatController*controller;
  8. public:
  9. /**
  10. 负责处理数据分发处理来自服务器数据
  11. */
  12. virtualvoiddispatcherMessage(char*data);
  13. /**
  14. *获取对应的消息ID
  15. */
  16. virtualintmsgID()override;
  17. };
  18. #endif//LoginFlatController_h

.cpp

  1. //thisisgenfile,logiccontroler
  2.  
  3. #include"LoginFlatController.h"
  4. LoginFlatController*LoginFlatController::controller=newLoginFlatController;
  5.  
  6. intLoginFlatController::msgID(){
  7. flatbuffers::FlatBufferBuilderbuilder;
  8. builder.Finish(CreateLoginFlatResponse(builder));
  9. automsgID=flatbuffers::GetRoot<LoginFlatResponse>(builder.GetBufferPointer())->msgID();
  10. builder.ReleaseBufferPointer();
  11. returnmsgID;
  12. }
  13.  
  14. /**
  15. 负责处理数据分发处理来自服务器数据
  16. */
  17. voidLoginFlatController::dispatcherMessage(char*data){
  18.  
  19. autologinflatresponse=getRoot<LoginFlatResponse>(data);
  20. //TODO::处理来自服务器数据LoginFlatResponse
  21.  
  22. }

因为生成代码的工具还在开发中。目前只完成了cpp生成 ,后期支持java(服务器端)---暂时只定制flatbuffer代码生成

后期开源分享,这里提供java代码生成类:

  1. packagecom.genflat.mapper;/*
  2. *Copyright(c)2015.
  3. *游戏服务器核心代码编写人石头哥哥拥有使用权
  4. *最终使用解释权归创心科技所有
  5. *联系方式:E-mail:13638363871@163.com;
  6. *个人博客主页:http://my.oschina.net/chenleijava
  7. *poweredby石头哥哥
  8. */
  9.  
  10. importorg.apache.commons.io.FileUtils;
  11.  
  12. importjava.io.File;
  13. importjava.io.FilenameFilter;
  14. importjava.io.IOException;
  15. importjava.io.RandomAccessFile;
  16. importjava.util.ArrayList;
  17.  
  18. /**
  19. *@author石头哥哥
  20. *</P>
  21. *Date:2015/6/2
  22. *</P>
  23. *Time:9:35
  24. *</P>
  25. *Package:dcServer-parent
  26. *</P>
  27. *<p/>
  28. *注解:
  29. */
  30. publicclassGenFlatCpp{
  31.  
  32. /**
  33. *客户端处理消息类型注意消息命名XXXResponse---服务器响应消息类型
  34. */
  35. privatestaticfinalStringclient="Response";
  36.  
  37. /**
  38. *用于生成处理消息类型引用的变量名注意是静态类型
  39. */
  40. privatestaticfinalStringcontrollorname="controller";
  41.  
  42.  
  43. /**
  44. *对应客户端处理来自服务器端消息命名
  45. *xxxResponse
  46. *<p/>
  47. *tableLoginResponse{
  48. *objectID:int=2;
  49. *username:string;
  50. *}
  51. *<p/>
  52. *生成处理来自服务器端的Response类型消息<p/>
  53. *自动生成映射的mapper如:controller_map[msgID<LoginResponse>()]=LoginResponseController::controller;<p/>
  54. *同时生成对应的controller处理部分<p/>
  55. *逻辑编写部位:virtualvoiddispatcherMessage(char*data);<p/>
  56. *
  57. *@paramfbspathflatbufferfbs所在文件路径<p/>
  58. *@paramcontrollerpath对应controller生成路径<p/>
  59. *@throwsIOException
  60. */
  61. @SuppressWarnings("ResultOfMethodCallIgnored")
  62. publicstaticvoidgenCppMapper(Stringfbspath,Stringcontrollerpath)throwsException{
  63. Filefile;
  64. //getfbstablelist
  65. file=newFile(fbspath);
  66. String[]fbsNames=file.list(newFilenameFilter(){
  67. @Override
  68. publicbooleanaccept(Filedir,Stringname){
  69. returnname.endsWith(".fbs");
  70. }
  71. });
  72. if(fbsNames==null){
  73. thrownewException("fbsnotfoundinres!!!");
  74. }
  75.  
  76. ArrayList<String>fbsPaths=newArrayList<String>();
  77.  
  78. for(Stringfbsname:fbsNames){
  79. fbsPaths.add(fbspath+"/"+fbsname);
  80. }
  81.  
  82. //读取所有fbs文件获取文件中的tablename
  83. ArrayList<String>mapperTable=newArrayList<String>();
  84.  
  85. //loadingfbsandfiltertablename
  86. for(Stringfbs:fbsPaths){
  87. file=newFile(fbs);
  88. RandomAccessFilerandomAccessFile;
  89. try{
  90. randomAccessFile=newRandomAccessFile(file,"r");//O_RDONLY
  91. Stringtxt="";
  92. while(txt!=null){
  93. txt=randomAccessFile.readLine();
  94. if(txt!=null
  95. &&txt.startsWith("table")){
  96. Stringtemp=txt.substring(0,txt.lastIndexOf("{"))
  97. .replace("table","");
  98. if(temp.endsWith(client))mapperTable.add(temp.trim());
  99.  
  100. }
  101. }
  102. randomAccessFile.close();//closerandomAccessFile
  103. }catch(IOExceptione){
  104. e.printStackTrace();
  105. }
  106. }
  107. fbsPaths.clear();
  108.  
  109.  
  110. ArrayList<String>controllerList=newArrayList<String>();
  111.  
  112.  
  113. //foricontroller
  114. StringBuildermapperBuilder=newStringBuilder();
  115. //controller_map[LoginFlatController::controller->msgID()]=LoginFlatController::controller;
  116. for(Stringtable:mapperTable){
  117. Stringcontrollername=table+"Controller";
  118. controllername=controllername.replace(client,"");
  119. mapperBuilder.append("controller_map[")
  120. .append(controllername)
  121. .append("::")
  122. .append(controllorname+"->msgID()")
  123. .append("]")
  124. .append("=")
  125. .append(controllername)
  126. .append("::")
  127. .append(controllorname)
  128. .append(";\n");
  129. controllerList.add(controllername);//addcontroller
  130. }
  131.  
  132. mapperTable.clear();
  133.  
  134.  
  135. ArrayList<String>genIcontrollerHeader=newArrayList<String>();
  136. genIcontrollerHeader.addAll(controllerList);
  137. /**
  138. *don'toverridehadgenxxxcontroller
  139. *becausemaybehadlogicinit!!!!
  140. */
  141. String[]exsiteController=newFile(controllerpath).list(newFilenameFilter(){
  142. @Override
  143. publicbooleanaccept(Filedir,Stringname){
  144. returnname.endsWith(".cpp")&&!name.endsWith("IController.cpp");
  145. }
  146. });
  147.  
  148. for(Stringname:exsiteController){
  149. Stringtemp=name.substring(0,name.indexOf("."));
  150. if(controllerList.contains(temp)){
  151. controllerList.remove(temp);
  152. }
  153. }
  154.  
  155.  
  156.  
  157. StringBuilderbuilderCpp=newStringBuilder();
  158. //gen.hfile
  159. for(Stringcontroller:controllerList){
  160. Stringdefine=controller+"_h";
  161. builderCpp.append("//thisisgenfile,don'tmodifyit\n")
  162. .append("#ifndef")
  163. .append("").append(define).append("\n")
  164. .append("#define")
  165. .append("").append(define).append("\n")
  166. .append("#include\"IController.h\"")
  167. .append("\n")
  168. .append("class")
  169. .append(controller)
  170. .append(":").append("publicIController{")
  171. .append("\n")
  172. .append("public:")
  173. .append("\n")
  174. .append("static")
  175. .append(controller)
  176. .append("*")
  177. .append(controllorname)
  178. .append(";\n")
  179. .append("public:\n")
  180. .append("/**\n"+
  181. "负责处理数据分发处理来自服务器数据\n"+
  182. "*/\n")
  183. .append("virtualvoiddispatcherMessage(char*data);\n")
  184. .append("/**\n"+
  185. "*获取对应的消息ID\n"+
  186. "*/\n")
  187. .append("virtualintmsgID()override;\n")
  188. .append("};\n")
  189. .append("#endif")
  190. .append("//").append(define);
  191. byte[]cpp_h=builderCpp.toString().getBytes();
  192. builderCpp.delete(0,cpp_h.length);
  193.  
  194. //writeheader
  195. FilecontrollerFile=newFile(controllerpath);
  196. if(!controllerFile.exists()){
  197. controllerFile.mkdirs();
  198. }
  199. FileUtils.writeByteArrayToFile(newFile(controllerpath+"/"+controller+".h"),cpp_h);
  200.  
  201.  
  202.  
  203.  
  204. //gencontrollercppfile
  205. StringtableName=controller.substring(0,controller.indexOf("Controller"))+client;
  206. StringlowTablename=tableName.toLowerCase();
  207. builderCpp.append("//thisisgenfile,logiccontroler\n")
  208. .append("\n")
  209. .append("#include")
  210. .append("")
  211. .append("\"")
  212. .append(controller).append(".h")
  213. .append("\"")
  214. .append("\n")
  215. .append(controller).append("")
  216. .append("*")
  217. .append(controller)
  218. .append("::")
  219. .append(controllorname).append("=")
  220. .append("new").append(controller)
  221. .append(";\n")
  222. .append("\n")
  223. .append("int")
  224. .append(controller+"::msgID(){\n")
  225. .append("flatbuffers::FlatBufferBuilderbuilder;\n"+
  226. "builder.Finish(Create"+tableName+"(builder));\n"+
  227. "automsgID=flatbuffers::GetRoot<"+tableName+">(builder.GetBufferPointer())->msgID();\n"+
  228. "builder.ReleaseBufferPointer();\n"+
  229. "returnmsgID;\n")
  230. .append("}\n\n")
  231. .append("/**\n"+
  232. "负责处理数据分发处理来自服务器数据\n"+
  233. "*/\n")
  234. .append("void").append(controller).append("::")
  235. .append("dispatcherMessage(char*data){\n\n").append("auto")
  236. .append(lowTablename)
  237. .append("=getRoot<")
  238. .append(tableName)
  239. .append(">(data);\n")
  240. .append("//TODO::处理来自服务器数据")
  241. .append(tableName)
  242. .append("\n\n")
  243. .append("}");
  244.  
  245. byte[]cpp=builderCpp.toString().getBytes();
  246. builderCpp.delete(0,cpp.length);
  247. FileUtils.writeByteArrayToFile(newFile(controllerpath+"/"+controller+".cpp"),cpp);
  248. }
  249.  
  250.  
  251.  
  252.  
  253.  
  254.  
  255.  
  256.  
  257.  
  258. //IControlleralwaysoverride
  259. //genIControllergeneratedheadername
  260. ArrayList<String>generatedHeaders=newArrayList<String>();
  261. Stringtempname;
  262. Stringtempnameup;
  263. charfirst;
  264. for(Stringname:fbsNames){
  265. tempname=name.substring(1,name.lastIndexOf("."));
  266. tempnameup=name.substring(0,name.lastIndexOf(".")).toUpperCase();
  267. first=tempnameup.charAt(0);
  268. generatedHeaders.add(first+tempname);
  269. }
  270.  
  271.  
  272. builderCpp.append("//warnthisisgenfile,don'tmodifyit\n")
  273. .append("#ifndef").append("_ICONTROLLER_H\n")
  274. .append("#define").append("_ICONTROLLER_H\n")
  275. .append("#include<map>\n")
  276. .append("#include\"cocos2d.h\"\n");
  277. //appendgeneratedheaderinclude
  278. for(Stringname:generatedHeaders){
  279. builderCpp.append("#include\"flatgen/").append(name)
  280. .append("_generated.h\"").append("\n");
  281. }
  282. generatedHeaders.clear();
  283.  
  284. builderCpp.append("usingnamespacecocos2d;\n")
  285. .append("usingnamespacegen;\n")
  286. .append("usingnamespacestd;\n")
  287. .append("#ifndefdelete_array\n")
  288. .append("#definedelete_array(p)do{if(p){delete[](p);(p)=nullptr;}}while(0)\n")
  289. .append("#endif//delete_array\n")
  290. .append("classIController{\n")
  291. .append("\n")
  292. .append("public:\n")
  293. .append("IController(){}\n")
  294. .append("/**\n"+
  295. "注册消息ID和对应处理controller的关系\n"+
  296. "以便于快速索引处理\n"+
  297. "*/\n")
  298. .append("staticstd::map<int,IController*>controller_map;\n")
  299. .append("/**\n"+
  300. "负责处理数据分发\n"+
  301. "*/\n")
  302. .append("virtualvoiddispatcherMessage(char*data);\n")
  303. .append("/**\n"+
  304. "*获取对应的消息ID\n"+
  305. "*/\n")
  306. .append("virtualintmsgID()=0;\n")
  307. //.append("/**\n"+
  308. //"*@Author石头哥哥,15-06-0123:06:00\n"+
  309. //"*\n"+
  310. //"*@brief获取生成消息对应的msgID\n"+
  311. //"*\n"+
  312. //"*@return<#returnvaluedescription#>\n"+
  313. //"*/\n")
  314. //.append("template<typenameT>staticintmsgID();\n")
  315. .append("/**\n"+
  316. "转化对应消息为flatbuffers实体\n"+
  317. "data+4:消息ID占用4字节\n"+
  318. "*/\n")
  319. .append("template<typenameT>constT*getRoot(char*data);\n")
  320. .append("/**\n"+
  321. "*@Author石头哥哥,15-06-0123:06:26\n"+
  322. "*\n"+
  323. "*@brief注册controolerandmapper\n"+
  324. "*/\n")
  325. .append("staticvoidregisterMapperController();\n")
  326. .append("};\n")
  327. //.append("template<typenameT>\n")
  328. //.append("inlineintIController::msgID(){\n"+
  329. //"flatbuffers::FlatBufferBuilderbuilder;\n"+
  330. //"builder.Finish(CreateLoginRequest(builder));\n"+
  331. //"automsgID=flatbuffers::GetRoot<T>(builder.GetBufferPointer())->msgID();\n"+
  332. //"builder.ReleaseBufferPointer();\n"+
  333. //"returnmsgID;\n"+
  334. //"}\n")
  335. .append("template<typenameT>\n"+
  336. "inlineconstT*IController::getRoot(char*data){\n"+
  337. "returnflatbuffers::GetRoot<T>(data+4);\n"+
  338. "}")
  339. .append("\n").append("#endif//_ICONTROLLER_H");
  340.  
  341. byte[]data=builderCpp.toString().getBytes();
  342. builderCpp.delete(0,data.length);
  343. FileUtils.writeByteArrayToFile(newFile(controllerpath+"/IController.h"),data);
  344.  
  345.  
  346. //genicontrollercpp
  347. builderCpp.append("//thisisgenfile,don'tmodifyit\n")
  348. .append("#include\"IController.h\"\n");
  349.  
  350. for(Stringcontroller:genIcontrollerHeader){
  351. builderCpp.append("#include")
  352. .append("\"").append(controller).append(".h")
  353. .append("\"\n");
  354. }
  355. genIcontrollerHeader.clear();
  356. controllerList.clear();
  357. builderCpp.append("\n")
  358. .append("map<int,IController*>IController::controller_map;\n")
  359. .append("voidIController::dispatcherMessage(char*data){}\n")
  360. .append("/**\n"+"*注册controllermapper\n"+"*/\n"+"voidIController::registerMapperController(){\n"+
  361. "log(\"%s\",\"registerMapperController开始注册controller......\");\n")
  362. .append(mapperBuilder.toString()).append("}\n");
  363. data=builderCpp.toString().getBytes();
  364. builderCpp.delete(0,data.length);
  365. FileUtils.writeByteArrayToFile(newFile(controllerpath+"/IController.cpp"),data);
  366.  
  367. System.out.println("-------gensuccess!!!---------------------");
  368.  
  369. }
  370.  
  371.  
  372. }
  1. packagecom.genflat.mapper;/*
  2. *Copyright(c)2015.
  3. *游戏服务器核心代码编写人石头哥哥拥有使用权
  4. *最终使用解释权归创心科技所有
  5. *联系方式:E-mail:13638363871@163.com;
  6. *个人博客主页:http://my.oschina.net/chenleijava
  7. *poweredby石头哥哥
  8. */
  9.  
  10. importjava.io.File;
  11. importjava.io.IOException;
  12.  
  13. /**
  14. *@author石头哥哥
  15. *</P>
  16. *Date:2015/6/2
  17. *</P>
  18. *Time:9:34
  19. *</P>
  20. *Package:dcServer-parent
  21. *</P>
  22. *<p/>
  23. *注解:
  24. */
  25. publicclassGenFlatMapper{
  26.  
  27.  
  28. /**
  29. *defaultgenc++
  30. *args[0]-l
  31. *args[1](java,cpp)
  32. *args[2]-p
  33. *args[3](controllerfilepath)
  34. *args[4]-o
  35. *args[5]fbsfilepath
  36. *
  37. *@paramargs
  38. */
  39. publicstaticvoidmain(String[]args)throwsIOException{
  40. Stringshow=">>>>flatbuffergen"+
  41. "\n该工具可以生成基于flatbuffers的代码,接口说明如下\n"+
  42. "使用命令:java-jargenflatMapper.jar-lcpp-ccontrollerpath-ffbspath\n"+
  43. "-l:编程语言类型这里暂时支持c++;\n"+
  44. "-p:游戏中处理对应消息的controller文件路径;\n"+
  45. "-o:编写的fbs文件路径;\n"+
  46. "游戏中fbs针对上行下行table命名规则有严格约定,如不使用该约定\n"+
  47. "使用该工具无效,详见readme!";
  48. System.out.println(show);
  49.  
  50. if(args.length!=0){
  51. System.out.println("--------begingenclientcode----------------");
  52. if(args.length<6){
  53. System.err.println(show);
  54. System.exit(0);
  55. }
  56. Stringl=args[1];
  57. Stringcontrollerpath=args[3];
  58. Stringfbspath=args[5];
  59. if(l.equals("java")){
  60. System.err.println("onlysupportclient,c++\n");
  61. System.err.println("useeg:\n"+
  62. "java-jargenflatMapper.jar-lcpp"+
  63. "-ccontrollerpath-ffbspath");
  64. System.exit(0);
  65. }elseif(l.equals("cpp")){
  66. try{
  67. GenFlatCpp.genCppMapper(fbspath,controllerpath);
  68. }catch(Exceptione){
  69. e.printStackTrace();
  70. }
  71. }
  72.  
  73. }else{
  74. try{
  75. //gencurrentfile
  76. System.out.println("toolswillgentocurrentfiles,ifyourfbsinresfile!!!");
  77. Filefile=newFile("./controller");
  78. if(!file.exists())file.mkdirs();
  79. //findfbs
  80. GenFlatCpp.genCppMapper("res","./controller");
  81. }catch(Exceptione){
  82. e.printStackTrace();
  83. }
  84.  
  85. }
  86.  
  87.  
  88. }
  89.  
  90. }


该生代码成器约定如下--如果你使用该方案,那么请严格遵循改约束,或许你有更好的idea:

  1. ###基于flatbuffers,使用fbs文件生成对应前端代码
  2. ###完成对应的controller和消息ID映射,目前暂时支持c++。
  3.  
  4.  
  5. >1.使用genTools生成对应客户端代码你需要严格约定
  6. 2.table命名约定上下行消息xxRequestxxResponse
  7. 3.前后端交互消息存在一个消息ID;命名约定:msgID
  8. >4.命名空间使用gen---主要限制前端
  9.  
  10. namespacegen;
  11. //下行消息xxRequest
  12. tableLoginRequest{
  13. msgID:int=1;//消息IDmsgID
  14. username:string;
  15. }
  16. //下行消息xxResponse
  17. tableLoginResponse{
  18. msgID:int=1;//消息IDmsgID
  19. username:string;
  20. }
  21.  
  22. ####如何使用:
  23. 该工具可以生成基于flatbuffers代码,接口说明如下
  24. 使用命令:
  25. java-jargenflatMapper.jar-lcpp-pcontrollerpath-ofbspath
  26. >-l:编程语言类型这里暂时支持c++;
  27. >-c:游戏中处理对应消息的controller文件路径;
  28. >-f:编写的fbs文件路径;

生成对应的文件如下:

上面代码都是生成的。

因为无法上传jar,如果你需要 留言你的邮箱 !

猜你在找的Cocos2d-x相关文章