65.自定义协议工具生成消息类

65.消息处理-自定义协议生成工具-协议消息生成-生成消息类


65.1 知识点

对比消息类和数据结构类的不同

类名和继承

public class PlayerMessage : BaseMessage

获得字节数组方法多了消息ID长度和消息体长度8个字节

public override int GetBytesNum()
{
    return 
        4 + // 消息ID的长度
        4 + // 消息体的长度
        4 + // playerID的字节数组长度
        playerData.GetBytesNum(); // playerData的字节数组长度
}

序列化方法要先写消息ID再写消息体长度

public override byte[] Writing()
{
    int index = 0;

    int bytesNum = GetBytesNum();

    byte[] bytes = new byte[bytesNum];
    // 先写消息ID
    WriteInt(bytes, GetID(), ref index);

    // 写入消息体的长度
    WriteInt(bytes, bytesNum - 8, ref index);

    // 写这个消息的成员变量
    WriteInt(bytes, playerID, ref index);
    WriteData(bytes, playerData, ref index);
    return bytes;
}

反序列化由于我们是在外部解析消息ID和消息体长度的,所以和数据结构类一致

获得定义消息ID的方法

/// <summary>
/// 自定义的消息ID 主要用于区分是哪一个消息类
/// </summary>
/// <returns></returns>
public override int GetID()
{
    return 1001;
}

观察xml配置

- <!--消息类类配置规则 包含 消息ID 类名 命名空间 变量类型 变量名-->
<message id="1001" name="PlayerMessage" namespace="GamePlayer">
    <field type="int" name="playerID"/>
    <field type="PlayerData" name="data"/>
</message>
<message id="1002" name="HeartMessage" namespace="GameSystem"/>

在GenerateCSharp类中定义生成消息类方法,并在ProtocolTool中调用

[MenuItem("ProtocolTool/生成C#脚本")]
private static void GenerateCSharp()
{
    // 读取xml相关的信息
    // XmlNodeList list = GetNodes("enum");
    // 根据这些信息 去拼接字符串 生成对应的脚本
    // 生成对应的枚举脚本
    generateCSharp.GenerateEnum(GetNodes("enum"));
    // 生成对应的数据结构类脚本
    generateCSharp.GenerateData(GetNodes("data"));
    // 生成对应的消息类脚本
    generateCSharp.GenerateMsg(GetNodes("message"));

    // 刷新编辑器界面 让我们可以看到生成的内容 不需要手动进行刷新了
    AssetDatabase.Refresh();
}

实现生成消息类方法,可以在生产数据结构类方法的基础上改

// 生成消息类
public void GenerateMsg(XmlNodeList nodes)
{
    string idStr = "";
    string namespaceStr = "";
    string classNameStr = "";
    string fieldStr = "";
    string getBytesNumStr = "";
    string writingStr = "";
    string readingStr = "";

    foreach (XmlNode dataNode in nodes)
    {
        // 消息ID
        idStr = dataNode.Attributes["id"].Value;
        // 命名空间
        namespaceStr = dataNode.Attributes["namespace"].Value;
        // 类名
        classNameStr = dataNode.Attributes["name"].Value;
        // 读取所有字段节点
        XmlNodeList fields = dataNode.SelectNodes("field");
        // 通过这个方法进行成员变量声明的拼接 返回拼接结果
        fieldStr = GetFieldStr(fields);
        // 通过某个方法 对GetBytesNum函数中的字符串内容进行拼接 返回结果
        getBytesNumStr = GetGetBytesNumStr(fields);
        // 通过某个方法 对Writing函数中的字符串内容进行拼接 返回结果
        writingStr = GetWritingStr(fields);
        // 通过某个方法 对Reading函数中的字符串内容进行拼接 返回结果
        readingStr = GetReadingStr(fields);

        string dataStr = "using System;\r\n" +
                         "using System.Collections.Generic;\r\n" +
                         "using System.Text;\r\n" +
                         $"namespace {namespaceStr}\r\n" +
                         "{\r\n" +
                         $"\tpublic class {classNameStr} : BaseMessage\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个字节
                         $"{getBytesNumStr}" +
                         "\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" +
                         $"{writingStr}" +
                         "\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" +
                         $"{readingStr}" +
                         "\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 " + idStr + ";\r\n" +
                         "\t\t}\r\n" +
                         "\t}\r\n" +
                         "}";

        // 保存为 脚本文件
        // 保存文件的路径
        string path = SAVE_PATH + namespaceStr + "/Msg/";
        // 如果不存在这个文件夹 则创建
        if (!Directory.Exists(path))
            Directory.CreateDirectory(path);

        // 字符串保存 存储为枚举脚本文件
        File.WriteAllText(path + classNameStr + ".cs", dataStr);
    }
    Debug.Log("消息类生成结束");
}

查看生成的消息类并测试

using System;
using System.Collections.Generic;
using System.Text;
namespace GamePlayer
{
    public class PlayerMessage : BaseMsg
    {
        public int playerID;
        public PlayerData data;
        public override int GetBytesNum()
        {
            int num = 8;
            num += 4;
            num += data.GetBytesNum();
            return num;
        }
        public override byte[] Writing()
        {
            int index = 0;
            byte[] bytes = new byte[GetBytesNum()];
            WriteInt(bytes, GetID(), ref index);
            WriteInt(bytes, bytes.Length - 8, ref index);
            WriteInt(bytes, playerID, ref index);
            WriteData(bytes, data, ref index);
            return bytes;
        }
        public override int Reading(byte[] bytes, int beginIndex = 0)
        {
            int index = beginIndex;
            playerID = ReadInt(bytes, ref index);
            data = ReadData<PlayerData>(bytes, ref index);
            return index - beginIndex;
        }
        public override int GetID()
        {
            return 1001;
        }
    }
}

using System;
using System.Collections.Generic;
using System.Text;
namespace GameSystem
{
    public class HeartMessage : BaseMsg
    {
        public override int GetBytesNum()
        {
            int num = 8;
            return num;
        }
        public override byte[] Writing()
        {
            int index = 0;
            byte[] bytes = new byte[GetBytesNum()];
            WriteInt(bytes, GetID(), ref index);
            WriteInt(bytes, bytes.Length - 8, ref index);
            return bytes;
        }
        public override int Reading(byte[] bytes, int beginIndex = 0)
        {
            int index = beginIndex;
            return index - beginIndex;
        }
        public override int GetID()
        {
            return 1002;
        }
    }
}

GamePlayer.PlayerMessage playerMessage1 = new GamePlayer.PlayerMessage();
playerMessage1.playerID = 999;
playerMessage1.data = new GamePlayer.PlayerData();
playerMessage1.data.id = 888;
playerMessage1.data.atk = 10;
playerMessage1.data.sex = true;
playerMessage1.data.lev = 77;
playerMessage1.data.arrays = new int[] { 1, 2, 3, 4 };
playerMessage1.data.list = new List<int>() { 4, 3, 2, 1 };
playerMessage1.data.dic = new Dictionary<int, string>() {
    { 1, "123"},
    { 2, "韬老狮"},
    { 3, "好好学习"},
};
playerMessage1.data.heroType = GamePlayer.E_HERO_TYPE.MAIN;

// 序列化
byte[] bytes = playerMessage1.Writing();

// 反序列化
int index = 0;
int msgID = BitConverter.ToInt32(bytes, index);
index += 4;
int msgLength = BitConverter.ToInt32(bytes, index);
index += 4;
GamePlayer.PlayerMessage playerMessage2 = new GamePlayer.PlayerMessage();
playerMessage2.Reading(bytes, index);
print(playerMessage2.playerID);

65.2 知识点代码

GenerateCSharp

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using UnityEngine;

namespace GamePlayer//1
{
    public enum E_Player_Type
    {
        Main,
        Other,
    }
    public class PlayerTest : BaseData
    {
        public List<int> list;
        public Dictionary<int, string> dic;
        public int[] arrays;
        public E_Player_Type type;
        public PlayerData player;

        public override int GetBytesNum()
        {
            int num = 0;
            num += 4;//list.Count
            for (int i = 0; i < list.Count; i++)
                num += 4;

            num += 4;//dic.Count
            foreach (int key in dic.Keys)
            {
                num += 4;//key所占的字节数
                num += 4;//value 字符串长度 占的字节数
                num += Encoding.UTF8.GetByteCount(dic[key]);
            }

            num += 4;//arrays.Length
            for (int i = 0; i < arrays.Length; i++)
                num += 4;

            num += 4;

            num += player.GetBytesNum();

            return num;
        }

        public override int Reading(byte[] bytes, int beginIndex = 0)
        {
            int index = beginIndex;

            list = new List<int>();//初始化规则
            short listCount = ReadShort(bytes, ref index);
            for (int i = 0; i < listCount; i++)
                list.Add(ReadInt(bytes, ref index));

            dic = new Dictionary<int, string>();//初始化规则
            short dicCount = ReadShort(bytes, ref index);
            for (int i = 0; i < dicCount; i++)
                dic.Add(ReadInt(bytes, ref index), ReadString(bytes, ref index));

            short arraysLength = ReadShort(bytes, ref index);
            arrays = new int[arraysLength];//初始化规则
            for (int i = 0; i < arraysLength; i++)
                arrays[i] = ReadInt(bytes, ref index);

            type = (E_Player_Type)ReadInt(bytes, ref index);

            player = ReadData<PlayerData>(bytes, ref index);

            return index - beginIndex;
        }

        public override byte[] Writing()
        {
            //固定内容
            int index = 0;
            byte[] bytes = new byte[GetBytesNum()];

            //可变的 是根据成员变量来决定如何拼接的
            //存储list的长度
            WriteShort(bytes, (short)list.Count, ref index);
            for (int i = 0; i < list.Count; i++)
                WriteInt(bytes, list[i], ref index);

            //存储Dictionary的内容
            //长度
            WriteShort(bytes, (short)dic.Count, ref index);
            foreach (int key in dic.Keys)
            {
                WriteInt(bytes, key, ref index);
                WriteString(bytes, dic[key], ref index);
            }

            //存储数组的长度
            WriteShort(bytes, (short)arrays.Length, ref index);
            for (int i = 0; i < arrays.Length; i++)
                WriteInt(bytes, arrays[i], ref index);

            //枚举
            WriteInt(bytes, Convert.ToInt32(type), ref index);

            //自定义数据结构类
            WriteData(bytes, player, ref index);

            //固定内容
            return bytes;
        }
    }
}

public class GenerateCSharp
{
    //协议保存路径
    private string SAVE_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 = SAVE_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 getBytesNumStr = "";
        string writingStr = "";
        string readingStr = "";

        foreach (XmlNode dataNode in nodes)
        {
            //命名空间
            namespaceStr = dataNode.Attributes["namespace"].Value;
            //类名
            classNameStr = dataNode.Attributes["name"].Value;
            //读取所有字段节点
            XmlNodeList fields = dataNode.SelectNodes("field");
            //通过这个方法进行成员变量声明的拼接 返回拼接结果
            fieldStr = GetFieldStr(fields);
            //通过某个方法 对GetBytesNum函数中的字符串内容进行拼接 返回结果
            getBytesNumStr = GetGetBytesNumStr(fields);
            //通过某个方法 对Writing函数中的字符串内容进行拼接 返回结果
            writingStr = GetWritingStr(fields);
            //通过某个方法 对Reading函数中的字符串内容进行拼接 返回结果
            readingStr = GetReadingStr(fields);

            string dataStr = "using System;\r\n" +
                                "using System.Collections.Generic;\r\n" +
                                "using System.Text;\r\n" + 
                                $"namespace {namespaceStr}\r\n" +
                                "{\r\n" +
                                $"\tpublic class {classNameStr} : BaseData\r\n" +
                                "\t{\r\n" +
                                    $"{fieldStr}" +
                                    "\t\tpublic override int GetBytesNum()\r\n" +
                                    "\t\t{\r\n" +
                                        "\t\t\tint num = 0;\r\n" +
                                        $"{getBytesNumStr}" +
                                        "\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" +
                                        $"{writingStr}" +
                                        "\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" +
                                        $"{readingStr}" +
                                        "\t\t\treturn index - beginIndex;\r\n" +
                                    "\t\t}\r\n" +
                                "\t}\r\n" +
                                "}";

            //保存为 脚本文件
            //保存文件的路径
            string path = SAVE_PATH + namespaceStr + "/Data/";
            //如果不存在这个文件夹 则创建
            if (!Directory.Exists(path))
                Directory.CreateDirectory(path);

            //字符串保存 存储为枚举脚本文件
            File.WriteAllText(path + classNameStr + ".cs", dataStr);

        }
        Debug.Log("数据结构类生成结束");
    }

    //生成消息类
    public void GenerateMsg(XmlNodeList nodes)
    {
        string idStr = "";
        string namespaceStr = "";
        string classNameStr = "";
        string fieldStr = "";
        string getBytesNumStr = "";
        string writingStr = "";
        string readingStr = "";

        foreach (XmlNode dataNode in nodes)
        {
            //消息ID
            idStr = dataNode.Attributes["id"].Value;
            //命名空间
            namespaceStr = dataNode.Attributes["namespace"].Value;
            //类名
            classNameStr = dataNode.Attributes["name"].Value;
            //读取所有字段节点
            XmlNodeList fields = dataNode.SelectNodes("field");
            //通过这个方法进行成员变量声明的拼接 返回拼接结果
            fieldStr = GetFieldStr(fields);
            //通过某个方法 对GetBytesNum函数中的字符串内容进行拼接 返回结果
            getBytesNumStr = GetGetBytesNumStr(fields);
            //通过某个方法 对Writing函数中的字符串内容进行拼接 返回结果
            writingStr = GetWritingStr(fields);
            //通过某个方法 对Reading函数中的字符串内容进行拼接 返回结果
            readingStr = GetReadingStr(fields);

            string dataStr = "using System;\r\n" +
                                "using System.Collections.Generic;\r\n" +
                                "using System.Text;\r\n" +
                                $"namespace {namespaceStr}\r\n" +
                                "{\r\n" +
                                $"\tpublic class {classNameStr} : BaseMessage\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个字节
                                        $"{getBytesNumStr}" +
                                        "\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" +
                                        $"{writingStr}" +
                                        "\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" +
                                        $"{readingStr}" +
                                        "\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 " + idStr + ";\r\n" +
                                    "\t\t}\r\n" +
                                "\t}\r\n" +
                                "}";

            //保存为 脚本文件
            //保存文件的路径
            string path = SAVE_PATH + namespaceStr + "/Msg/";
            //如果不存在这个文件夹 则创建
            if (!Directory.Exists(path))
                Directory.CreateDirectory(path);

            //字符串保存 存储为枚举脚本文件
            File.WriteAllText(path + classNameStr + ".cs", dataStr);

        }
        Debug.Log("消息类生成结束");
    }

    /// <summary>
    /// 获取成员变量声明内容
    /// </summary>
    /// <param name="fields"></param>
    /// <returns></returns>
    private string GetFieldStr(XmlNodeList fields)
    {
        string fieldStr = "";
        foreach (XmlNode field in fields)
        {
            //变量类型
            string type = field.Attributes["type"].Value;
            //变量名
            string fieldName = field.Attributes["name"].Value;
            if(type == "list")
            {
                string T = field.Attributes["T"].Value;
                fieldStr += "\t\tpublic List<" + T + "> ";
            }
            else if(type == "array")
            {
                string data = field.Attributes["data"].Value;
                fieldStr += "\t\tpublic " + data + "[] ";
            }
            else if(type == "dic")
            {
                string Tkey = field.Attributes["Tkey"].Value;
                string Tvalue = field.Attributes["Tvalue"].Value;
                fieldStr += "\t\tpublic Dictionary<" + Tkey +  ", " + Tvalue + "> ";
            }
            else if(type == "enum")
            {
                string data = field.Attributes["data"].Value;
                fieldStr += "\t\tpublic " + data + " ";
            }
            else
            {
                fieldStr += "\t\tpublic " + type + " ";
            }

            fieldStr += fieldName + ";\r\n";
        }
        return fieldStr;
    }

    //拼接 GetBytesNum函数的方法
    private string GetGetBytesNumStr(XmlNodeList fields)
    {
        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
                bytesNumStr += "\t\t\tnum += " + GetValueBytesNum(type, name) + ";\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()";
        }
    }

    //拼接 Writing函数的方法
    private string GetWritingStr(XmlNodeList fields)
    {
        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
            {
                writingStr += "\t\t\t" + GetFieldWritingStr(type, name) + "\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 GetReadingStr(XmlNodeList fields)
    {
        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";
        }

        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)";
        }
    }
}

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 GenerateCSharp generateCSharp = new GenerateCSharp();

    [MenuItem("ProtocolTool/生成C#脚本")]
    private static void GenerateCSharp()
    {
        //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 GenerateC()
    {
        Debug.Log("生成C++代码");
    }

    [MenuItem("ProtocolTool/生成Java脚本")]
    private static void GenerateJava()
    {
        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);
    }
}

PlayerMessage

using System;
using System.Collections.Generic;
using System.Text;
namespace GamePlayer
{
    public class PlayerMessage : BaseMessage
    {
        public int playerID;
        public PlayerData data;
        public override int GetBytesNum()
        {
            int num = 8;
            num += 4;
            num += data.GetBytesNum();
            return num;
        }
        public override byte[] Writing()
        {
            int index = 0;
            byte[] bytes = new byte[GetBytesNum()];
            WriteInt(bytes, GetID(), ref index);
            WriteInt(bytes, bytes.Length - 8, ref index);
            WriteInt(bytes, playerID, ref index);
            WriteData(bytes, data, ref index);
            return bytes;
        }
        public override int Reading(byte[] bytes, int beginIndex = 0)
        {
            int index = beginIndex;
            playerID = ReadInt(bytes, ref index);
            data = ReadData<PlayerData>(bytes, ref index);
            return index - beginIndex;
        }
        public override int GetID()
        {
            return 1001;
        }
    }
}

HeartMessage

using System;
using System.Collections.Generic;
using System.Text;
namespace GameSystem
{
    public class HeartMessage : BaseMessage
    {
        public override int GetBytesNum()
        {
            int num = 8;
            return num;
        }
        public override byte[] Writing()
        {
            int index = 0;
            byte[] bytes = new byte[GetBytesNum()];
            WriteInt(bytes, GetID(), ref index);
            WriteInt(bytes, bytes.Length - 8, ref index);
            return bytes;
        }
        public override int Reading(byte[] bytes, int beginIndex = 0)
        {
            int index = beginIndex;
            return index - beginIndex;
        }
        public override int GetID()
        {
            return 1002;
        }
    }
}

Lesson65_消息处理_自定义协议生成工具_协议消息生成_生成消息类

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Lesson65_消息处理_自定义协议生成工具_协议消息生成_生成消息类 : MonoBehaviour
{
    void Start()
    {
        GamePlayer.PlayerMessage playerMessage1 = new GamePlayer.PlayerMessage();
        playerMessage1.playerID = 999;
        playerMessage1.data = new GamePlayer.PlayerData();
        playerMessage1.data.id = 888;
        playerMessage1.data.atk = 10;
        playerMessage1.data.sex = true;
        playerMessage1.data.lev = 77;
        playerMessage1.data.arrays = new int[] { 1, 2, 3, 4 };
        playerMessage1.data.list = new List<int>() { 4, 3, 2, 1 };
        playerMessage1.data.dic = new Dictionary<int, string>() {
            { 1, "123"},
            { 2, "韬老狮"},
            { 3, "好好学习"},
        };
        playerMessage1.data.heroType = GamePlayer.E_HERO_TYPE.MAIN;

        //序列化
        byte[] bytes = playerMessage1.Writing();

        //反序列化
        int index = 0;
        int msgID = BitConverter.ToInt32(bytes, index);
        index += 4;
        int msgLength = BitConverter.ToInt32(bytes, index);
        index += 4;
        GamePlayer.PlayerMessage playerMessage2 = new GamePlayer.PlayerMessage();
        playerMessage2.Reading(bytes, index);
        print(playerMessage2.playerID);
    }
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏