欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 高考 > 【Unity网络编程知识】自定义消息协议和自动生成协议工具

【Unity网络编程知识】自定义消息协议和自动生成协议工具

2025/5/21 13:05:42 来源:https://blog.csdn.net/zhoutao2333/article/details/148087429  浏览:    关键词:【Unity网络编程知识】自定义消息协议和自动生成协议工具

1、消息(协议)规则制定

数据结构类基类

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;public abstract class BaseData
{/// <summary>/// 用于子类重写的 获取字节数组容器大小的方法/// </summary>/// <returns></returns>public abstract int GetBytesNum();/// <summary>/// 把成员变量序列化为 对应的字节数组/// </summary>/// <returns></returns>public abstract byte[] Writing();/// <summary>/// 把二进制字节数组 反序列化 到成员变量当中/// </summary>/// <param name="bytes">反序列化使用的字节数组</param>/// <param name="beginIndex">从该字节数组的第几个位置开始解析 默认是 0</param>public abstract int Reading(byte[] bytes, int beginIndex = 0);/// <summary>/// 存储int类型变量到指定的字节数组/// </summary>/// <param name="bytes">指定字节数组</param>/// <param name="value">具体的int值</param>/// <param name="index">每次存储后用于记录当前索引位置的变量</param>protected void WriteInt(byte[] bytes, int value, ref int index){BitConverter.GetBytes(value).CopyTo(bytes, index);index += sizeof(int);}protected void WriteShort(byte[] bytes, short value, ref int index){BitConverter.GetBytes(value).CopyTo(bytes, index);index += sizeof(short);}protected void WriteLong(byte[] bytes, long value, ref int index){BitConverter.GetBytes(value).CopyTo(bytes, index);index += sizeof(long);}protected void WriteFloat(byte[] bytes, float value, ref int index){BitConverter.GetBytes(value).CopyTo(bytes, index);index += sizeof(float);}protected void WriteByte(byte[] bytes, byte value, ref int index){bytes[index] = value;index += sizeof(byte);}protected void WriteBool(byte[] bytes, bool value, ref int index){BitConverter.GetBytes(value).CopyTo(bytes, (int)index);index += sizeof(bool);}protected void WriteString(byte[] bytes, string value, ref int index){//先存储string字节数组长度byte[] strBytes = Encoding.UTF8.GetBytes(value);int num = strBytes.Length;BitConverter.GetBytes(num).CopyTo(bytes, index);index += sizeof(int);//在存储 string 字节数组strBytes.CopyTo(bytes, index);index += num;}protected void WriteData(byte[] bytes, BaseData data, ref int index){data.Writing().CopyTo(bytes, index);index += data.GetBytesNum();}/// <summary>/// 根据字节数组读取整形/// </summary>/// <param name="bytes">读取数组</param>/// <param name="index">开始读取的索引位置</param>/// <returns></returns>protected int ReadInt(byte[] bytes, ref int index){int value = BitConverter.ToInt32(bytes, index);index += sizeof(int);return value;}protected short ReadShort(byte[] bytes, ref int index){short value = BitConverter.ToInt16(bytes, index);index += sizeof(short);return value;}protected long ReadLong(byte[] bytes, ref int index){long value = BitConverter.ToInt64(bytes, index);index += sizeof(long);return value;}protected float ReadFloat(byte[] bytes, ref int index){float value = BitConverter.ToSingle(bytes, index);index += sizeof(float);return value;}protected byte ReadByte(byte[] bytes, ref int index){byte b = bytes[index];index++;return b;}protected bool ReadBool(byte[] bytes, ref int index){bool value = BitConverter.ToBoolean(bytes, index);index += sizeof(bool);return value;}protected string ReadString(byte[] bytes, ref int index){int length = BitConverter.ToInt32(bytes, index);index += sizeof(int);string value = Encoding.UTF8.GetString(bytes, index, length);index += length;return value;}protected T ReadData<T>(byte[] bytes, ref int index) where T : BaseData, new(){T value = new T();index += value.Reading(bytes, index);return value;}}

消息类基类

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class BaseMsg : BaseData
{public override int GetBytesNum(){throw new System.NotImplementedException();}public override int Reading(byte[] bytes, int beginIndex = 0){throw new System.NotImplementedException();}public override byte[] Writing(){throw new System.NotImplementedException();}public virtual int GetID(){return 0;}
}

 2、消息类使用方法

2.1 创建数据类,继承数据结构基类

根据成员变量实现方法GetBytesNum,Reading,Writing

using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;/// <summary>
/// 玩家数据类
/// </summary>
public class PlayerData : BaseData
{public string name;public int atk;public int lev;public override int GetBytesNum(){return 4 + 4 + 4 + Encoding.UTF8.GetBytes(name).Length;}public override int Reading(byte[] bytes, int beginIndex = 0){int index = beginIndex;name = ReadString(bytes, ref index);atk = ReadInt(bytes, ref index);lev = ReadInt(bytes, ref index);return index - beginIndex;}public override byte[] Writing(){int index = 0;byte[] bytes = new byte[GetBytesNum()];WriteString(bytes, name, ref index);WriteInt(bytes, atk, ref index);WriteInt(bytes, lev, ref index);return bytes;}
}

2.2 创建消息类,继承消息类基类

消息类需要根据成员变量实现方法GetBytesNum,Reading,Writing,GetID

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class PlayerMsg : BaseMsg
{public int playerID;public PlayerData playerData;public override byte[] Writing(){int index = 0;int bytesNum = GetBytesNum();byte[] bytes = new byte[bytesNum];//先写消息IDWriteInt(bytes, GetID(), ref index);//写入消息体长度 我们-8的目的 是只存储消息体的长度 前面8个字节 是我们字节定制的规则 解析时按照这个规则处理就行了WriteInt(bytes, bytesNum - 8, ref index);//写消息的成员变量WriteInt(bytes, playerID, ref index);WriteData(bytes, playerData, ref index);return bytes;}public override int Reading(byte[] bytes, int beginIndex = 0){//反序列化不需要取解析ID 因为在这一步之前 就应该把ID反序列化出来//用来判断到底使用哪一个自定义类来反序列化int index = beginIndex;playerID = ReadInt(bytes, ref index);playerData = ReadData<PlayerData>(bytes, ref index);return index - beginIndex;}public override int GetBytesNum(){return 4 + //消息ID长度4 + //消息体的长度4 + //palyerIDplayerData.GetBytesNum(); //playerData}/// <summary>/// 自定义的消息ID 主要用于区分是哪一个消息类/// </summary>/// <returns></returns>public override int GetID(){return 1001;}
}

2.3 发送消息,首先创建消息类实例,使用方法Writing()获取字节数组,将字节数组发送出去

                PlayerMsg ms = new PlayerMsg();ms.playerID = 123123;ms.playerData = new PlayerData();ms.playerData.name = "hellow";ms.playerData.atk = 0;ms.playerData.lev = 1;ms.Writing();

2.4 接受消息,收到消息字节数组,先解析消息ID,根据ID使用具体消息类Reading()解析消息

        //首先解析消息的IDint msgID = BitConverter.ToInt32(receiveBytes, 0);switch (msgID){case 1001:PlayerMsg msg = new PlayerMsg();msg.Reading(receiveBytes, 4);Debug.Log(msg.playerID);Debug.Log(msg.playerData.name);Debug.Log(msg.playerData.atk);Debug.Log(msg.playerData.lev);break;default:break;}

3、创建配置工具自动生成脚本

3.1 使用xml文件进行配置,规则如下

<?xml version="1.0" encoding="UTF-8"?>
<messages><!--枚举配置规则--><enum name="E_PLAYER_TYPE" namespace="GamePlayer"><field name="MAIN">1</field><field name="OTHER"/></enum><enum name="E_MONSTER_TYPE" namespace="GameMonster"><field name="NORMAL">2</field><field name="BOSS"/></enum><!--数据结构类配置规则--><data name="PlayerData" namespace="GamePlayer"><field type="int" name="id" /><field type="float" name="atk" /><field type="long" name="lev" /><field type="array" name="arrays" /><field type="list" T="int" name="list" /><field type="dic" Tkey="int" Tvalue="string" name="dic" /></data><!--消息类配置规则--><message id="1001" name="PlayerMeg" namespace="GamePlayer"><field type="int" name="playerID" /><field type="PlayerData" name="data" /></message><message id="1002" name="HeartMsg" namespace="GameSystem"/>
</messages>

3.2 工具类功能实现脚本

ProtocolTool

using System.Collections;
using System.Collections.Generic;
using System.Xml;
using UnityEditor;
using UnityEngine;public class ProtocolTool
{//配置文件所在路径private static string PROTO_INFO_PATH = Application.dataPath + "/Editor/ProtocolTool/ProtocolInfo.xml";private static GeneraterCSharp generateCSharp = new GeneraterCSharp();[MenuItem("ProtocolTool/生成C#脚本")]private static void GeneraterCSharp(){//1.读取xml相关的信息//XmlNodeList list = GetNodes("enum");//2.根据这些信息 拼接字符串 生成对应的脚本//生成对应的枚举脚本generateCSharp.GenerateEnum(GetNodes("enum"));//生成对应的数据结构类脚本generateCSharp.GenerateData(GetNodes("data"));//生成对应的消息类脚本generateCSharp.GenerateMsg(GetNodes("message"));//刷新编辑器界面AssetDatabase.Refresh();}[MenuItem("ProtocolTool/生成C++脚本")]private static void GeneraterC(){Debug.Log("生成C++代码");}[MenuItem("ProtocolTool/生成Java脚本")]private static void GeneraterJava(){Debug.Log("生成Java代码");}/// <summary>/// 获取指定名字的所有子节点 的 List/// </summary>/// <param name="nodeName"></param>/// <returns></returns>private static XmlNodeList GetNodes(string nodeName){XmlDocument xml = new XmlDocument();xml.Load(PROTO_INFO_PATH);XmlNode root = xml.SelectSingleNode("messages");return root.SelectNodes(nodeName);}}

 GeneraterCSharp

using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using UnityEngine;public class GeneraterCSharp
{//协议保存路径private string SAVA_PATH = Application.dataPath + "/Scripts/Protocol/";//生成枚举public void GenerateEnum(XmlNodeList nodes){//生成枚举脚本的逻辑string namespaceStr = "";string enumNameStr = "";string fieldStr = "";foreach (XmlNode enumNode in nodes){//获取命名空间配置信息namespaceStr = enumNode.Attributes["namespace"].Value;//获取枚举名配置信息enumNameStr = enumNode.Attributes["name"].Value;//获取所有的字段节点 然后进行字符串拼接XmlNodeList enumFields = enumNode.SelectNodes("field");//一个新的枚举需要清空上一次拼接字符串fieldStr = "";foreach (XmlNode enumField in enumFields){fieldStr += "\t\t" + enumField.Attributes["name"].Value;if (enumField.InnerText != "")fieldStr += " = " + enumField.InnerText;fieldStr += ",\r\n";}//对所有可变的内容进行拼接string enumStr = $"namespace {namespaceStr}\r\n" +"{\r\n" +$"\tpublic enum {enumNameStr}\r\n" +"\t{\r\n" +$"{fieldStr}" +"\t}\r\n" +"}";//保存文件路径string path = SAVA_PATH + namespaceStr + "/Enum/";//如果不存在这个文件夹 则创建if(!Directory.Exists(path))Directory.CreateDirectory(path);//字符串保存 存储为枚举脚本文件File.WriteAllText(path + enumNameStr + ".cs", enumStr);}Debug.Log("枚举生成结束");}//生成数据结构类public void GenerateData(XmlNodeList nodes){string namespaceStr = "";string classNameStr = "";string fieldStr = "";string getBytesNumFunStr = "";string writingFunStr = "";string readingFunStr = "";foreach (XmlNode dataNode in nodes){//命名空间namespaceStr = dataNode.Attributes["namespace"].Value;//类名classNameStr = dataNode.Attributes["name"].Value;XmlNodeList fields = dataNode.SelectNodes("field");//通过该方法将成员变量进行拼接完成fieldStr = GetFieldStr(fields);//通过方法 对GetBytesNum函数进行拼接 返回结果getBytesNumFunStr = GetBytesNumFunSre(fields);//通过方法 对Writing函数进行拼接 返回结果writingFunStr = GetWritingFunStr(fields);//通过方法 对Reading函数进行拼接 返回结果readingFunStr = GetReadingFunStr(fields);string dataStr = "using System;\r\nusing System.Collections;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\n\r\n" +$"namespace {namespaceStr}\r\n" +"{\r\n" +$"\tpublic class {classNameStr} : BaseMsg\r\n" +"\t{\r\n" +fieldStr +"\t\tpublic override int GetBytesNum()\r\n" +"\t\t{\r\n" +"\t\t\tint num = 0;\r\n" +getBytesNumFunStr +"\t\t\treturn num;\r\n" +"\t\t}\r\n" +"\t\tpublic override byte[] Writing()\r\n" +"\t\t{\r\n" +"\t\t\tint index = 0;\r\n" +"\t\t\tbyte[] bytes = new byte[GetBytesNum()];\r\n" +writingFunStr +"\t\t\treturn bytes;\r\n" +"\t\t}\r\n" +"\t\tpublic override int Reading(byte[] bytes, int beginIndex = 0)\r\n" +"\t\t{\r\n" +"\t\t\tint index = beginIndex;\r\n" +readingFunStr +"\t\t\treturn index - beginIndex;\r\n" +"\t\t}\r\n" +"\t}\r\n" +"}\r\n";//保存文件路径string path = SAVA_PATH + namespaceStr + "/Data/";//如果不存在这个文件夹 则创建if (!Directory.Exists(path))Directory.CreateDirectory(path);//字符串保存 存储为枚举脚本文件File.WriteAllText(path + classNameStr + ".cs", dataStr);}Debug.Log("数据结构类生成结束");}//生成消息类public void GenerateMsg(XmlNodeList nodes){string isStr = "";string namespaceStr = "";string classNameStr = "";string fieldStr = "";string getBytesNumFunStr = "";string writingFunStr = "";string readingFunStr = "";foreach (XmlNode dataNode in nodes){isStr = dataNode.Attributes["id"].Value;//命名空间namespaceStr = dataNode.Attributes["namespace"].Value;//类名classNameStr = dataNode.Attributes["name"].Value;XmlNodeList fields = dataNode.SelectNodes("field");//通过该方法将成员变量进行拼接完成fieldStr = GetFieldStr(fields);//通过方法 对GetBytesNum函数进行拼接 返回结果getBytesNumFunStr = GetBytesNumFunSre(fields);//通过方法 对Writing函数进行拼接 返回结果writingFunStr = GetWritingFunStr(fields);//通过方法 对Reading函数进行拼接 返回结果readingFunStr = GetReadingFunStr(fields);string dataStr = "using System;\r\nusing System.Collections;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\n\r\n" +$"namespace {namespaceStr}\r\n" +"{\r\n" +$"\tpublic class {classNameStr} : BaseMsg\r\n" +"\t{\r\n" +fieldStr +"\t\tpublic override int GetBytesNum()\r\n" +"\t\t{\r\n" +"\t\t\tint num = 8;\r\n" +//这个8代表的是 消息ID的4个字节 + 消息体长度的4个字节getBytesNumFunStr +"\t\t\treturn num;\r\n" +"\t\t}\r\n" +"\t\tpublic override byte[] Writing()\r\n" +"\t\t{\r\n" +"\t\t\tint index = 0;\r\n" +"\t\t\tbyte[] bytes = new byte[GetBytesNum()];\r\n" +"\t\t\tWriteInt(bytes, GetID(), ref index);\r\n" +"\t\t\tWriteInt(bytes, bytes.Length - 8, ref index);\r\n" +writingFunStr +"\t\t\treturn bytes;\r\n" +"\t\t}\r\n" +"\t\tpublic override int Reading(byte[] bytes, int beginIndex = 0)\r\n" +"\t\t{\r\n" +"\t\t\tint index = beginIndex;\r\n" +readingFunStr +"\t\t\treturn index - beginIndex;\r\n" +"\t\t}\r\n" +"\t\tpublic override int GetID()\r\n" +"\t\t{\r\n" +"\t\t\treturn " + isStr + ";\r\n" +"\t\t}\r\n" +"\t}\r\n" +"}\r\n";//保存文件路径string path = SAVA_PATH + namespaceStr + "/Msg/";//如果不存在这个文件夹 则创建if (!Directory.Exists(path))Directory.CreateDirectory(path);//字符串保存 存储为枚举脚本文件File.WriteAllText(path + classNameStr + ".cs", dataStr);}Debug.Log("消息类生成结束");}/// <summary>/// 获取成员变量声明内容/// </summary>/// <param name="fieldNodes"></param>/// <returns></returns>private string GetFieldStr(XmlNodeList fieldNodes){string fieldStr = "";foreach(XmlNode fieldNode in fieldNodes){string type = fieldNode.Attributes["type"].Value;string nameStr = fieldNode.Attributes["name"].Value;if(type == "array"){string data = fieldNode.Attributes["data"].Value;fieldStr += $"\t\tpublic {data}[] ";}else if(type == "list"){string T = fieldNode.Attributes["T"].Value;fieldStr += $"\t\tpublic List<{T}> ";}else if(type == "dic"){string tKey = fieldNode.Attributes["Tkey"].Value;string tValue = fieldNode.Attributes["Tvalue"].Value;fieldStr += $"\t\tpublic Dictionary<{tKey}, {tValue}> ";}else if(type == "enum"){string data = fieldNode.Attributes["data"].Value;fieldStr += $"\t\tpublic {data} ";}else{fieldStr += "\t\tpublic " + type + " ";}fieldStr += nameStr + ";\r\n";}return fieldStr;}//拼接 GetBytesNum函数的方法private string GetBytesNumFunSre(XmlNodeList fields){string str = "";string bytesNumStr = "";string type = "";string name = "";foreach(XmlNode field in fields){type = field.Attributes["type"].Value;name = field.Attributes["name"].Value;if(type == "list"){string T = field.Attributes["T"].Value;bytesNumStr += "\t\t\tnum += 2;\r\n"; //+2 是为了节约字节数 用一个short去存储信息bytesNumStr += "\t\t\tfor (int i= 0; i < " + name + ".Count; ++i)\r\n";//这里使用的是 name + [i] 目前是获取 List当中的元素传入进行使用bytesNumStr += "\t\t\t\tnum += " + GetValueBytesNum(T, name + "[i]") + ";\r\n";}else if (type == "array"){string data = field.Attributes["data"].Value;bytesNumStr += "\t\t\tnum += 2;\r\n"; //+2 是为了节约字节数 用一个short去存储信息bytesNumStr += "\t\t\tfor (int i= 0; i < " + name + ".Length; ++i)\r\n";//这里使用的是 name + [i] 目前是获取 List当中的元素传入进行使用bytesNumStr += "\t\t\t\tnum += " + GetValueBytesNum(data, name + "[i]") + ";\r\n";}else if (type == "dic"){string Tkey = field.Attributes["Tkey"].Value;string Tvalue = field.Attributes["Tvalue"].Value;bytesNumStr += "\t\t\tnum += 2;\r\n"; //+2 是为了节约字节数 用一个short去存储信息bytesNumStr += "\t\t\tforeach (" + Tkey + " key in " + name + ".Keys)\r\n";bytesNumStr += "\t\t\t{\r\n";bytesNumStr += "\t\t\t\tnum += " + GetValueBytesNum(Tkey, "key") + ";\r\n";bytesNumStr += "\t\t\t\tnum += " + GetValueBytesNum(Tvalue, name + "[key]") + ";\r\n";bytesNumStr += "\t\t\t}\r\n";}//else if (type == "enum")//{//}else{bytesNumStr += "\t\t\tnum += " + GetValueBytesNum(type, name) + ";\r\n";}}//str += "\t\tpublic override int GetBytesNum()\r\n" +//       "\t\t{\r\n" +//            "\t\t\tint num = 0;\r\n" +//            bytesNumStr +//            "\t\t\treturn num;\r\n" +//       "\t\t}\r\n";return bytesNumStr;}//获取指定类型的字节数private string GetValueBytesNum(string type, string name){switch (type){case "int":case "float":case "enum":return "4";case "long":return "8";case "byte":case "bool":return "1";case "short":return "2";case "string":return "4 + Encoding.UTF8.GetByteCount(" + name + ")";default:return name + ".GetBytesNum()";}}private string GetWritingFunStr(XmlNodeList fields){string funStr = "";string writingStr = "";string type = "";string name = "";foreach (XmlNode field in fields){type = field.Attributes["type"].Value;name = field.Attributes["name"].Value;if(type == "list"){string T = field.Attributes["T"].Value;writingStr += $"\t\t\tWriteShort(bytes, (short){name}.Count, ref index);\r\n";writingStr += $"\t\t\tfor (int i = 0; i < {name}.Count; ++i)\r\n";writingStr += "\t\t\t\t" + GetFieldWritingStr(T, name + "[i]") + "\r\n";}else if(type == "array"){string data = field.Attributes["data"].Value;writingStr += $"\t\t\tWriteShort(bytes, (short){name}.Length, ref index);\r\n";writingStr += $"\t\t\tfor (int i = 0; i < {name}.Length; ++i)\r\n";writingStr += "\t\t\t\t" + GetFieldWritingStr(data, name + "[i]") + "\r\n";}else if (type == "dic"){string Tkey = field.Attributes["Tkey"].Value;string Tvalue = field.Attributes["Tvalue"].Value;writingStr += $"\t\t\tWriteShort(bytes, (short){name}.Count, ref index);\r\n";writingStr += $"\t\t\tforeach ({Tkey} key in {name}.Keys)\r\n";writingStr += "\t\t\t{\r\n";writingStr += "\t\t\t\t" + GetFieldWritingStr(Tkey, "key") + "\r\n";writingStr += "\t\t\t\t" + GetFieldWritingStr(Tvalue, name + "[key]") + "\r\n";writingStr += "\t\t\t}\r\n";}//else if (type == "enum")//{//}else{writingStr += "\t\t\t" + GetFieldWritingStr(type, name) + "\r\n";}}//funStr += "\t\tpublic override byte[] Writing()\r\n" +//       "\t\t{\r\n" +//            "\t\t\tint index = 0;\r\n" +//            "\t\t\tbyte[] bytes = new byte[GetBytesNum()];\r\n" +//            writingStr +//            "\t\t\treturn bytes;\r\n" +//       "\t\t}\r\n";return writingStr;}private string GetFieldWritingStr(string type, string name){switch (type){case "byte":return "WriteByte(bytes, " + name + ", ref index);";case "int":return "WriteInt(bytes, " + name + ", ref index);";case "short":return "WriteShort(bytes, " + name + ", ref index);";case "long":return "WriteLong(bytes, " + name + ", ref index);";case "float":return "WriteFloat(bytes, " + name + ", ref index);";case "bool":return "WriteBool(bytes, " + name + ", ref index);";case "string":return "WriteString(bytes, " + name + ", ref index);";case "enum":return "WriteInt(bytes, Convert.ToInt32(" + name + "), ref index);";default:return "WriteData(bytes, " + name + ", ref index);";}}private string GetReadingFunStr(XmlNodeList fields){string funStr = "";string readingStr = "";string type = "";string name = "";foreach (XmlNode field in fields){type = field.Attributes["type"].Value;name = field.Attributes["name"].Value;if(type == "list"){string T = field.Attributes["T"].Value;readingStr += "\t\t\t" + name + " = new List<" + T + ">();\r\n";readingStr += "\t\t\tshort " + name + "Count = ReadShort(bytes, ref index);\r\n";readingStr += "\t\t\tfor (int i = 0; i < " + name + "Count; ++i)\r\n";readingStr += "\t\t\t\t" + name + ".Add(" + GetFieldReadingStr(T) + ");\r\n";}else if(type == "array"){string data = field.Attributes["data"].Value;readingStr += "\t\t\tshort " + name + "Length = ReadShort(bytes, ref index);\r\n";readingStr += "\t\t\t" + name + " = new " + data + "[" + name + "Length];\r\n";readingStr += "\t\t\tfor (int i = 0; i < " + name + "Length; ++i)\r\n";readingStr += "\t\t\t\t" + name + "[i] = " + GetFieldReadingStr(data) + ";\r\n";}else if (type == "dic"){string Tkey = field.Attributes["Tkey"].Value;string Tvalue = field.Attributes["Tvalue"].Value;readingStr += "\t\t\t" + name + $" = new Dictionary<{Tkey}, {Tvalue}>();\r\n";readingStr += $"\t\t\tshort {name}Count = ReadShort(bytes, ref index);\r\n";readingStr += $"\t\t\tfor (int i = 0; i < {name}Count; ++i)\r\n";readingStr += $"\t\t\t\t{name}.Add({GetFieldReadingStr(Tkey)}, {GetFieldReadingStr(Tvalue)});\r\n";}else if (type == "enum"){string data = field.Attributes["data"].Value;readingStr += $"\t\t\t{name} = ({data})ReadInt(bytes, ref index);\r\n";}else{readingStr += "\t\t\t" + name + " = " + GetFieldReadingStr(type) + ";\r\n";}}//funStr += "\t\tpublic override int Reading(byte[] bytes, int beginIndex = 0)\r\n" +//           "\t\t{\r\n" +//                "\t\t\tint index = beginIndex;\r\n" +//                readingStr +//                "\t\t\treturn index - beginIndex;\r\n" +//           "\t\t}\r\n";return readingStr;}private string GetFieldReadingStr(string type){switch (type){case "byte":return "ReadByte(bytes, ref index)";case "int":return "ReadInt(bytes, ref index)";case "short":return "ReadShort(bytes, ref index)";case "long":return "ReadLong(bytes, ref index)";case "float":return "ReadFloat(bytes, ref index)";case "bool":return "ReadBool(bytes, ref index)";case "string":return "ReadString(bytes, ref index)";default:return "ReadData<" + type + ">(bytes, ref index)";}}}

3.3 工具使用步骤

1)创建xml配置文件,根据需要使用的消息类进行配置

<?xml version="1.0" encoding="UTF-8"?>
<messages><!--枚举配置规则--><enum name="E_PLAYER_TYPE" namespace="GamePlayer"><field name="MAIN">1</field><field name="OTHER"/></enum><enum name="E_HERO_TYPE" namespace="GamePlayer"><field name="MAIN"/><field name="OTHER"/></enum><enum name="E_MONSTER_TYPE" namespace="GameMonster"><field name="NORMAL">2</field><field name="BOSS"/></enum><!--数据结构类配置规则--><data name="PlayerData" namespace="GamePlayer"><field type="int" name="id" /><field type="float" name="atk" /><field type="bool" name="sex" /><field type="long" name="lev" /><field type="array" data="int" name="arrays" /><field type="list" T="int" name="list" /><field type="dic" Tkey="int" Tvalue="string" name="dic" /><field type="enum" data="E_HERO_TYPE" name="hereType"/></data><!--消息类配置规则--><message id="1001" name="PlayerMeg" namespace="GamePlayer"><field type="int" name="playerID" /><field type="PlayerData" name="data" /></message><message id="1002" name="HeartMsg" namespace="GameSystem"/>
</messages>

2)在ProtocolTool工具类中修改PROTO_INFO_PATH,根据自己的xml配置文件路径进行

3)在GeneraterCSharp工具类中修改SAVA_PATH,设置文件生成路径

4)在unity中点击按钮ProtocolTool/生成C#脚本,完成脚本生成

 

 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词