更多筆記和源碼請關注:【微信公衆號】 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);
});
打印結果: