-----pb和代码格式化
1.先下载llvm。 如: LLVM-12.0.0-6923b0a7-win64.exe
Release LLVM 17.0.6 · llvm/llvm-project (github.com)
2.安装2个插件 // pb高亮 和 跳转
3.修改vscode下的setting.json文件,设置保存时格式化代码 // 当然还有终端为gitbash
或者File->Preferences->Settings下修改setting.json // 点击文件时可以在ide中定位
{
"git.openRepositoryInParentFolders": "never",
// 保存时触发clang格式化
"editor.formatOnSave": true,
"window.openFilesInNewWindow": "on",
"explorer.autoReveal": "focusNoScroll",
"explorer.confirmDelete": false,
// 使用clang-format
"[proto3]": {
"editor.defaultFormatter": "xaver.clang-format"
},
"workbench.iconTheme": "vs-minimal",
"workbench.colorTheme": "Visual Studio Light",
"window.confirmSaveUntitledWorkspace": false,
"terminal.integrated.profiles.windows": {
"Git Bash": {
"path": "F:\\Git\\git-bash.exe",
// "path": "C:\\Program Files\\Git\\bin\\bash.exe",
"args": []
}
},
"terminal.integrated.defaultProfile.windows": "Git Bash"
}
4.配置下 .clang.format // 注意不要改下面}的位置
{BasedOnStyle: Google,
AlignConsecutiveDeclarations: true,
AlignConsecutiveAssignments: true,
ColumnLimit: 0,
IndentWidth: 4}
5.设置格式化为clang.format // 由于clang已经在安装时在path环境变量中了,因此无需再配置。
右键-->Format Document With..-->Configure Default Formatter...-->Clang Format
---------------------------------------------------------------------------
autoGen.sh
rm -rf out
mkdir out
# Java
protoc.exe --java_out=./out ./*.proto
# cocos
# pbjs -t static-module -w commonjs --es6 --keep-case --root comm -o ./out/login.js ./login.proto
# pbts -o ./out/login.d.ts ./out/login.js
echo "finish"
login.proto
syntax = "proto2";
package msg;
option java_package = "org.mj.bizserver.allmsg";
message CSLogin {
// 消息 Id
optional int32 msgId = 1;
}
----------------------20221227(思考proto文件的组织)-----------------
其实,我现在认为,作为工具的话,
common.proto // 定义的一些 Dxx类。模块之间是不会相互引用的。
101_200_mail.proto
201_300_friend.proto
这样子也没什么问题,在写工具类生成代码时,先生成临时文件,再进一步生成。
但实际上,是不够直观,也可以直接在proto文件中,指定导出的类名什么的,这种稍微看着别扭一点,但是实际也没什么问题,这样子写工具类简单了,无需中间文件。
-----------------20221101(在cocos creator中使用生成对应的.d.ts,使用typescript时有协议提示)----------------------
1.威海麻将中,安装下这个,就在本地得到node_modules
npm install --save-dev protobufjs@6.8.8
2.将protoc.exe和pbjs、pbts添加到环境变量中
// proto.exe
F:\pb
// pbjs 和 pbts 这2个node.js写的脚本
F:\pb\node_modules\.bin
3.autoGen.cmd
@echo off
rd /s/q .\out
md .\out
rem # Java
protoc --java_out=.\out .\commProtocol.proto
protoc --java_out=.\out .\passportServerProtocol.proto
protoc --java_out=.\out .\hallServerProtocol.proto
protoc --java_out=.\out .\MJ_weihai_Protocol.proto
protoc --java_out=.\out .\clubServerProtocol.proto
protoc --java_out=.\out .\chatServerProtocol.proto
protoc --java_out=.\out .\recordServerProtocol.proto
rem # JS
rem # 第二条命令可能不被执行,
rem # 直接复制粘贴到 DOS 命令行手动执行解决上面这个问题
set "_pbjs=node %NODE_HOME%\node_modules\protobufjs\bin\pbjs"
set "_pbts=node %NODE_HOME%\node_modules\protobufjs\bin\pbts"
%_pbjs% -t static-module -w commonjs --es6 --keep-case --root comm -o .\out\mod_commProtocol.js .\commProtocol.proto
%_pbts% -o .\out\mod_commProtocol.d.ts .\out\mod_commProtocol.js
%_pbjs% -t static-module -w commonjs --es6 --keep-case --root passportServer -o .\out\mod_passportServerProtocol.js .\passportServerProtocol.proto
%_pbts% -o .\out\mod_passportServerProtocol.d.ts .\out\mod_passportServerProtocol.js
%_pbjs% -t static-module -w commonjs --es6 --keep-case --root hallServer -o .\out\mod_hallServerProtocol.js .\hallServerProtocol.proto
%_pbts% -o .\out\mod_hallServerProtocol.d.ts .\out\mod_hallServerProtocol.js
%_pbjs% -t static-module -w commonjs --es6 --keep-case --root MJ_weihai_ -o .\out\mod_MJ_weihai_Protocol.js .\MJ_weihai_Protocol.proto
%_pbts% -o .\out\mod_MJ_weihai_Protocol.d.ts .\out\mod_MJ_weihai_Protocol.js
%_pbjs% -t static-module -w commonjs --es6 --keep-case --root clubServer -o .\out\mod_clubServerProtocol.js .\clubServerProtocol.proto
%_pbts% -o .\out\mod_clubServerProtocol.d.ts .\out\mod_clubServerProtocol.js
%_pbjs% -t static-module -w commonjs --es6 --keep-case --root chatServer -o .\out\mod_chatServerProtocol.js .\chatServerProtocol.proto
%_pbts% -o .\out\mod_chatServerProtocol.d.ts .\out\mod_chatServerProtocol.js
%_pbjs% -t static-module -w commonjs --es6 --keep-case --root recordServer -o .\out\mod_recordServerProtocol.js .\recordServerProtocol.proto
%_pbts% -o .\out\mod_recordServerProtocol.d.ts .\out\mod_recordServerProtocol.js
pause
4.这样子在当前目录下,生成mod_xxx.js和mod_xxx.d.ts
5.由于在proto文件中直接写的有syntax、package、option java_package,因此直接就生成的有java的。
syntax = "proto3";
package msg;
option java_package = "org.mj.bizserver.allmsg";
//
// 聊天服务器消息编号
enum ChatServerMsgCodeDef {
_Dummy = 0;
_SendQuickMsgCmd = 401;
_SendQuickMsgResult = 402;
_SendQuickMsgBroadcast = 403;
_SendEmojiCmd = 404;
_SendEmojiResult = 405;
_SendEmojiBroadcast = 406;
};
//
// 发送快速消息
///
// 指令
message SendQuickMsgCmd {
// 消息 Id
sint32 msgId = 1;
}
// 结果
message SendQuickMsgResult {
// 消息 Id
sint32 msgId = 1;
// 是否发送成功
bool ok = 2;
}
// 广播
message SendQuickMsgBroadcast {
// 消息来自用户 Id
sint32 fromUserId = 1;
// 消息 Id
sint32 msgId = 2;
// 是否发送成功
bool ok = 3;
}
//
// 发送表情
///
// 指令
message SendEmojiCmd {
// 表情 Id
sint32 emojiId = 1;
}
// 结果
message SendEmojiResult {
// 表情 Id
sint32 emojiId = 1;
// 是否发送成功
bool ok = 2;
}
// 广播
message SendEmojiBroadcast {
// 消息来自用户 Id
sint32 fromUserId = 1;
// 表情 Id
sint32 emojiId = 2;
// 是否发送成功
bool ok = 3;
}
-------------------------------------------之前写的服务器和客户端--------------------------------------
【服务器】java中使用protobuf 1.protoc.exe下载 2.build.sh编译脚本 3.vscode安装插件编辑game.proto(文件有颜色提示)
1)以windows为例子,将以下地址粘贴到浏览器下载64位的zip包,解压出proto.exe文件(各种语言都用这个编译脚本)
https://github.com/protocolbuffers/protobuf/releases/download/v3.14.0/protoc-3.14.0-win64.zip
github官网下载如下
2)pom.xml
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.10.0-rc-1</version>
</dependency>
3)在vscode下载插件写协议文件,有一定的语法着色
4)编译脚本build.sh(1.发现写成build.bat反而不行,改为sh则可以执行双击运行,直接生成msg下的文件!2.read命令阻塞那查看编译完成)
win版本build.sh例子(从proto.exe所在路径开始写相对路径,客户端只用关注protocol目录里面的相关的业务proto文件即可)
# 清空下之前的协议文件
rm -rf ./../src/main/java/org/example/msg
# 生成新文件
./protoc.exe ./protocol/*.proto ./options/*.proto --java_out=./../src/main/java
# 删除google生成的多余的文件
rm -rf ./../src/main/java/com
echo "编译完毕!"
read var
5)目录结构
idea中目录结构(只用关注protocol下的proto文件即可)
options.proto ( 自定义扩展,其中descriptor.proto自己从之前下载的proto工具中找到即可)
syntax= "proto2";
// 导出包名
option java_package="org.example.msg";
import "options/descriptor.proto";
extend google.protobuf.MessageOptions{
optional int32 msgid = 10001;
}
101_200_login.proto
syntax = "proto2";
option java_package = "org.example.msg";
// 导出类名
option java_outer_classname = "MsgLogin";
message DHuman {
optional string userName = 1; // 用户名
optional string password = 2; // 密码
}
202_300_game.proto
syntax = "proto2";
option java_package = "org.example.msg";
// 导出类名
option java_outer_classname = "MsgGame";
// 引入其它proto文件,以使用DLogin(其实这里不应该出现这种一个模块引入另一个模块的写法
// 公共的东西只应该有Dxxx这种公用数据,应该定义在common.proto文件中)
import "protocol/101_200_login.proto";
import "options/options.proto";
// 开始战斗
message CSStartBattle {
option (msgid) = 101;
optional DHuman info = 1;
}
message SCStartBattle {
optional EStatus status = 1; // 开始状态
}
enum EStatus{
OK = 1;
FAIL = 2;
}
Main.java(注意下获取msgid的方式)
package org.example;
import com.google.protobuf.GeneratedMessageV3;
import org.example.msg.MsgGame;
import org.example.msg.MsgLogin;
import org.example.msg.Options;
public class Main {
public static void main(String[] args) throws Exception {
MsgGame.CSStartBattle.Builder builder = MsgGame.CSStartBattle.newBuilder();
builder.setInfo(MsgLogin.DHuman.newBuilder().setUserName("jianan").setPassword("123456").build());
// 获取里面自定义的msgid
Class<?>[] innerClazzArray = MsgGame.class.getDeclaredClasses();
for (Class<?> innerClazz : innerClazzArray) {
if (!GeneratedMessageV3.class.isAssignableFrom(innerClazz)) {
continue;
}
GeneratedMessageV3 returnObj = (GeneratedMessageV3) innerClazz.getDeclaredMethod("getDefaultInstance").invoke(innerClazz);
// 默认是0
int msgId = returnObj.getDescriptorForType().getOptions().getExtension(Options.msgid);
if (msgId != 0) {
System.out.println("msgid:" + msgId);
// 存储自定义消息id与消息的映射关系
}
}
// 得到消息号
int msgCode = builder.build().getDescriptorForType().getOptions().getExtension(Options.msgid);
// 编码为字节码
byte[] bytes = builder.build().toByteArray();
System.out.println("msgCode:" + msgCode);
System.out.println(bytes);
}
}
/*
msgid:101
msgCode:101
[B@5e57643e
*/
【客户端】 creator中使用protobuf: 1.需要导入pb为插件 2.使用protobuf.min.js 3.命令号enum的获取
1)下载地址
https://github.com/protobufjs/protobuf.js/tree/master/dist
2)game.proto
// awesome.proto
package awesomepackage;
syntax = "proto3";
enum Cmd{
INVALID_CMD = 0;
AwesomeMessage = 1;
}
message AwesomeMessage {
string awesome_field = 1; // becomes awesomeField
}
3)creator 1.9.1
cc.loader.loadRes("awesome.proto", function (err, data) {
if (err) {
return;
}
// 读到文本内容,解析为pb脚本
let pb = protobuf.parse(data);
// 获取类型
var AwesomeMessage = pb.root.lookupType("AwesomeMessage");
// 构造消息
var payload = {awesomeField: "AwesomeString"};
// json编码
console.log("字符串长度:", JSON.stringify(payload).length);
// pb编码
var message = AwesomeMessage.create(payload);
var buffer = AwesomeMessage.encode(message).finish();
console.log("pb后长度:", buffer.length);
// 解码
var message = AwesomeMessage.decode(buffer);
console.log(message);
// 通过枚举输出命令号
let Cmd = pb.root.lookupEnum("Cmd").values;
console.log(Cmd.AwesomeMessage);
});
注意: 文档中只有node,js的加载用法, creator中读取资源要用自己的方法。
----------------------
由于导入为插件了,不需要require protobuf的东西直接通过protobuf.xxx即可引用
// var ProtoBuf = require('protobufjs');
var builder = protobuf.parse("syntax = \"proto3\"; \npackage yd;\n\nmessage data{\nstring y = 1;\nstring d = 2;\n}");
if(typeof(cc.TONGXIN) == "undefined"){
cc.TONGXIN = {
// AwesomeMessage : builder.build("yd"),
AwesomeMessage : builder.valueOf("yd"),
wslink :"ws://127.0.0.1:8889/Ws",
jishi: 0, //计数
yeschushi:false,// 是否初始化
timeout:8000, //80秒没连接推出
restart:200,// 2秒重练一次
run:0.01, //执行间隔
wsdata:Array(),//队列数据
isliank:false//是否连接
};
}