Use Protobufjs (a) in the Cocos Creator

A. Environmental preparation

I have been exploring the Cocos H5 correct posture development , javascript currently doing projects have been inseparable, etc. nodejs, npm or grunt scaffolding tool.

1. initialization file package.json

nPM heat

When the new good cocos-js or creator items used in the project root directory npm init command, all the way round, will be created in the current directory package.json file for nodejs tripartite management module. Details on the network npm There are many tutorials here not elaborate.

2. protobufjs module

file

He was first in cocos2dx 2.x era began with protobufjs module to manipulate protobuf until now. So all of the following contents are in use on protobufjs cocos creator, including the native platform (cocos2d-js is similar).

Project to install protobufjs

npm install protobufjs@5 --save

Use npm install command to install the module, note that we use here is protobufjs 5.x version. Although protobufjs latest version 6.x, offers ts, rpc support and other functions, but there is a problem that can not be dynamically loaded in the micro-letter file proto small game.

Installation protobufjs to the global

asl install -g protobufjs @ 5

Use npm install -g module mounted to the global parameters, the main purpose is to provide convenience pbjs protobufjs command line tool. pbjs proto original file can be converted into json, js, so as to provide different loading proto way, we can choose according to their own situation.

Two. Protobufjs usage

Here are the contents of the demo file Player.proto defined

syntax = "proto3";
package grace.proto.msg;

message Player {
    uint32  id = 1;         //唯一ID  首次登录时设置为0,由服务器分配
    string  name = 2;       //显示名字
    uint64  enterTime = 3;  //登录时间
}

Proto details about specific syntax here is not to say, we will focus on how the Player object Player.proto defined in the file instantiated in js, the property assignment, serialization, deserialization operations.

1. Static language used proto file

Use protobuf in c ++ / java static languages ​​such usually use protoc command will compile the official proto files into c ++ / java code like this:

protoc --cpp_out = output path xxx.proto
Protoc --java_out = output path xxx.proto

Use the imported file output path corresponding to the language engineering.

2. Use the proto file in the project creator

file

javascript is a dynamic language that can generate objects at run time, thus providing a more convenient protobufjs dynamic compilation, the proto objects in the file generated js objects, briefly explain the following specific steps in the use of the creator:

1. Load the file and compiled proto proto objects

//导入protobufjs模块
let protobuf = require("protobufjs");
//获取一个builder对象
let builder = protobuf.newBuilder();
//使用protobufjs加文件,并与一个builder对象关联
protobuf.protoFromFile('xxx.proto', builder);
protobuf.protoFromFile('yyy.proto', builder);
...
let PB = builder.build('grace.proto.msg'); 

This operation is mainly use protobufjs loaded, compiled proto file.

2. Examples of proto object attribute assignment

let PB = builder.build('grace.proto.msg')

PB will build function returns the value object contains all the message objects is defined in the proto now become js objects can be instantiated, as follows:

//实例化Player
let player = new PB.Player();  
//属性赋值
player.name = '张三';             
player.enterTime = Date.now();

Object serialization and serialization anti 3.proto

No bullshit, or directly on the code

...
//使用实例对象上的toArrayBuffer函数将对象序列化为二进制数据
let data = player.toArrayBuffer();
//使用类型对象上的decode函数将二进制数据反序列化为实例对象
let otherPlayer = PB.player.decode(data);

If you're lucky you can use protobuf on the web, why do only on the web, when you run the above code when under jsb environment, you will experience a sad reminder of what is happening.

III. Protobufjs save on cocos-jsb

Why run on native hung out? To understand this issue requires nodejs browser \ cocos-jsb three javascript running host environment has a certain understanding.

I mentioned in the previous article when choosing nodejs module, pay attention to whether to support nodejs and web, as long as the pure js modules can generally be easily used in cocos, such as async, undersocre, lodash and so on.
protobufjs This module is a very good run in the browser and nodejs environment. But it will be a problem running on cocos-jsb, we need to locate the key code to the problem:

protobuf.protoFromFile('xxx.proto', builder);

1. Analysis

Protobuf.protoFromFile function names from the point of view that this is a file to be loaded, the thought of files loaded, api related to file operations, we have to sort out the file interface on different platforms:

Host platform File Interface Explanation
Browser XMLHttpRequest Basic browser dynamically load resources, such as file AJAX operation
nodejs fs.readFile / fs.readFileSync The file operation module nodejs, implemented by the underlying ++ c / c
cocos, etc. jsb.fileUtils.getStringFromFile Read the contents of the file interfaces cocos-js provided at no stage platform (ios \ android \ windows) api achieved by different underlying

See here I believe many people have to understand why there is a problem in the cocos-jsb, let us read protobufjs source, our analysis confirms.

2. Analysis protobufjs source

file
The main code is found protobufjs loaded file, I added the following comments to the source code, please carefully read the footnotes:

Util.fetch = function(path, callback) {
    //检查callback参数,callback参数决定是否为异步加载
    if (callback && typeof callback != 'function')
        callback = null;

    //运行环境是否为nodejs
    if (Util.IS_NODE) {
        //加载nodejs的文件系统模块
        var fs = require("fs");  
        //检查是否有callback,存在使用fs.readFile异步函数读取文件内容
        if (callback) {
            fs.readFile(path, function(err, data) {
                if (err)
                    callback(null);
                else
                    callback(""+data);
            });
        } else
            //使用fs.readFileSync同步函数读取文件内容 
            try {
                return fs.readFileSync(path);
            } catch (e) {
                return null;
            }
    } else {
        //当不为nodejs运行环境使用XmlHttpRequest加载文件
        var xhr = Util.XHR();
        //根据callbcak参数是否存在,使用异步还是同步方式
        xhr.open('GET', path, callback ? true : false);
        // xhr.setRequestHeader('User-Agent', 'XMLHTTP/1.0');
        xhr.setRequestHeader('Accept', 'text/plain');
        if (typeof xhr.overrideMimeType === 'function') xhr.overrideMimeType('text/plain');
        //通过XmlHttpRequest.onreadystatechange事件函数异步获取文件数据
        if (callback) {
            xhr.onreadystatechange = function() {
                if (xhr.readyState != 4) return;
                if (/* remote */ xhr.status == 200 || /* local */ (xhr.status == 0 && typeof xhr.responseText === 'string'))
                    callback(xhr.responseText);
                else
                    callback(null);
            };
            if (xhr.readyState == 4)
                return;
            //调用send方法发起AJAX请求
            xhr.send(null);
        } else {
            ////调用send方法发起AJAX请求,同步获取文件数据
            xhr.send(null);
            if (/* remote */ xhr.status == 200 || /* local */ (xhr.status == 0 && typeof xhr.responseText === 'string'))
                return xhr.responseText;
            return null;
        }
    }
};

From the above code can be seen protobufjs library is ready for the browser and nodejs, and did not even considered the existence of cocos-jsb (Tucao: It is recommended interfaces can imitate nodejs cocos official offer so many things can be less), so in cocos-jsb using protobufjs a way which is modified protobufjs source, as follows:

Util.fetch = function(path, callback) {
    if (callback && typeof callback != 'function')
        callback = null;
    //将平台检查代码改为cocos提供的接口
    if (cc.sys.isNative) {
        //文件读取使用cocos-jsb提供的函数
        try {
            let data = jsb.fileUtils.getStringFromFile(path);
            cc.log(`proto文件内容: {data}`);
            return data;
        } catch (e) {
            return null;
        }
    } else {
        //web端无需修改,略
        ...
};

We cocos interface will modify the code, load the problem was resolved, the problem was really solved?
Sorry, the code to addition to the above there is a need to change the code, the source code is as follows:

BuilderPrototype["import"] = function(json, filename) {
    var delim = '/';

    // Make sure to skip duplicate imports

    if (typeof filename === 'string') {
        //这里又出现了平台检查
        if (ProtoBuf.Util.IS_NODE)
            // require("path")是加载nodejs的path模块,resolve
            filename = require("path")['resolve'](filename);
        if (this.files[filename] === true)
            return this.reset();
        this.files[filename] = true;

    } else if (typeof filename === 'object') { // Object with root, file.

        var root = filename.root;
        //这里还要修改
        if (ProtoBuf.Util.IS_NODE)
            root = require("path")['resolve'](root);
        if (root.indexOf("\\") >= 0 || filename.file.indexOf("\\") >= 0)
            delim = '\\';
        var fname;
         //这里还要修改
        if (ProtoBuf.Util.IS_NODE)
            fname = require("path")['join'](root, filename.file);
        else
            fname = root + delim + filename.file;
        if (this.files[fname] === true)
            return this.reset();
        this.files[fname] = true;
    }
    ...
}

I will not paste modify the code, we resolve itself.

Four for protobuf continue to fill the hole

Originally I write to you, most of the problems have been resolved, but this time, after the confidence to use if you transform protobufjs source, your code will run up that moment, I believe most people will be forced to look Mongolia.
file

Mom did not work! ! Read a lot of words, finally read here, is not only not up and running in the simulator, on the web is also not up and running.

How to do, in order to solve the problem, I have to continue writing.

1. Understand the creator dynamic loading method resources

Please think about a problem, creator of the project a picture on the web with the cocos-jsb their file path will be the same? Directly protobuf.protoFromFile ( 'xxx.proto') to load a proto file will succeed?
cocos document said to dynamically load a picture resource file needs to be stored in the assets / resources directory, loaded using the following method:

cc.loader.loadRes('resources/xxx')

Try proto files are stored in resources / pb / directory, use the following code:

protobuf.protoFromFile('resources/pb/xxx.proto')

They will also fail to get tips, how to do it? How to get the correct resource path?
Well, do not buy off the child, and tired to write directly answer it!

protobuf.protoFromFile(cc.url.raw('resources/pb/xxx.proto'));

cc.url.raw this function in the browser, simulator, the phone will return a different resource path, this is the real resource path, which under the code should run normally again.

2. A better solution brought to justice

I have been exploring the Cocos H5 correct development mode, although you can run to solve the problem in the cocos-jsb protobufjs by modifying the source code of the method, but this is not the only solution.

How to get in without modifying the source code protobufjs up and running, and the use of pre-compiled proto pbjs tool to use JSON file and js files, please keep on watching my series of articles "When the Creator encounter protobufjs"!

file

Guess you like

Origin www.cnblogs.com/creator-star/p/11584504.html