Unity导表工具制作,可用于ILRuntime下热更使用

首先我们明确一下导表工具的目的就是将,策划的表格数据转换为游戏里面程序方便调用的数据格式,一般都是游戏初始换的时候,以字典的结构<Type,<Id,object>> 类似的结构加载表格数据,我们的导表工具就是将Excel表,生成对应的类结构,二进制数据。

1.第一步过滤表格,因为我们的表格是服务器和客户端都放在一起,只是以表头做标志进行区分,如果放在不同的文件夹下的话,就不用做过滤了 下载链接

        /// <summary>
        /// 导入CSV数据
        /// </summary>
        private static bool ImportCsvData(FileInfo file)
        {
            DataTable dt = GetCsvData(file);
            string s = dt.Rows[0][0] as string;
            if (s != "CS" && s != "C")
            {
                UnityEngine.Debug.LogError("客户端无需处理不带C的表格");
                return false; // 客户端无需处理不带C的表格
            }
            CreateByteData(file.Name.Replace(file.Extension, ""), dt);
            return true;
        }

2.第二步,填充数据到DataTable中,这里我用的是.csv表格(excel需要插件进行读取)这个其实就可以看作一个txt文件,中间用逗号隔开,这里我们用正则表达式过滤处理

        /// <summary>
        /// 可忽略引号中的","
        /// </summary>
        private static Regex pattern = new Regex(",(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))");
        /// <summary>
        /// 解析CSV数据到DataTable
        /// </summary>
        private static DataTable GetCsvData(FileInfo file)
        {
            DataTable dataTable = new DataTable();
            StreamReader streamReader = file.OpenText();
            string oneline;

            bool bFirstRow = true;
            int columnCount = 0;
            while ((oneline = streamReader.ReadLine()) != null)
            {
                string[] itemArray = pattern.Split(oneline);
                // 获取列数
                if (bFirstRow)
                {
                    foreach (var item in itemArray)
                    {
                        DataColumn dataColumn = new DataColumn(string.Format("F{0}", ++columnCount));
                        dataTable.Columns.Add(dataColumn);
                    }
                    bFirstRow = false;
                }
                //填充数据并加入到datatable中
                dataTable.Rows.Add(itemArray.Take(columnCount).ToArray());
            }
            streamReader.Close();
            return dataTable;
        }

3.第三步读取数据生产二进制文件与对应表格类,生产二进制文件就是将DataTable结构下的数据写到数据流中最终生成一个txt文件,因为如果要热更的话bundle只支持txt热更(.bytes这种后缀或者无后缀的不支持),生产对于表格类的话就可以下写出个模板来,对应字段名替换就行,其实就当作用程序写一个txt就可以了,只不过后缀是.cs

        //表头

        /// <summary>
        /// 将DataTable数据转换为二进制格式
        /// </summary>
        private static void CreateByteData(string fileName, DataTable dt)
        {
            try
            {
                //数据格式 行数 列数 二维数组每项的值 这里不做判断 都用string存储
                string[,] tableHeadArr = null;
                byte[] buffer = null;

                using (MemoryStream ms = new MemoryStream())
                using (BinaryWriter writer = new BinaryWriter(ms))
                {
                    //行数
                    int rows = dt.Rows.Count;
                    //列数
                    int columns = dt.Columns.Count;

                    tableHeadArr = new string[columns, HeaderRows];

                    writer.Write(rows - HeaderRows); //减去表头
                    for (int i = 0; i < rows; i++)
                    {
                        for (int j = 0; j < columns; j++)
                        {
                            if (i < HeaderRows)
                            {
                                tableHeadArr[j, i] = dt.Rows[i][j].ToString().Trim();
                            }
                            else
                            {
                                if (j > 0 && tableHeadArr[j, CSRow] != "CS" && tableHeadArr[j, CSRow] != "C")
                                {
                                    continue;
                                }
                                string type = tableHeadArr[j, TypeRow];
                                string value = dt.Rows[i][j].ToString().Trim();

                                switch (type.ToLower())
                                {
                                    case "int":
                                        writer.Write(string.IsNullOrWhiteSpace(value) ? 0 : int.Parse(value));
                                        break;
                                    case "long":
                                        writer.Write(string.IsNullOrWhiteSpace(value) ? 0 : long.Parse(value));
                                        break;
                                    case "short":
                                        writer.Write(string.IsNullOrWhiteSpace(value) ? (short)0 : short.Parse(value));
                                        break;
                                    case "float":
                                        writer.Write(string.IsNullOrWhiteSpace(value) ? 0 : float.Parse(value));
                                        break;
                                    case "byte":
                                        writer.Write(string.IsNullOrWhiteSpace(value) ? (byte)0 : byte.Parse(value));
                                        break;
                                    case "bool":
                                        writer.Write(string.IsNullOrWhiteSpace(value) ? false : bool.Parse(value));
                                        break;
                                    case "double":
                                        writer.Write(string.IsNullOrWhiteSpace(value) ? 0 : double.Parse(value));
                                        break;
                                    case "vector3":
                                        try
                                        {
                                            string[] array = value.Trim('\"').Split(',');
                                            float x = float.Parse(array[0]);
                                            float y = float.Parse(array[1]);
                                            float z = float.Parse(array[2]);
                                            writer.Write(x);
                                            writer.Write(y);
                                            writer.Write(z);
                                        }
                                        catch
                                        {
                                            Debug.LogError($"解析Vector3错误! str={value}");
                                            writer.Write(0f);
                                            writer.Write(0f);
                                            writer.Write(0f);
                                        }
                                        break;
                                    case "vector2":
                                        try
                                        {
                                            string[] array = value.Trim('\"').Split(',');
                                            float x = float.Parse(array[0]);
                                            float y = float.Parse(array[1]);
                                            writer.Write(x);
                                            writer.Write(y);
                                        }
                                        catch
                                        {
                                            Debug.LogError($"解析Vector2错误! str={value}");
                                            writer.Write(0f);
                                            writer.Write(0f);
                                        }
                                        break;
                                    default:
                                        writer.Write(value);
                                        break;
                                }
                            }
                        }
                    }
                    buffer = ms.GetBuffer();
                }
                CreateTableTableData(fileName, tableHeadArr, buffer);
                CreateTableTableCSharp(fileName, tableHeadArr, buffer);
            }
            catch (System.Exception ex)
            {
                Debug.LogError("Excel=>" + fileName + " Generate Failed:" + ex.Message);
            }
        }

        /// <summary>
        /// 生成Byte文件
        /// </summary>
        private static void CreateTableTableData(string fileName, string[,] dataArr, byte[] buffer)
        {
            string path = string.Format("{0}\\{1}", OutBytesFilePath, fileName + ".txt");
            FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write);
            BinaryWriter binaryWriter = new BinaryWriter(fs);
            binaryWriter.Write(buffer);
            binaryWriter.Flush();
            binaryWriter.Close();
        }


        /// <summary>
        /// 生成代码
        /// </summary>
        private static void CreateTableTableCSharp(string fileName, string[,] dataArr, byte[] buffer)
        {
            string templateTable = File.ReadAllText(Sourcepath + "CSharpTemplate/TemplateTable.txt");
            string templateColumn = File.ReadAllText(Sourcepath + "CSharpTemplate/TemplateColumn.txt");

            StringBuilder columnSb = new StringBuilder();
            StringBuilder ctorSb = new StringBuilder();
            for (int i = 0; i < dataArr.GetLength(0); i++)
            {
                if (i == 0)
                    continue;
                if (dataArr[i, CSRow] != "CS" && dataArr[i, CSRow] != "C")
                    continue;
                columnSb.Append(string.Format(templateColumn, dataArr[i, DescriptorRow], dataArr[i, TypeRow], dataArr[i, NameRow]));
                ctorSb.AppendLine($"            {dataArr[i, NameRow]} = reader.Read{ChangeTypeNameBinaryReader(dataArr[i, TypeRow])}();");
            }

            string entityContent = templateTable.Replace("{0}", fileName).Replace("{1}", columnSb.ToString()).Replace("{2}", ctorSb.ToString());

            using (FileStream fs = new FileStream(string.Format("{0}/{1}Table.cs", OutCSharpFilePath, fileName), FileMode.Create))
            {
                using (StreamWriter sw = new StreamWriter(fs))
                {
                    sw.Write(entityContent);
                }
            }
        }

4.最后就是写一个加载的方法,同样是用模板去搞


        private static void CreateTableLoadCSharp(List<string> list)
        {
            StringBuilder sb = new StringBuilder();
            string templateLoad = File.ReadAllText(Sourcepath + "CSharpTemplate/LoadData.txt");
            for (int i = 0; i < list.Count; i++)
            {
                sb.Append(templateLoad.Replace("{1}", list[i]));
            }
            string templateTable = File.ReadAllText(Sourcepath + "CSharpTemplate/DatasLoder.txt");

            string str = templateTable.Replace("{1}", sb.ToString());
            str = str.Replace("{2}", list.Count.ToString());
            using (FileStream fs = new FileStream($"{OutCSharpFilePath}/DatasLoder.cs", FileMode.Create))
            {
                using (StreamWriter sw = new StreamWriter(fs))
                {
                    sw.Write(str);
                }
            }
        }

5.写一个管理类,用于游戏启动加载表格数据,这个就不介绍了,就是加载数据。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值