59.自定义协议工具配置

59.消息处理-自定义协议生成工具-协议消息配置


59.1 知识点

选择哪种格式配置协议?

  • xmlDocument
  • json
  • excel
  • 自定义
  • 等等

我们可以根据自己的喜好选择,选择方便配置的,好用的即可。配置的主要目的是确定类名、成员变量名。之后根据读取的这些配置信息,再通过代码按照规则自动生成对应的类文件。

我个人喜欢使用xml作为协议配置文件。学会xml配置,其它的方式都是大同小异的。我们主要是学习制作思路和流程。以后的项目中,大家根据自己的喜好选择即可。

以xml配置为例制定配置规则

主要步骤

  • xml相关知识:可以在数据持久化之xml中进行学习
  • 创建xml配置文件
  • 制定配置规则
    • 枚举规则
    • 数据类规则
    • 消息类规则

配置完成后的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="heroType"/>
    </data>
    <data name="HeartData" namespace="GameSystem">
        <field type="long" name="time"/>
    </data>

    <!--消息类类配置规则 包含 消息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"/>

</messages>

读取xml配置信息

读取xml文件信息

XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(Application.dataPath + "/网络基础教程/Lesson59_消息处理_自定义协议生成工具_协议消息配置/Lesson59_消息处理_自定义协议生成工具_协议消息配置.xml");

读取各节点元素

根节点读取
// 获取XML文档中名为 "messages" 的根节点
XmlNode rootXmlNode = xmlDocument.SelectSingleNode("messages");
读取出所有枚举结构类节点
print("******枚举******");

// 获取名为 "enum" 的所有子节点并存储在 XmlNodeList 中
XmlNodeList enumXmlNodeList = rootXmlNode.SelectNodes("enum");

// 遍历所有 "enum" 子节点
foreach (XmlNode enumXmlNode in enumXmlNodeList)
{
    print("**************");

    // 打印枚举的名称
    print("枚举名字:" + enumXmlNode.Attributes["name"].Value);

    // 打印枚举所在的命名空间
    print("枚举所在命名空间:" + enumXmlNode.Attributes["namespace"].Value);

    print("******枚举成员字段******");

    // 获取该枚举节点下所有名为 "field" 的子节点
    XmlNodeList fieldXmlNodeList = enumXmlNode.SelectNodes("field");

    // 遍历枚举的成员字段
    foreach (XmlNode fieldXmlNode in fieldXmlNodeList)
    {
        string str = fieldXmlNode.Attributes["name"].Value;

        // 如果枚举字段具有值,则将其添加到输出字符串
        if (fieldXmlNode.InnerText != "")
            str += " = " + fieldXmlNode.InnerText;
        str += ",";

        // 打印枚举字段的名称和可能的值
        print(str);
    }

    print("**************");
}
读取出所有数据结构类节点
print("******数据结构类******");

// 获取名为 "data" 的所有子节点并存储在 XmlNodeList 中
XmlNodeList dataXmlNodeList = rootXmlNode.SelectNodes("data");

// 遍历所有 "data" 子节点
foreach (XmlNode dataXmlNode in dataXmlNodeList)
{
    print("**************");

    // 打印数据结构类的名称
    print("数据结构类名:" + dataXmlNode.Attributes["name"].Value);

    // 打印数据结构类所在的命名空间
    print("数据结构类所在命名空间:" + dataXmlNode.Attributes["namespace"].Value);

    print("******数据结构类成员******");

    // 获取该数据结构类节点下所有名为 "field" 的子节点
    XmlNodeList fieldXmlNodeList = dataXmlNode.SelectNodes("field");

    // 遍历数据结构类的成员字段
    foreach (XmlNode fieldXmlNode in fieldXmlNodeList)
    {
        // 获取字段的数据类型和名称,然后打印
        print(fieldXmlNode.Attributes["type"].Value + " " + fieldXmlNode.Attributes["name"].Value + ";");
    }

    print("**************");
}
读取出所有消息节点
print("******消息类******");

// 获取名为 "message" 的所有子节点并存储在 XmlNodeList 中
XmlNodeList messageXmlNodeList = rootXmlNode.SelectNodes("

message");

// 遍历所有 "message" 子节点
foreach (XmlNode messageXmlNode in messageXmlNodeList)
{
    print("**************");

    // 打印消息类的名称
    print("消息类名:" + messageXmlNode.Attributes["name"].Value);

    // 打印消息类所在的命名空间
    print("消息类所在命名空间:" + messageXmlNode.Attributes["namespace"].Value);

    // 打印消息ID
    print("消息ID:" + messageXmlNode.Attributes["id"].Value);

    print("******消息类成员******");

    // 获取该消息类节点下所有名为 "field" 的子节点
    XmlNodeList fieldXmlNodeList = messageXmlNode.SelectNodes("field");

    // 遍历消息类的成员字段
    foreach (XmlNode fieldXmlNode in fieldXmlNodeList)
    {
        // 获取字段的数据类型和名称,然后打印
        print(fieldXmlNode.Attributes["type"].Value + " " + fieldXmlNode.Attributes["name"].Value + ";");
    }

    print("**************");
}

总结

利用配置文件配置消息、数据结构、枚举的目的:

  1. 减少工作量,配置一次,之后自动化生成各种语言对应的类文件。
  2. 减少沟通成本,避免前后端语言不同时,手动写代码出现前后端不统一的问题。

59.2 知识点代码

Lesson59_消息处理_自定义协议生成工具_协议消息配置

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

public class Lesson59_消息处理_自定义协议生成工具_协议消息配置 : MonoBehaviour
{
    void Start()
    {
        #region 知识点一 选择哪种格式配置协议?

        //1.xmlDocument
        //2.json
        //3.excel
        //4.自定义
        //等等
        //我们可以根据自己的喜好选择
        //选择方便配置的,好用的即可
        //配置的主要目的是确定
        //类名、成员变量名

        //之后根据读取的这些配置信息
        //再通过代码按照规则自动生成对应的类文件

        //我个人喜欢使用xml作为协议配置文件
        //学会xml配置,其它的方式都是大同小异的
        //我们主要是学习制作思路和流程
        //以后的项目中,大家根据自己的喜好选择即可

        #endregion

        #region 知识点二 以xml配置为例制定配置规则

        //xml相关知识,可以在数据持久化之xml中进行学习
        //1. 创建xml配置文件
        //2. 制定配置规则
        //   1.枚举规则 
        //   2.数据类规则
        //   3.消息类规则

        #endregion

        #region 知识点三 读取xml配置信息

        //1.读取xml文件信息
        XmlDocument xmlDocument = new XmlDocument();
        xmlDocument.Load(Application.dataPath + "/网络基础教程/Lesson59_消息处理_自定义协议生成工具_协议消息配置/Lesson59_消息处理_自定义协议生成工具_协议消息配置.xml");



        //2.读取各节点元素


        //2-1: 根节点读取
        // 获取XML文档中名为 "messages" 的根节点
        XmlNode rootXmlNode = xmlDocument.SelectSingleNode("messages");


        //2-2: 读取出所有枚举结构类节点

        print("******枚举******");

        // 获取名为 "enum" 的所有子节点并存储在 XmlNodeList 中
        XmlNodeList enumXmlNodeList = rootXmlNode.SelectNodes("enum");
        // 遍历所有 "enum" 子节点
        foreach (XmlNode enumXmlNode in enumXmlNodeList)
        {
            print("**************");

            // 打印枚举的名称
            print("枚举名字:" + enumXmlNode.Attributes["name"].Value);

            // 打印枚举所在的命名空间
            print("枚举所在命名空间:" + enumXmlNode.Attributes["namespace"].Value);

            print("******枚举成员字段******");

            // 获取该枚举节点下所有名为 "field" 的子节点
            XmlNodeList fieldXmlNodeList = enumXmlNode.SelectNodes("field");

            // 遍历枚举的成员字段
            foreach (XmlNode fieldXmlNode in fieldXmlNodeList)
            {
                string str = fieldXmlNode.Attributes["name"].Value;

                // 如果枚举字段具有值,则将其添加到输出字符串
                if (fieldXmlNode.InnerText != "")
                    str += " = " + fieldXmlNode.InnerText;
                str += ",";

                // 打印枚举字段的名称和可能的值
                print(str);
            }

            print("**************");
        }


        //2-3: 读取出所有数据结构类节点

        print("******数据结构类******");

        // 获取名为 "data" 的所有子节点并存储在 XmlNodeList 中
        XmlNodeList dataXmlNodeList = rootXmlNode.SelectNodes("data");

        // 遍历所有 "data" 子节点
        foreach (XmlNode dataXmlNode in dataXmlNodeList)
        {
            print("**************");

            // 打印数据结构类的名称
            print("数据结构类名:" + dataXmlNode.Attributes["name"].Value);

            // 打印数据结构类所在的命名空间
            print("数据结构类所在命名空间:" + dataXmlNode.Attributes["namespace"].Value);

            print("******数据结构类成员******");

            // 获取该数据结构类节点下所有名为 "field" 的子节点
            XmlNodeList fieldXmlNodeList = dataXmlNode.SelectNodes("field");

            // 遍历数据结构类的成员字段
            foreach (XmlNode fieldXmlNode in fieldXmlNodeList)
            {
                // 获取字段的数据类型和名称,然后打印
                print(fieldXmlNode.Attributes["type"].Value + " " + fieldXmlNode.Attributes["name"].Value + ";");
            }

            print("**************");
        }


        //2-4: 读取出所有消息节点

        print("******消息类******");

        // 获取名为 "message" 的所有子节点并存储在 XmlNodeList 中
        XmlNodeList messageXmlNodeList = rootXmlNode.SelectNodes("message");

        // 遍历所有 "message" 子节点
        foreach (XmlNode messageXmlNode in messageXmlNodeList)
        {
            print("**************");

            // 打印消息类的名称
            print("消息类名:" + messageXmlNode.Attributes["name"].Value);

            // 打印消息类所在的命名空间
            print("消息类所在命名空间:" + messageXmlNode.Attributes["namespace"].Value);

            // 打印消息ID
            print("消息ID:" + messageXmlNode.Attributes["id"].Value);

            print("******消息类成员******");

            // 获取该消息类节点下所有名为 "field" 的子节点
            XmlNodeList fieldXmlNodeList = messageXmlNode.SelectNodes("field");

            // 遍历消息类的成员字段
            foreach (XmlNode fieldXmlNode in fieldXmlNodeList)
            {
                // 获取字段的数据类型和名称,然后打印
                print(fieldXmlNode.Attributes["type"].Value + " " + fieldXmlNode.Attributes["name"].Value + ";");
            }

            print("**************");
        }



        #endregion

        #region 总结

        //利用配置文件配置消息、数据结构、枚举的目的
        //1.减少工作量,配置一次,之后自动化生成各种语言对应的类文件
        //2.减少沟通成本,避免前后端语言不同时,手动写代码出现前后端不统一的问题

        #endregion
    }
}

Lesson59_消息处理_自定义协议生成工具_协议消息配置.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="heroType"/>
    </data>
    <data name="HeartData" namespace="GameSystem">
        <field type="long" name="time"/>
    </data>

    <!--消息类类配置规则 包含 消息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"/>
    
</messages>


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

×

喜欢就点赞,疼爱就打赏