# ExcelTool 本项目基于 https://github.com/dingxiaowei/ExcelTool 开发。用于 [AudioSystem](https://github.com/htw128/UnityAudioExtend), [HapticSystem](https://github.com/htw128/UnityAudioExtend#Haptic) 导出数据使用。 #### 功能 * 生成对应的数据模板代码 * 支持生成模板代码字段注释 * 生成二进制文件 * 自动将文件拷贝到对应的工程目录 * 二进制数据读取 * 字段不配置会使用默认数值 #### 目前支持的字段 * 常规的字段,例如int,float,string,bool,long,list,intlist,longlist,floatlist,boollist,List 大小写不限 * 支持自定义字段 vector,例如[1,2,3] * 支持自定义字段 list,其实是vector数组,例如[[1,2,3],[2,3,4],[4,5,6]] ##### 自动生成的模板代码 ```c# /* * auto generated by tools(注意:千万不要手动修改本文件) * avatarguideTest */ using System; using System.IO; using System.Collections.Generic; using System.Text; using System.Linq; [Serializable] public class avatarguideTest : IBinarySerializable { public int Id { get; set; } public string gender { get; set; } public float age { get; set; } public bool bValue { get; set; } public List vector { get; set; } public List> Grid { get; set; } public void DeSerialize(BinaryReader reader) { Id = reader.ReadInt32(); gender = reader.ReadString(); age = reader.ReadSingle(); bValue = reader.ReadBoolean(); var vectorCount = reader.ReadInt32(); if (vectorCount > 0) { vector = new List(); for (int i = 0; i < vectorCount; i++) { vector.Add(reader.ReadSingle()); } } else { vector = null; } var GridCount = reader.ReadInt32(); if (GridCount > 0) { Grid = new List>(); for (int i = 0; i < GridCount; i++) { var tempList = new List(); var tempListCount = reader.ReadInt32(); for (int j = 0; j < tempListCount; j++) { tempList.Add(reader.ReadSingle()); } Grid.Add(tempList); } } else { Grid = null; } } public void Serialize(BinaryWriter writer) { writer.Write(Id); writer.Write(gender); writer.Write(age); writer.Write(bValue); if (vector == null || vector.Count == 0) { writer.Write(0); } else { writer.Write(vector.Count); for (int i = 0; i < vector.Count; i++) { writer.Write(vector[i]); } } if (Grid == null || Grid.Count == 0) { writer.Write(0); } else { writer.Write(Grid.Count); for (int i = 0; i < Grid.Count; i++) { writer.Write(Grid[i].Count); for (int j = 0; j < Grid[i].Count; j++) { writer.Write(Grid[i][j]); } } } } public override string ToString() { var str = $"Id:{Id} Gender:{gender} age:{age} bValue:{bValue} "; if (vector != null) { str += $"vector:[{vector[0]},{vector[1]},{vector[2]}] "; } if (Grid != null) { str += "Grid:["; for (int i = 0; i < Grid.Count; i++) { str += $"[{Grid[i][0]},{Grid[i][1]},{Grid[i][2]}]"; if (i < Grid.Count - 1) str += ","; } str += "]"; } return str; } } [Serializable] public partial class avatarguideTestConfig : IBinarySerializable { public List avatarguideTestInfos = new List(); public void DeSerialize(BinaryReader reader) { int count = reader.ReadInt32(); for (int i = 0;i < count; i++) { avatarguideTest tempData = new avatarguideTest(); tempData.DeSerialize(reader); avatarguideTestInfos.Add(tempData); } } public void Serialize(BinaryWriter writer) { writer.Write(avatarguideTestInfos.Count); for (int i = 0; i < avatarguideTestInfos.Count; i++) { avatarguideTestInfos[i].Serialize(writer); } } public IEnumerable QueryById(int id) { var datas = from d in avatarguideTestInfos where d.Id == id select d; return datas; } public override string ToString() { StringBuilder sb = new StringBuilder(); for (int i = 0; i < avatarguideTestInfos.Count; i++) { sb.Append($"{avatarguideTestInfos[i].ToString()}\n"); } return sb.ToString(); } } ``` #### 使用案例 ##### 解析二进制文件 ```c# IBinarySerializable newavList = new avatarguideTestList(); var readOK = FileManager.ReadBinaryDataFromFile(Path.Combine(path, "avatarguideTest.dat"), ref newavList); if (readOK) { ConsoleHelper.WriteInfoLine(newavList.ToString()); } else { ConsoleHelper.WriteErrorLine("读取失败"); } ``` ![](img/3.jpg) ##### Unity解析二进制 将二进制文件(后缀必须是.bytes)放在Resources目录,然后通过Resources.Load接口加载 ```c# var bytes = Resources.Load("avatarguideTest"); if (bytes == null) { return; } IBinarySerializable newavList = new avatarguideTestConfig(); var readOK = FileManager.ReadBinaryDataFromBytes(bytes.bytes, ref newavList); if (readOK) { Debug.Log(newavList.ToString()); //根据Id查询数据 //var avatarguideTest = (avatarguideTestConfig)newavList; //var obj = avatarguideTest.QueryById(2); //if (obj != null && obj.Count() > 0) // Debug.Log(obj.FirstOrDefault().ToString()); } else { Debug.LogError("数据读取错误"); } ``` #### 泛型读表 ```c# T ReadTable(string tableName) where T : IBinarySerializable, new() { var bytes = LoadTextAsset(tableName); if (bytes != null) { IBinarySerializable data = new T(); var readOK = FileManager.ReadBinaryDataFromBytes(bytes.bytes, ref data); if (readOK) { return (T)data; } else { Debug.LogError($"{tableName}解析出错 类型{typeof(T)}"); } } return default(T); } ``` ##### 查询数据 ```c# var avatarguideTest = (avatarguideTestConfig)newavList; var obj = avatarguideTest.QueryById(2); if (obj != null && obj.Count() > 0) ConsoleHelper.WriteInfoLine(obj.FirstOrDefault().ToString()); ``` #### 自动化拷贝批处理 ```batch @echo off echo "开始拷贝jsons" for %%i in (*.dat) do ( echo begin copy... %%i copy /y %%~nxi ..\..\hola_unity\Assets\Resources\Config\%%~nxi echo copy complate ... %%i ) echo "拷贝完成" pause ``` #### 扩展类方法 上面的config类采用的是partical class 就是为了方便扩展自定义的方法,如果想要添加自定义方法也定义一个partical class文件作为扩展即可 #### TODO * [x] 支持枚举类型 * [x] 支持不同表不同namespace * [ ] 支持Excel数据配置规范性检测,例如手误配置不符合规范导致加载异常,例如大小写逗号(肉眼容易忽略),或者空格等等 * [ ] ID不能重复 * [ ] Music、Audio Container不能自引用 * [ ] 同时播放的音乐BPM必须一致 * [ ] Blend容器不能配置Haptic ID * [ ] 生成CueSheet避免magic number * [ ] AudioObject支持Container嵌套 #### Unity客户端使用范例 采用的美术效果机型适配商业化解决方案Demo https://github.com/dingxiaowei/DeviceGrading 优雅的表格使用范本