62.自定义协议工具生成数据结构类GetBytesNum函数

62.消息处理-自定义协议生成工具-协议消息生成-生成数据结构类-GetBytesNum函数


62.1 知识点

观察假如正常手写GetBytesNum函数应该怎么写

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)
    {
        throw new System.NotImplementedException();
    }

    public override byte[] Writing()
    {
        throw new System.NotImplementedException();
    }
}

观察xml配置

<!--数据结构类配置规则 包含 类名 命名空间 变量类型 变量名-->
<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="heroType"/>
</data>
<data name="HeartData" namespace="GameSystem">
    <field type="long" name="time"/>
</data>

定义返回不同类型字节长度的函数

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

定义拼接GetBytesNum函数字符串的函数GetGetBytesNumStr

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

在生成数据结构类函数中调用GetBytesNum函数,进行GetBytesNum函数的拼接。注意要添加命名空间。

//生成数据结构类
public void GenerateData(XmlNodeList nodes)
{
    string namespaceStr = "";
    string classNameStr = "";
    string fieldStr = "";
    string getBytesNumStr = "";

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

        string dataStr = "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}\r\n" +
            "}";

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

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

点击编辑器按钮查看查看拼接的GetBytesNum函数结果

public class PlayerData : BaseData
{
    public int id;
    public float atk;
    public bool sex;
    public long lev;
    public int[] arrays;
    public List<int> list;
    public Dictionary<int, string> dic;
    public E_HERO_TYPE heroType;
    public override int GetBytesNum()
    {
        int num = 0;
        num += 4;
        num += 4;
        num += 1;
        num += 8;
        num += 2;
        for (int i = 0; i < arrays.Length; ++i)
            num += 4;
        num += 2;
        for (int i = 0; i < list.Count; ++i)
            num += 4;
        num += 2;
        foreach (int key in dic.Keys)
        {
            num += 4;
            num += 4 + Encoding.UTF8.GetByteCount(dic[key]);
        }
        num += 4;
        return num;
    }
}

public class HeartData : BaseData
{
    public long time;
    public override int GetBytesNum()
    {
        int num = 0;
        num += 8;
        return num;
    }
}

62.2 知识点代码

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)
        {
            throw new System.NotImplementedException();
        }

        public override byte[] Writing()
        {
            throw new System.NotImplementedException();
        }
    }
}

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 = "";

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

            string dataStr = "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}\r\n" +
                              "}";

            //保存为 脚本文件
            //保存文件的路径
            string path = SAVE_PATH + namespaceStr + "/Data/";
            //如果不存在这个文件夹 则创建
            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;
    }

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


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

×

喜欢就点赞,疼爱就打赏