更多笔记和源码请关注:【微信公众号】 CocosCreator笔记
protobuf:
protocol buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。
Protocol Buffers 是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 XML,但是比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。
你可以定义数据的结构,然后使用特殊生成的源代码轻松的在各种数据流中使用各种语言进行编写和读取结构数据。你甚至可以更新数据结构,而不破坏由旧数据结构编译的已部署程序。
技术摘要
静态加载(适用于微信小游戏)
动态加载(不适用于微信小游戏)
准备工作
下载protobufjs,最新版本为v6.8.8:
https://www.npmjs.com/package/protobufjs
根据需要提取相关js,放入目标目录
创建proto:
syntax = "proto3";
package tutorial;
message Person {
string name = 1;
int32 id = 2; // Unique ID number for this person.
string email = 3;
}
message AddressBook {
repeated Person people = 1;
}
静态加载
1编译proto为js
下载protoc编译器,将proto编译为js:
https://repo1.maven.org/maven2/com/google/protobuf/protoc/
这里我将下载好的protoc和proto文件放在同一目录内
在目录内打开控制台,根据需要输入command
生成单个proto的js:
pbjs -t static-module -w commonjs -o addressbook_pb.js addressbook.proto
将目录内所有proto生成一个js:
pbjs -t static-module -w commonjs -o proto.js *.proto
生成后目录内的文件如下:
将生成的js文件放入目标目录內
修改刚刚生成的js,引入正确的protobuf.js
ps:关于引入方式,历史笔记中有详细介绍
// var $protobuf = require("protobufjs/minimal");
var $protobuf = require("./protobuf.js");
2编码和解码
引入js:
import { tutorial } from "../protobuf/addressbook_pb.js"
encode/decode:
let person = tutorial.Person.create({ name: "Tom", id: 18, email: "tom@email" });
let buffer = tutorial.Person.encode(person).finish();
let message = tutorial.Person.decode(buffer);
console.log(buffer);
console.log(message);
let people = [{ name: "Tom", id: 18, email: "tom@email" },
{ name: "Lili", id: 20, email: "lili@email" }
];
let payload = tutorial.AddressBook.create({ people: people });
buffer = tutorial.AddressBook.encode(payload).finish();
message = tutorial.AddressBook.decode(buffer);
console.log(buffer);
console.log(message);
打印结果:
动态加载
相比静态加载,动态加载直接load需要的proto就可以使用,更加灵活,也可以有效的减少js文件
但其内部使用了Function,而在微信小游戏中禁止动态生成代码的行为,所以无法在小游戏中使用
①将proto放到resources目录下
②修改protobuf.js,使用cc的资源加载方式
在fetch函数中增加对资源的动态加载(cc.loader.loadRes),以获取proto内容
③使用
引入protobuf:
import * as protobuf from "./protobuf.js";
加载proto:
load(fileName) {
return new Promise((resolve, reject) => {
protobuf.load(fileName, (err, root) => {
if (err) {
reject(err);
} else {
this._root = root;
resolve();
}
});
});
}
decode:
//packageMessage: package.message
decode(packageMessage: string, buffer) {
//lookup等价于lookupTypeOrEnum
//不同的是lookup找不到返回null,lookupTypeOrEnum找不到则是抛出异常
let message = null;
let data = this._root.lookup(packageMessage);
if (data != null) {
message = data.decode(buffer);
}
return message;
}
encode:
//packageMessage: package.message
encode(packageMessage: string, obj) {
let buffer = null;
let data = this._root.lookup(packageMessage);
if (data != null) {
let message = data.create(obj);
buffer = data.encode(message).finish();
}
return buffer;
}
使用:
let proto = LoadProto.getInstance();
proto.load("proto/addressbook")
.then(() => {
let person = { name: "Tom", id: 18, email: "tom@email" };
let buffer = proto.encode("tutorial.Person", person);
let message = proto.decode("tutorial.Person", buffer);
console.log(buffer);
console.log(message);
let people = [{ name: "Tom", id: 18, email: "tom@email" },
{ name: "Lili", id: 20, email: "lili@email" }
];
let payload = { people: people };
buffer = proto.encode("tutorial.AddressBook", payload);
message = proto.decode("tutorial.AddressBook", buffer);
console.log(buffer);
console.log(message);
});
打印结果: