解决方案:在Cocos Creator1.8中使用官方的google protobuf

看了一下,网上并没有在Cocos Creator1.8中使用官方的google protobuf的完整解决方案。
由于项目以前用的java写的的服务器,处理google protobuf2的逻辑已经写好,所以我研究了一下google protobuf在cocos的应用。

最新更新:之前没有确定protobufjs和google protobuf是否兼容(即同样的proto文件转化成的二进制是否一样)。现在证实是兼容的。所以完全可以用protobufjs的解决方案,没有必要用我这个。pbkiller也是完全可以的。 不过具体的api有些不同,另外我觉得google的byte操作更好一些。所以遇到问题不能用protobufjs的用我这个方法就可以了

Creator 版本:1.8
google protobuf版本: 3.5

粗略步骤:
1 下载官方的google protobuf组件
2 通过.proto文件生成js文件
3 修改源码
4 测试

1 下载官方的google protobuf组件

这一步之前建议先阅读https://github.com/google/protobuf里面的文档
尤其是js分类下的文档

这一步的目标就是要弄到两个东西:
proto文件的编译器

google-protobuf.js

proto文件的编译器是为了把你写的.proto文件变成.js文件
为了得到proto文件的编译器,可以从https://github.com/google/protobuf/releases下载最新的js编译器(注意看下载的包的名字,是protoc,不是protobuf,很容易下错,比如本人。。)

google-protobuf.js是一个runtime支持,用于提供一些方法。
为了得到google-protobuf.js,可以直接通过npm下载安装,安装npm的方法请百度。
安装好npm后,在一个合适的文件夹内打开命令行,输入 npm install google-protobuf 安装google protobuf的runtime支持。
安装好后会出现很多文件,只有里面的google-protobuf.js是必须的,其他的可以删掉。

2 通过.proto文件生成js文件

首先要准备好proto文件,写proto的文件的语法用3或者2版本的都可以。
在有protoc.exe的文件夹打开命令行(或者打开命令行后cd 到那里去),
输入 protoc --js_out=import_style=commonjs,binary:. XXXXX.proto
其中 XXXXX.proto 是你的proto文件名,可以有多个空格隔开
结束后本文件夹内会出现一个新的js文件。
(看官方文档的朋友会注意到官网写了这里有两种生成方法:CommonJS和Closure,我选用了CommonJS,Closure应该也可以但是后面改源码的方式不同)

3 修改源码

首先把上面步骤生成的两个文件放在你的项目里。
cocos creator会提示是否导入为插件,选择否
然后会等待cocos编译一段时间,由于脚本代码多最多可能有几十秒

然后可以运行一下,肯定会报错。
首先是一个无法从undefined获得navigator。
仔细看源码会发现其实是goog.global为undefined了
再仔细一看就会发现是$jscomp.getGlobal(a) 这个函数的问题。
把它改成


其中很长的那行是原代码的那行。
本质上其实就是强行让他等于window

然后找到这行,用搜索工具吧,大约在40~45行
var COMPILED = !0, goog = goog || {}; goog.global = this;
改成
var COMPILED = !0, goog = goog || {}; goog.global = $jscomp.getGlobal();

然后就是最后要加一些导出的东西,在最后加上这三行:

接着修改proto文件编译出的那个js文件,
在最前面,找到这两行:
var jspb = require(‘google-protobuf’);
var goog = jspb;

把它改成
var jspbcomp = require(‘google-protobuf’);
var COMPILED = jspbcomp.COMPILED;
var jspb = jspbcomp.jspb;
var goog = jspbcomp.goog;
保存文件。

等待cocos编译一下(严格说这不是编译,是生成temp里面的quick script)
然后应该就没有报错了

4 测试

比如说本项目的proto文件编译出来的js文件是Packet_pb.js
我的proto文件里面有个int类型的type属性,类似于
message Packet {
required int32 type = 1;
}

那么可以写一个cocos creator的组件,在里面写

var packet_pb = require(‘Packet_pb’);
console.log(packet_pb);

var message = new packet_pb.Packet();
console.log(message);

message.setType(12);
console.log(message.getType());

观察log信息,最后如果可以输出12,成功!

再试一下:
var b = message.serializeBinary();
console.log(b);
观察log信息:

转化成2进制成功!

15赞

前端直接用 protobufjs 就好了,什么都不用改,和后端没什么关系

但是 protobufjs 发送出去的二进制和google protobuf的不一样吧,请问有人测试过么?

是一样的。你的用法不对。(ts版,js也差不多)

import { awesomepackage } from “./bundle”;

let message = awesomepackage.AwesomeMessage.create({ awesomeField: “hello” });
let buffer = awesomepackage.AwesomeMessage.encode(message).finish();
let decoded = awesomepackage.AwesomeMessage.decode(buffer);
cc.log(buffer);
cc.log(decoded);

为了方便大家,可以直接用这个,就不用下载,也不用改google-protobuf.js的源码了

jsfile.zip (33.8 KB)

我之前也用的 google-protobuf.js 。后来各种要改代码,烦死。现在 用 protobufjs,蛮好

谢谢楼主,太棒了。加个好友,一起研究哈

我在去年发了一个1.6.x的protobuf.js插件,放到1.8也是可以用的,我自己跑了下,没什么问题,可以正常进入游戏中

1赞

我用了你修改后的文件,最后在浏览器运行 goog.global = this,但是我明明已经把他改成 goog.global = $jscomp.getGlobal();

后来我再做项目时发现其实这里面所有的window和document都是特殊浏览器支持的代码(源码里很多都是opera,edge,ie这些东西的特殊代码),其实可以把这些代码都删掉的。
尤其是如果要使用在微信小程序的话,还不能有eval函数,而这里面还有eval函数。

于是我就又进一步改了这个的源码。去掉了所有的eval函数和window以及document的使用。依旧可以正常运行,可能在某些特殊设备上会有兼容性的问题吧。。

更新的googleprotobufjs.zip (33.6 KB)

这是更新后的,去掉了所有的window document和eval函数。适合微信小程序。 但是去掉了很多代码,某些浏览器下可能会出错,目前我是用的chrome和firefox没有发现任何错误。

2赞

另外,如果大家用javascript的websocket和C#或者java的socket通信的话,还有一个坑(我最近在这个坑里刚出来)。
就是websocket比socket所在的TCP/IP高一层级,它的协议多一个websocket信息头。
信息头的描述请参考 https://tools.ietf.org/html/rfc6455#section-5

如果想让js的websocket和C#或者java的socket通信,必须在服务端手动添加/去掉websocket信息头,才能发送/接收消息。

而且websocket能自动处理tcp层的断粘包。所以客户端是很方便的。

目前基本实现了,具体代码不便提供,有同样问题的我们可以一起探讨。

这应该是其他地方的问题,可以试试清空浏览器缓存,并且把temp/quickscript文件夹删了重开cocos creator

我觉得应该直接在 C# 或 Java 里使用已有的 WebSocket 实现比较好

对,有现成的工具的,不用重复造轮子。我是为了测试手写了一部分代码。

我觉得最好不要修改第三方库, 维护升级不方便,来一个无侵入的解决方案

1赞

你多虑了,我在游戏中用protobufjs,后台java用Google protobuf工作了好几年了。我还用nodejs+protobufjs给被人的游戏后台(c++),做压力测试,他们只提供proto文件给我,都是可以正常通信。

proto现在相当于一种编码标准了,都是按google定义的标准来的,如果生成的二进制不同,那就不能称为protobuf。

如果可用,真心不错。
我现在是在服务端的接入层把 proto二进制转换成json与客户端web socket通讯

如果真的是这样。那我确实没必要搞这么多工作。谢谢,待我闲时研究一下。