Unity配表工具
前言最近把前同事 @Mike Jinhua 写的配表工具整理了一下,网上的Unity配表工具有很多,也算分享一下另一种实现吧。
工具介绍
生成工具使用python3写的,python写工具有几个优点,首先语言是跨平台的,常用IDE也是跨平台的。然后python是解释性语言,可以直接调试,可以快速测试功能。python的下载链接如下
IDE使用的是pycharm
关于pycharm的配置网上介绍的文章有很多,参考一篇就可以了。最后工具打开界面如下所示
python工具使用了第三方库xlrd, 通过pycharm,可以很方便的导入第三方库
python工具使用的话可能需要设置一下Excel文件目录,生成的二进制文件目录,代码生成目录,在Config.py文件中,下面三个路径需要自定义下,当然也可以使用默认目录。
# Excel文件目录
EXCEL_DIR = "./Excel"
# 数据生成路径
UnityDataDir = "./../ExcelTest/Assets/StreamingAssts/Config/"
# 代码生成路径
UnityCodeDir = "./../ExcelTest/Assets/Scripts/Config/" 工具会在Unity中生成一个二进制数据文件和相应的所有配表类。如下图所示
外部调用的话,只要几行代码就可以初始化所有的表格数据。
string configpath = Application.streamingAssetsPath + "/Config/Config.data";
ConfigManager.LoadConfig(configpath);这个配表工具能做到自动化,数据的配置可以在Excel内完成。程序不需要再写其他代码,只要通过生成的配置类读取相应的数据就可以了。
既然在Excel内就能配置数据,那么把视角转向Excel表吧。打开某一张配置表,如下图所示
每个数据表的表头有5行
第一行是生成的代码的注释第二行有三个字段可以选择CS,C,S, 分别代表这个字段是客户端服务器通用,只是客户端使用,还是只能是服务器使用。通过这个字段筛选,可以避免生成数据的冗余第三行是生成的字段类型,目前列举了N种类型
int 整型
float 浮点型
bool bool值
string 字符串
list 整型列表
list 浮点数列表
list 字符串列表
map int为key, int为值的字典
map int为key, float为值的字典
map int为key, string为值的字典
map string为key, int为值的字典
map string为key, float为值的字典
map string为key, string为值的字典通过选择这些类型,可以生成常用的数据类型
第四行是生成的字段名字(避免重名)第五个字段是设置生成的配表类有几个Key值
没有Key的情况下,生成的类没有读取函数,只能用List遍历所有的数据
有一个Key的情况下,生成的类数据用Dictionary来管理,可以通过这个Key值获取数据
在有多个Key的情况下,生成的类数据用List来管理,可以通过多个Key值的获取函数获取表格数据
打上Key关键字的字段一般使用int, string这两个基本类型需要特殊说明的是,在Excel中,对于数组类型字段,需要使用默认的分隔符
对于List字段,分隔符是使用的 ';' (分号)
对于Map字段,一级分隔符是 '|' (竖斜杠), 二级分隔符是 ';' (分号)具体代码实现
1. Excel2Unity表格生成工具
对于这个python写的表格工具,主要的用来生成二进制数据和代码文本。
A. 二进制文件生成
笔者在整理代码的过程中,对于python生成二进制文件不了解,通过Google学习了python对二进制流的操作
python通过struct类对二进制数据进行读写, 文档如下
在这篇文档中,主要是要确定对于不同的数据写入需要什么格式,主要是下面这张表
目前这个表格工具其实只用到了4种类型int, float, bool, string
在python3中,写入数据使用如下代码 struct.pack(format, val)
对于int类型,使用的Format是"i", 流入的数据占用4个字节, 在python中代码如下bytes = struct.pack(format, int(val))对于float类型,和int类型相似,使用的Format是"f", 流入的数据占用4个字节, 在python中代码如下 bytes = struct.pack(format, float(val))对于bool类型,使用的Format是"?", 流入的数据占用1个字节,在python中代码如下 bytes = struct.pack(format, bool(val))对于特殊的string类型,根据表格显示,使用的Format是"s", 流入的数据只占用1个字节. 这里就有需要注意的地方了。在配表列出的数据类型中,除了列出的int, float, bool 三种类型,其他的类型流化成二进制数据的时候全部使用的是string流入。看看如下的python代码
newval = val.encode()
vallen = len(newval)
lenbyte = struct.pack("i", vallen)
strformat = str(vallen) + format
valbyte = struct.pack(strformat, newval)
bytes = lenbyte + valbyte上面的代码中,对于Excel表格中读取的单元格数据,首先得到这块数据的所占字节数,然后用int类型流入这个字节数,然后通过字节数和"s"拼装成最终的字符串格式,例如,字节数是20个,那么最终的字符串格式就是"20s", 然后再用struct.pack函数流入二进制数据。
也就是说,对于一个string类型,流入的二进制数据包括占用4个字节的数据长度,以及这么多数据长度的字节。由两部分组成。
完整的python函数如下所示
@staticmethod
def Encode2Bytes(format, val):
if format == "i":
bytes = struct.pack(format, int(val))
elif format == "f":
bytes = struct.pack(format, float(val))
elif format == "?":
bytes = struct.pack(format, bool(val))
elif format == "s":
newval = val.encode()
vallen = len(newval)
lenbyte = struct.pack("i", vallen)
strformat = str(vallen) + format
valbyte = struct.pack(strformat, newval)
bytes = lenbyte + valbyte
return bytes由于只生成一个二进制文件,所以所有文件的所有数据都会拼接起来,保存在一个二进制文件里面。
B. 代码生成
对于代码的生成,就是普通的字符串拼接,然后保存在文件中。需要注意的是:
file = open(path, "wb")
file.write(filecontent.encode())
file.close()对于生成的字符串filecontent, 需要使用encode()函数编码成utf-8格式,encode的默认参数就是编码成utf-8格式
2. Unity数据读取
在Unity中读取生成的二进制文件,需要准备几个基础类,拿出一个生成的配表文件类
public class Test1Cfg
{
public int ID; // int类型
public float HP; // float类型
public bool HasUse; // bool类型
public string Name1; // string类型
public string Name2; // string类型
public List<int> Vec1; // int数组
public List<float> Vec2; // float数组
public List<string> Vec4; // string数组
public Dictionary<int, int> Map1; // intint字典
public Dictionary<int, float> Map2; // intfloat字典
public Dictionary<int, string> Map4; // intstring字典
public Dictionary<string, int> Map5; // stringint字典
public Dictionary<string, float> Map6; // stringfloat字典
public Dictionary<string, string> Map8; // stringstring字典
public void Deserialize (DynamicPacket packet)
{
ID = packet.PackReadInt32();
HP = packet.PackReadFloat();
HasUse = packet.PackReadBoolean();
Name1 = packet.PackReadString();
Name2 = packet.PackReadString();
Vec1 = SheetGenCommonFunc.GetListInt(packet.PackReadString());
Vec2 = SheetGenCommonFunc.GetListFloat(packet.PackReadString());
Vec4 = SheetGenCommonFunc.GetListString(packet.PackReadString());
Map1 = SheetGenCommonFunc.GetDictIntInt(packet.PackReadString());
Map2 = SheetGenCommonFunc.GetDictIntFloat(packet.PackReadString());
Map4 = SheetGenCommonFunc.GetDictIntString(packet.PackReadString());
Map5 = SheetGenCommonFunc.GetDictStringInt(packet.PackReadString());
Map6 = SheetGenCommonFunc.GetDictStringFloat(packet.PackReadString());
Map8 = SheetGenCommonFunc.GetDictStringString(packet.PackReadString());
}
}对于python的二进制写入,C#这边的二进制读取分别
使用DynamicPacket的PackReadInt32()函数读取int数据
使用DynamicPacket的PackReadFloat()函数读取float数据
使用DynamicPacket的PackReadBoolean()函数读取boolean数据
使用DynamicPacket的PackReadString()函数读取string数据。
由于string数据流入比较特殊,所以特别看下PackReadString()这个函数的实现
public string PackReadString()
{
int count = this.PackReadInt32();
if (count == 0)
return &#34;&#34;;
byte[] bytes = this.PackReadBytes(count);
return Encoding.UTF8.GetString(bytes);
}
public int PackReadInt32()
{
return this.mReader.ReadInt32();
}
public byte[] PackReadBytes(int count)
{
byte[] array = new byte;
for (int i = 0; i < count; i++)
{
array = this.mReader.ReadByte();
}
return array;
}首先调用PackReadInt32()函数读取字节数,然后调用PackReadBytes()函数读取出二进制数据流,通过Encoding.UTF8.GetString(bytes)函数获取utf-8格式的string数据。注意到mReader变量,所有的数据都是通过这个变量来读取的,这个变量是BinaryReader类定义的。
对于DynamicPacket这个类的初始化,如下所示
public BinaryWriter mWriter;
public BinaryReader mReader;
public MemoryStream mMemStream;
public DynamicPacket(byte[] bytes)
: this()
{
this.mMemStream.Write(bytes, 0, bytes.Length);
this.mMemStream.Seek(0L, SeekOrigin.Begin);
}
public DynamicPacket()
{
this.mMemStream = new MemoryStream();
this.mReader = new BinaryReader(this.mMemStream);
this.mWriter = new BinaryWriter(this.mMemStream);
}DynamicPacket把表格二进制文件读取,通过BinaryReader来读取所有的二进制数据。通过这个DynamicPacket类,可以流化出所有的数据。
C#进行二进制数据读取不复杂,具体可以看下github的工程代码,最后给出这个工具的github地址。
项目github地址
其他的导表工具实现
github成熟工具
页:
[1]