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