当前位置: 首页 > news >正文

网站建设在微信里打广告内容黄冈网站搭建推荐

网站建设在微信里打广告内容,黄冈网站搭建推荐,海城百度公司 海城网站建设,网站上线前营销推广工作准备文章目录简介Protobuf 语法规则Proto Editor实现创建窗口定义类、字段增删类编辑字段导入、导出Json文件生成.proto文件生成.bat文件简介 在Socket网络编程中,假如使用Protobuf作为网络通信协议,需要了解Protobuf语法规则、编写.proto文件并通过编译指令…

文章目录

  • 简介
    • Protobuf 语法规则
    • Proto Editor
  • 实现
    • 创建窗口
    • 定义类、字段
    • 增删类
    • 编辑字段
    • 导入、导出Json文件
    • 生成.proto文件
    • 生成.bat文件


简介

Socket网络编程中,假如使用Protobuf作为网络通信协议,需要了解Protobuf语法规则、编写.proto文件并通过编译指令将.proto文件转化为.cs脚本文件,本文介绍如何在Unity中实现一个编辑器工具来使开发人员不再需要关注这些语法规则、编译指令,以及更便捷的编辑和修改.proto文件内容。工具已上传至SKFramework框架Package Manager中:

SKFramework PackageManager

Protobuf 语法规则

在介绍工具之前先简单介绍protobuf的语法规则,以便更好的理解工具的作用,下面是一个proto文件的示例:

message AvatarProperty
{required string userId = 1;required float posX = 2;required float posY = 3;required float posZ = 4;required float rotX = 5;required float rotY = 6;required float rotZ = 7;required float speed = 8;
}
  • 类通过message来声明,后面是类的命名
  • 字段修饰符包含三种类型:
    • required : 不可增加或删除的字段,必须初始化
    • optional : 可选字段,可删除,可以不初始化
    • repeated : 可重复字段(对应C#里面的List)
  • 与C#的字段类型对应关系如下,查阅自官网
.proto TypeC# TypeNotes
doubledouble
floatfloat
int32intUses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead.
int64longUses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead.
uint32uintUses variable-length encoding.
uint64ulongUses variable-length encoding.
sint32intUses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s.
sint64longUses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s.
fixed32uintAlways four bytes. More efficient than uint32 if values are often greater than 228.
fixed64ulongAlways eight bytes. More efficient than uint64 if values are often greater than 256.
sfixed32intAlways four bytes.
sfixed64longAlways eight bytes.
boolbool
stringstringA string must always contain UTF-8 encoded or 7-bit ASCII text, and cannot be longer than 232.
bytesByteStringMay contain any arbitrary sequence of bytes no longer than 232.
  • 标识号:示例中的1-8表示每个字段的标识号,并不是赋值。

每个字段都有唯一的标识号,这些标识符是用来在消息的二进制格式中识别各个字段的。[1,15]之内的标识号在编码的时候会占用一个字节。[16,2047]之内的标识号则占用2个字节。所以应该为那些频繁出现的消息元素保留[1,15]之内的标识号。:要为将来有可能添加的、频繁出现的标识号预留一些标识号,不可以使用其中的[19000-19999]标识号,Protobuf协议实现中对这些进行了预留。

Proto Editor

Proto Editor

如图所示,工具包含以下功能:

  • New、Clear Message:增加、删除message类;

New、Clear Message

  • 增加、删除、编辑fields字段(修饰符、类型、命名、分配标识号);

增删字段

  • Import、Export Json File:导入、导出json文件(假如要修改一个已有的通信协议类,导入之前导出的Json文件再次编辑即可);

Import Json File

  • Generate Proto File:生成.proto文件;
  • Create .bat:生成.bat文件(不再需要手动编辑编译指令)。

生成的.proto & .bat文件

实现

创建窗口

  • 继承Editor Window编辑器窗口类;
  • Menu Item添加打开窗口的菜单;
public class ProtoEditor : EditorWindow
{[MenuItem("Multiplayer/Proto Editor")]public static void Open(){GetWindow<ProtoEditor>("Proto Editor").Show();}
}

定义类、字段

/// <summary>
/// 类
/// </summary>
public class Message
{/// <summary>/// 类名/// </summary>public string name = "New Message";/// <summary>/// 所有字段/// </summary>public List<Fields> fieldsList = new List<Fields>(0);
}
/// <summary>
/// 字段
/// </summary>
public class Fields
{public ModifierType modifier;public FieldsType type;public string typeName;public string name;public int flag;
}
  • Modifer Type:修饰符类型
/// <summary>
/// 修饰符类型
/// </summary>
public enum ModifierType
{/// <summary>/// 必需字段/// </summary>Required,/// <summary>/// 可选字段/// </summary>Optional,/// <summary>/// 可重复字段/// </summary>Repeated
}
  • Fields Type:字段类型

这里只定义了我常用的几种类型,Custom用于自定义类型:

/// <summary>
/// 字段类型
/// </summary>
public enum FieldsType
{Double,Float,Int,Long,Bool,String,Custom,
}

增删类

  • 声明一个列表存储所有类
//存储所有类
private List<Message> messages = new List<Message>();
  • 声明一个字典用于存储折叠栏状态(每个类可折叠查看)
//字段存储折叠状态
private readonly Dictionary<Message, bool> foldoutDic = new Dictionary<Message, bool>();
  • 插入、删除
//滚动视图
scroll = GUILayout.BeginScrollView(scroll);
for (int i = 0; i < messages.Count; i++)
{var message = messages[i];GUILayout.BeginHorizontal();foldoutDic[message] = EditorGUILayout.Foldout(foldoutDic[message], message.name, true);//插入新类if (GUILayout.Button("+", GUILayout.Width(20f))){Message insertMessage = new Message();messages.Insert(i + 1, insertMessage);foldoutDic.Add(insertMessage, true);Repaint();return;}//删除该类if (GUILayout.Button("-", GUILayout.Width(20f))){messages.Remove(message);foldoutDic.Remove(message);Repaint();return;}GUILayout.EndHorizontal();
}
GUILayout.EndScrollView();
  • 底部新增、清空菜单:
GUILayout.BeginHorizontal();
//创建新的类
if (GUILayout.Button("New Message"))
{Message message = new Message();messages.Add(message);foldoutDic.Add(message, true);
}
//清空所有类
if (GUILayout.Button("Clear Messages"))
{//确认弹窗if (EditorUtility.DisplayDialog("Confirm", "是否确认清空所有类型?", "确认", "取消")){//清空messages.Clear();foldoutDic.Clear();//重新绘制Repaint();}
}
GUILayout.EndHorizontal();

编辑字段

  • 折叠栏为打开状态时,绘制该类具体的字段:
//如果折叠栏为打开状态 绘制具体字段内容
if (foldoutDic[message])
{//编辑类名message.name = EditorGUILayout.TextField("Name", message.name);//字段数量为0 提供按钮创建if (message.fieldsList.Count == 0){if (GUILayout.Button("New Field")){message.fieldsList.Add(new Fields(1));}}else{for (int j = 0; j < message.fieldsList.Count; j++){var item = message.fieldsList[j];GUILayout.BeginHorizontal();//修饰符类型item.modifier = (ModifierType)EditorGUILayout.EnumPopup(item.modifier);//字段类型item.type = (FieldsType)EditorGUILayout.EnumPopup(item.type);if (item.type == FieldsType.Custom){item.typeName = GUILayout.TextField(item.typeName);}//编辑字段名item.name = EditorGUILayout.TextField(item.name);GUILayout.Label("=", GUILayout.Width(15f));//分配标识号item.flag = EditorGUILayout.IntField(item.flag, GUILayout.Width(50f));//插入新字段if (GUILayout.Button("+", GUILayout.Width(20f))){message.fieldsList.Insert(j + 1, new Fields(message.fieldsList.Count + 1));Repaint();return;}//删除该字段if (GUILayout.Button("-", GUILayout.Width(20f))){message.fieldsList.Remove(item);Repaint();return;}GUILayout.EndHorizontal();}}
}

导入、导出Json文件

  • 导出Json文件以及生成Proto文件之前都需要判断当前的编辑是否有效,从以下几个方面判断:
    • proto file name:文件名编辑是否输入为空;
    • message name:类名编辑是否输入为空;
    • 自定义字段类型时,是否输入为空;
    • 标识号是否唯一 。

为Message、Fields类添加有效性判断函数:

/// <summary>
/// 类
/// </summary>
public class Message
{/// <summary>/// 类名/// </summary>public string name = "New Message";/// <summary>/// 所有字段/// </summary>public List<Fields> fieldsList = new List<Fields>(0);public bool IsValid(){bool flag = !string.IsNullOrEmpty(name);for (int i = 0; i < fieldsList.Count; i++){flag &= fieldsList[i].IsValid();if (!flag) return false;for (int j = 0; j < fieldsList.Count; j++){if (i != j){flag &= fieldsList[i].flag != fieldsList[j].flag;}if (!flag) return false;}}return flag;}
}
/// <summary>
/// 字段
/// </summary>
public class Fields
{public ModifierType modifier;public FieldsType type;public string typeName;public string name;public int flag;public Fields() { }public Fields(int flag){modifier = ModifierType.Required;type = FieldsType.String;name = "FieldsName";typeName = "FieldsType";this.flag = flag;}public bool IsValid(){return type != FieldsType.Custom || (type == FieldsType.Custom && !string.IsNullOrEmpty(typeName));}
}
  • 最终编辑有效性判断:
//编辑的内容是否有效
private bool ContentIsValid()
{bool flag = !string.IsNullOrEmpty(fileName);flag &= messages.Count > 0;for (int i = 0; i < messages.Count; i++){flag &= messages[i].IsValid();if (!flag) break;}return flag;
}
  • 导入、导出Json:

GUILayout.BeginHorizontal();
//导出Json
if (GUILayout.Button("Export Json File"))
{if (!ContentIsValid()){EditorUtility.DisplayDialog("Error", "请按以下内容逐项检查:\r\n1.proto File Name是否为空\r\n2.message类名是否为空\r\n" +"3.字段类型为自定义时 是否填写了类型名称\r\n4.标识号是否唯一", "ok");}else{//文件夹路径string dirPath = Application.dataPath + workspacePath;//文件夹不存在则创建if (!Directory.Exists(dirPath))Directory.CreateDirectory(dirPath);//json文件路径string filePath = dirPath + "/" + fileName + ".json";if (EditorUtility.DisplayDialog("Confirm", "是否保存当前编辑内容到" + filePath, "确认", "取消")){//序列化string json = JsonMapper.ToJson(messages);//写入File.WriteAllText(filePath, json);//刷新AssetDatabase.Refresh();}}
}
//导入Json
if (GUILayout.Button("Import Json File"))
{//选择json文件路径string filePath = EditorUtility.OpenFilePanel("Import Json File", Application.dataPath + workspacePath, "json");//判断路径有效性if (File.Exists(filePath)){//读取json内容string json = File.ReadAllText(filePath);//清空messages.Clear();foldoutDic.Clear();//反序列化messages = JsonMapper.ToObject<List<Message>>(json);//填充字典for (int i = 0; i < messages.Count; i++){foldoutDic.Add(messages[i], true);}//文件名称FileInfo fileInfo = new FileInfo(filePath);fileName = fileInfo.Name.Replace(".json", "");//重新绘制Repaint();return;}
}
GUILayout.EndHorizontal();

生成.proto文件

主要是字符串拼接工作:

//生成proto文件
if (GUILayout.Button("Generate Proto File"))
{if (!ContentIsValid()){EditorUtility.DisplayDialog("Error", "请按以下内容逐项检查:\r\n1.proto File Name是否为空\r\n2.message类名是否为空\r\n" +"3.字段类型为自定义时 是否填写了类型名称\r\n4.标识号是否唯一", "ok");}else{string protoFilePath = EditorUtility.SaveFilePanel("Generate Proto File", Application.dataPath, fileName, "proto");if (!string.IsNullOrEmpty(protoFilePath)){StringBuilder protoContent = new StringBuilder();for (int i = 0; i < messages.Count; i++){var message = messages[i];StringBuilder sb = new StringBuilder();sb.Append("message " + message.name + "\r\n" + "{\r\n");for (int n = 0; n < message.fieldsList.Count; n++){var field = message.fieldsList[n];//缩进sb.Append("    ");//修饰符sb.Append(field.modifier.ToString().ToLower());//空格sb.Append(" ");//如果是自定义类型 拼接typeName switch (field.type){case FieldsType.Int: sb.Append("int32"); break;case FieldsType.Long: sb.Append("int64"); break;case FieldsType.Custom: sb.Append(field.typeName); break;default: sb.Append(field.type.ToString().ToLower()); break;}//空格sb.Append(" ");//字段名sb.Append(field.name);//等号sb.Append(" = ");//标识号sb.Append(field.flag);//分号及换行符sb.Append(";\r\n");}sb.Append("}\r\n");protoContent.Append(sb.ToString());}//写入文件File.WriteAllText(protoFilePath, protoContent.ToString());//刷新(假设路径在工程内 可以避免手动刷新才看到)AssetDatabase.Refresh();//打开该文件夹FileInfo fileInfo = new FileInfo(protoFilePath);Process.Start(fileInfo.Directory.FullName);}}
}

生成.bat文件

  • 使用OpenFolderPanel打开protogen.exe文件所在的文件夹,.bat文件需要生成在该文件夹下:

protogen.exe

  • 获取proto文件夹下的所有.proto文件的名称,拼接编译指令:
//创建.bat文件
if (GUILayout.Button("Create .bat"))
{//选择路径(protogen.exe所在的文件夹路径)string rootPath = EditorUtility.OpenFolderPanel("Create .bat file(protogen.exe所在的文件夹)", Application.dataPath, string.Empty);//取消if (string.IsNullOrEmpty(rootPath)) return;//protogen.exe文件路径string protogenPath = rootPath + "/protogen.exe";//不是protogen.exe所在的文件夹路径if (!File.Exists(protogenPath)){EditorUtility.DisplayDialog("Error", "请选择protogen.exe所在的文件夹路径", "ok");}else{string protoPath = rootPath + "/proto";DirectoryInfo di = new DirectoryInfo(protoPath);//获取所有.proto文件信息FileInfo[] protos = di.GetFiles("*.proto");//使用StringBuilder拼接字符串StringBuilder sb = new StringBuilder();//遍历for (int i = 0; i < protos.Length; i++){string proto = protos[i].Name;//拼接编译指令sb.Append(rootPath + @"/protogen.exe -i:proto\" + proto + @" -o:cs\" + proto.Replace(".proto", ".cs") + "\r\n");}sb.Append("pause");//生成".bat文件"string batPath = $"{rootPath}/run.bat";File.WriteAllText(batPath, sb.ToString());//打开该文件夹Process.Start(rootPath);}
}

最终运行.bat文件,就可以将.proto文件转化为.cs脚本文件:

运行.bat文件

http://www.mmbaike.com/news/109486.html

相关文章:

  • 怎么做导购网站电脑优化软件
  • 医疗营销型网站建设郑州seo哪家好
  • 专业机票网站建设网站seo优化工具
  • 手机网站开发专业友情链接推广平台
  • 网站建设怎样设置动态背景网站推广和网络推广
  • 网页美工设计什么百度seo关键词优化公司
  • 网站建设 制作公司推广平台下载
  • 如何选择网站建设百度最容易收录的网站
  • 成都网站建设排名网页设计图片
  • 宝鸡手机版网站建设最有效的宣传方式
  • 网站怎么免费注册网站推广计划方法
  • 网站开发毕业答辩如何线上推广引流
  • 什么网站可以免费做兼职网络营销课程个人总结3000字
  • 为什么做红酒网站网络营销包括
  • 网站维护主要做哪些爱站网长尾词挖掘
  • wordpress 后台禁用长沙官网seo分析
  • 曰本做爰网站登录百度账号
  • 网络客服做彩票网站的百度怎么注册自己的店铺
  • 重庆如何快速制作一个网站seo搜索引擎优化书籍
  • 免费网页设计整套模板网站优化一年多少钱
  • 软件开发的步骤流程网上seo研究
  • wordpress自带主题有什么用广州网站优化平台
  • 设计用哪些网站有哪些功能市场调研的方法有哪些
  • 学校网页网站模板百度推广时间段在哪里设置
  • 做网站功能模块seo推广优势
  • 哪个网站做ppt好百度快速排名软件原理
  • 公司手机网站制作福州网站seo优化公司
  • 有没有做西餐的视频网站批量外链工具
  • 网站代码结构美国疫情最新情况
  • 生鲜网站建设规划书样板下载app到手机上并安装