CocosCreator使用protobuf

一、环境

    操作系统 mac 10.12.2

    CocosCreator 1.5.1

    protobuf.js 6.7.0

二、正文

1、把与服务器协议好的.proto(我的文件是client.proto)文件放在assets/resources文件夹下。

2、在https://github.com/dcodeIO/protobuf.js/releases/上下载相应的protobuf.js,把protobuf.js放到你的项目的script文件夹下(不一定是script文件夹,这只是一个规范,因为CocosCreator是仿照u3d来做的,而u3d的做法是把脚本放在script文件夹下)。

新建ProtobufManager.js(依旧是script文件夹下或者script的子目录),然后,上代码,这是本人小封装了一下的代码:

var ProtobufManager;
(function(ProtobufManager) {
	ProtobufManager.heartCount = 1;

	var loadProtobuf = function() {
		function callback(err, root) {
			ProtobufManager.Root = root;
			ProtobufManager.Command = root.lookup("proto.Command").values;
            GameServerManager.connectServer();
		};
		protobuf.load(cc.url.raw("resources/proto/client.proto"), callback);
	};
	ProtobufManager.loadProtobuf = loadProtobuf;

	ProtobufManager.sendAutoID = function() {
		var autoID = {id : this.heartCount};
		this.serialize("proto.AutoID", autoID, this.Command.client_heart_beat);
	}

	ProtobufManager.getAutoID = function(buffer) {
		return this.decode("proto.AutoID", buffer);
	}

	ProtobufManager.serialize = function(proto, object, command) {
		var protobufObj = this.Root.lookupType(proto);
		this.serializeProtobuf(protobufObj, object, command);
	} 

	ProtobufManager.serializeProtobuf = function(protobufObj, object, command) {
		var message = this.checkMessage(protobufObj, object);
		var buffer = this.serializeMessage(protobufObj, message);
		this.packProtobuf(command, buffer);
	}
	ProtobufManager.checkMessage = function(protobufObj, object) {
		var errMsg = protobufObj.verify(object);
		if(errMsg) {
			throw Error(errMsg);
		}
		var message = protobufObj.fromObject(object);
		return message;
	}
	ProtobufManager.serializeMessage = function(protobufObj, message) {
		var buffer = protobufObj.encode(message).finish();
		var array = new Uint8Array(buffer);
		return array;
	}
	ProtobufManager.decode = function(proto, buffer) {
		var protobufObj = this.Root.lookupType(proto);
		return this.decodeProtobuf(protobufObj, buffer);
	}
	ProtobufManager.decodeProtobuf = function(protobufObj, buffer) {
		return protobufObj.decode(buffer);
	}
	ProtobufManager.packProtobuf = function(command, buffer) {
		var len = buffer.length;
		
		var byteArr = new ArrayBuffer(len + 10);
		var dv = new DataView(byteArr, 0);
		dv.setUint32(0, len + 6, false);
		dv.setUint32(4, this.heartCount, false);
		dv.setUint16(8, command, false);
		for(var i = 0; i < len; i++) {
			dv.setUint8(10 + i, buffer[i], false);
		}
		this.heartCount++;
		GameServerManager.send(byteArr);
		
	}
})(ProtobufManager || (ProtobufManager = {}));
window.ProtobufManager = ProtobufManager;
下面,给出我用的client.proto文件

// 包结构
// +------------------+-------------------+------------------+----------------+
// |  length(uint32)  |  sequence(uint32) | command(uint16)  |  frame([]byte) |
// +------------------+-------------------+------------------+----------------+
//       4 byte              4 byte              2 byte
// length: 包大小
// sequence: 请求包的序号,新会话自1开始递增
// command: 协议号  
// frame: 具体Message序列化后的二进制数据

// 返回包与请求包格式一致,服务器主动推送包sequence为0,请求返回包sequence同请求包一致


// server 
// 113.10.201.102:3800

enum Proto {
    option allow_alias = true;
    UNKNOWN     = 0;
    PackSize    = 4;
    SeqIDSize   = 4;
    CommandSize = 2;
}


enum Command {
    // 主命令 (0 ~ 99)
    client_heart_beat     = 0;   // 心跳包..    -> AutoID  
    client_heart_beat_ack = 1;   // 心跳响应     -> AutoID   

    // 测试命令 (10000 ~)
    //test_any = 10001;
    test_oneof = 10002;
    test_map   = 10003;
    
}


message Test {
    // enum anyType {
    //    t_int64 = 0;   // AutoID
    //    t_str = 1;    // String
    // }
    // message Any {
    //    anyType type = 1;
    //    google.protobuf.Any body = 2;
    // }
    message Oneof {
        oneof test_oneof{
            string name = 1;
            int32 age = 2;
        }
    }
    message Map {
        map<uint32, double> body = 1;
    }
}


// 请求的通用回复
message CommonReply {
    enum Code {
        SUCCESS                   = 0;
        ERR_INVALID_PROTOCOL      = 1;
        ERR_INVALID_DATA          = 2; //客户端数据错误
        ERR_INVALID_OPERATION     = 3; //无效操作
        ERR_USER_UNUSABLE         = 6; //用户未激活
        ERR_ACCOUT_LOCK           = 7; //账户被锁定,禁止下注
        ERR_AUTHFAIL              = 401; //登录认证失败
        ERR_SERVER_INTERNAL_ERROR = 500; //服务端内部错误
    }
    Code code = 1;
    string desc = 2;
}


// 用于只传id或一个数字的结果, 如心跳, 大厅人数
message AutoID {
    int64 id = 1;
}
代码里的GameServerManager是一个websocket。
如果大家不了解websocket怎么使用,这里有我的下一篇文章,是和这篇protobuf衔接的。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值