diff --git a/README.md b/README.md index 6150943..6cca0e1 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,8 @@ luban相较于常规的excel导表工具有以下核心优势: - 增强了excel格式。可以比较简洁地excel配置**任意复杂**的数据,像子结构、结构列表,以及更复杂的深层次的嵌套结构都能直接解析处理。 - 完备的类型系统和多原始数据支持(xml、json、lua、yaml),可以轻松表达和解析**任意复杂**的数据。意味着传统excel导表工具无法处理的技能、行为树、副本等等复杂配置,luban也能够统一处理了,彻底将程序从复杂的配置解析中解放出来。 - 完善的工作流支持。如id的外键引用检查;资源合法性检查;灵活的数据源定义(拆表或者多表合一);灵活的分组导出机制;多种本地化支持;生成极快(日常迭代300ms以内);Excel2TextDiff工具方便diff查看excel文件的版本间差异; -- **=== LubanAssistant Excel插件 ===**。支持把json、lua、xml等文本格式的配置数据加载到excel中,批量编辑处理,最后再保存回原文件,较好地解决大型项目中多人合作数据编辑冲突合并的问题,较好解决在编辑器中制作的配置难以在excel中批量修改的问题。 +- **LubanAssistant Excel插件**。支持把json、lua、xml等文本格式的配置数据加载到excel中,批量编辑处理,最后再保存回原文件,较好地解决大型项目中多人合作数据编辑冲突合并的问题,较好解决在编辑器中制作的配置难以在excel中批量修改的问题。 +- 支持自定义代码与数据模板。强大的数据表达能力使得绝大多数项目的配置格式往往是luban的子集,因而有较低的项目迁移成本,利用模板重新适配代码和数据生成后,即使是研发已久或者上线项目也能从luban强大的数据处理能力中受益。 ## 文档 @@ -45,12 +46,11 @@ luban相较于常规的excel导表工具有以下核心优势: ## 特性 - 支持excel族、json、xml、lua、yaml 多种数据格式,基本统一了游戏常见的配置数据 - **强大完备的类型系统**。**可以优雅表达任意复杂的数据结构**。支持所有常见原生类型、datetime类型、容器类型list,set,map、枚举和结构、**多态结构**以及**可空类型**。 -- 支持增强的excel格式。可以在excel里比较简洁填写出非常复杂的数据(比如顶层字段包含"list,A"类型字段, 而A是结构并且其中又包含"list,B"类型字段,B也是结构并且包含"list,C"这样的字段...)。 -- 生成代码清晰易读、良好模块化。特地支持运行时原子性热更新配置。 -- 生成极快。支持常规的本地缓存增量生成模式,也支持云生成模式。MMORPG这样大型项目也能秒内生成。日常增量生成基本在300ms以内,项目后期极大节省了迭代时间。另外支持**watch监测模式**,数据目录变化立即重新生成。 +- 支持增强的excel格式。可以在excel里比较简洁填写出任意复杂的嵌套数据。 +- 生成代码清晰易读、良好模块化。支持指定变量命名风格约定。特地支持运行时原子性热更新配置。 - 灵活的数据源定义。一个表可以来自多个文件或者一个文件内定义多个表或者一个目录下所有文件甚至来自云表格,以及以上的组合 - 支持表与字段级别分组。可以灵活定义分组,选择性地导出客户端或者服务器或编辑器所用的表及字段 -- 多种导出数据格式支持。支持binary、json、lua、xml 等导出数据格式 +- 多种导出数据格式支持。支持binary、json、lua、xml、erlang、**xlsx** 及自定义的导出数据格式 - 强大灵活的定制能力 - 支持代码模板,可以用自定义模板定制生成的代码格式 - **支持数据模板**,可以用模板文件定制导出格式。意味着可以在不改动现有程序代码的情况下,把luban当作**配置处理前端**,生成自定义格式的数据与自己项目的配置加载代码配合工作。开发已久的项目或者已经上线的老项目,也能从luban强大的数据处理工作流中获益 @@ -66,7 +66,10 @@ luban相较于常规的excel导表工具有以下核心优势: - 支持文本静态本地化。导出时所有text类型数据正确替换为最终的本地化字符串。绝大多数的业务功能不再需要运行根据本地化id去查找文本的内容,简化程序员的工作。 - 支持文本动态本地化。运行时动态切换所有text类型数据为目标本地化字符串。 - 支持 main + patches 数据合并。在基础数据上,施加差分数据,生成最终完整数据,适用于制作有细微不同的多地区的配置数据。 - - [TODO] 【独创】 支持任意粒度和任意类型数据(如int,bean,list,map)的本地化。 + - [TODO] 【独创】 支持任意粒度和任意类型数据(如int,bean,list,map)的本地化。 +- 生成极快。支持常规的本地缓存增量生成模式,也支持云生成模式。MMORPG这样大型项目也能秒内生成。日常增量生成基本在300ms以内,项目后期极大节省了迭代时间。另外支持**watch监测模式**,数据目录变化立即重新生成。 +- **LubanAssistant**,Luban的Excel插件。支持把json、lua、xml等文本格式的配置数据加载到excel中,批量编辑处理,最后再保存回原文件,较好地解决大型项目中多人合作数据编辑冲突合并的问题,较好解决在编辑器中制作的配置难以在excel中批量修改的问题。 +- Excel2TextDiff。将excel转成文本后再diff,清晰对比excel版本之间内容变化。 - 支持主流的游戏开发语言 - c++ (11+) - c# (.net framework 4+. dotnet core 3+) @@ -95,10 +98,6 @@ luban相较于常规的excel导表工具有以下核心优势: - 其他家基于js的小程序平台 - 其他所有支持lua的引擎和平台 - 其他所有支持js的引擎和平台 -- 扩展工具 - - Excel2TextDiff。将excel转成文本后再diff,清晰对比excel版本之间内容变化。 - - **LubanAssistant**,Luban的Excel插件。支持把json、lua、xml等文本格式的配置数据加载到excel中,批量编辑处理,最后再保存回原文件,较好地解决大型项目中多人合作数据编辑冲突合并的问题,较好解决在编辑器中制作的配置难以在excel中批量修改的问题。 - ## 增强的excel格式 luban支持在excel中解析任意复杂的数据结构,哪怕复杂如技能、行为树(但在实践中一般使用编辑器制作这些数据,以json格式保存,而不会在excel里填写)。下面从简单到复杂展示在luban中配置这些数据的方式。 diff --git a/src/Luban.Job.Cfg/Source/Cache/FileRecordCacheManager.cs b/src/Luban.Job.Cfg/Source/Cache/FileRecordCacheManager.cs index 6d1438d..ac7e567 100644 --- a/src/Luban.Job.Cfg/Source/Cache/FileRecordCacheManager.cs +++ b/src/Luban.Job.Cfg/Source/Cache/FileRecordCacheManager.cs @@ -1,4 +1,5 @@ using Luban.Job.Cfg.Datas; +using Luban.Job.Cfg.DataSources; using Luban.Job.Cfg.Defs; using System.Collections.Concurrent; using System.Collections.Generic; diff --git a/src/Luban.Job.Cfg/Source/DataConverts/LuaConvertor.cs b/src/Luban.Job.Cfg/Source/DataConverts/LuaConvertor.cs index ad8791e..0dcf2d8 100644 --- a/src/Luban.Job.Cfg/Source/DataConverts/LuaConvertor.cs +++ b/src/Luban.Job.Cfg/Source/DataConverts/LuaConvertor.cs @@ -1,4 +1,5 @@ using Luban.Job.Cfg.Datas; +using Luban.Job.Cfg.DataSources; using Luban.Job.Cfg.Defs; using Luban.Job.Cfg.Utils; using System; diff --git a/src/Luban.Job.Cfg/Source/DataExporters/BinaryExportor.cs b/src/Luban.Job.Cfg/Source/DataExporters/BinaryExportor.cs index edd9b8e..19e4857 100644 --- a/src/Luban.Job.Cfg/Source/DataExporters/BinaryExportor.cs +++ b/src/Luban.Job.Cfg/Source/DataExporters/BinaryExportor.cs @@ -1,5 +1,6 @@ using Bright.Serialization; using Luban.Job.Cfg.Datas; +using Luban.Job.Cfg.DataSources; using Luban.Job.Cfg.DataVisitors; using Luban.Job.Cfg.Defs; using System.Collections.Generic; diff --git a/src/Luban.Job.Cfg/Source/DataExporters/ErlangExport.cs b/src/Luban.Job.Cfg/Source/DataExporters/ErlangExport.cs index 9b8aa7b..5767124 100644 --- a/src/Luban.Job.Cfg/Source/DataExporters/ErlangExport.cs +++ b/src/Luban.Job.Cfg/Source/DataExporters/ErlangExport.cs @@ -1,4 +1,5 @@ using Luban.Job.Cfg.Datas; +using Luban.Job.Cfg.DataSources; using Luban.Job.Cfg.DataVisitors; using Luban.Job.Cfg.Defs; using System.Collections.Generic; diff --git a/src/Luban.Job.Cfg/Source/DataExporters/Json2Exportor.cs b/src/Luban.Job.Cfg/Source/DataExporters/Json2Exportor.cs index 4e3b265..abf62df 100644 --- a/src/Luban.Job.Cfg/Source/DataExporters/Json2Exportor.cs +++ b/src/Luban.Job.Cfg/Source/DataExporters/Json2Exportor.cs @@ -1,4 +1,5 @@ using Luban.Job.Cfg.Datas; +using Luban.Job.Cfg.DataSources; using Luban.Job.Cfg.DataVisitors; using Luban.Job.Cfg.Defs; using System; diff --git a/src/Luban.Job.Cfg/Source/DataExporters/JsonExportor.cs b/src/Luban.Job.Cfg/Source/DataExporters/JsonExportor.cs index 774f90d..faa8d04 100644 --- a/src/Luban.Job.Cfg/Source/DataExporters/JsonExportor.cs +++ b/src/Luban.Job.Cfg/Source/DataExporters/JsonExportor.cs @@ -1,4 +1,5 @@ using Luban.Job.Cfg.Datas; +using Luban.Job.Cfg.DataSources; using Luban.Job.Cfg.DataVisitors; using Luban.Job.Cfg.Defs; using System; diff --git a/src/Luban.Job.Cfg/Source/DataExporters/LuaExportor.cs b/src/Luban.Job.Cfg/Source/DataExporters/LuaExportor.cs index bf39598..e167998 100644 --- a/src/Luban.Job.Cfg/Source/DataExporters/LuaExportor.cs +++ b/src/Luban.Job.Cfg/Source/DataExporters/LuaExportor.cs @@ -1,4 +1,5 @@ using Luban.Job.Cfg.Datas; +using Luban.Job.Cfg.DataSources; using Luban.Job.Cfg.DataVisitors; using Luban.Job.Cfg.Defs; using System.Collections.Generic; diff --git a/src/Luban.Job.Cfg/Source/DataSources/Excel/ExcelDataSource.cs b/src/Luban.Job.Cfg/Source/DataSources/Excel/ExcelDataSource.cs index c7901f6..b1e6b1f 100644 --- a/src/Luban.Job.Cfg/Source/DataSources/Excel/ExcelDataSource.cs +++ b/src/Luban.Job.Cfg/Source/DataSources/Excel/ExcelDataSource.cs @@ -58,10 +58,10 @@ namespace Luban.Job.Cfg.DataSources.Excel { try { - foreach (TitleRow row in sheet.GetRows()) + foreach (var r in sheet.GetRows()) { - var tagRow = row.GetSubTitleNamedRow(TAG_KEY); - string tagStr = tagRow?.Current?.ToString(); + TitleRow row = r.Row; + string tagStr = r.Tag; if (DataUtil.IsIgnoreTag(tagStr)) { continue; diff --git a/src/Luban.Job.Cfg/Source/DataSources/Excel/RawSheet.cs b/src/Luban.Job.Cfg/Source/DataSources/Excel/RawSheet.cs index 1d772a5..98101d1 100644 --- a/src/Luban.Job.Cfg/Source/DataSources/Excel/RawSheet.cs +++ b/src/Luban.Job.Cfg/Source/DataSources/Excel/RawSheet.cs @@ -14,8 +14,6 @@ namespace Luban.Job.Cfg.DataSources.Excel public string TableName { get; set; } - public int TitleRowCount { get; set; } - public List> Cells { get; set; } } } diff --git a/src/Luban.Job.Cfg/Source/DataSources/Excel/RawSheetTableDefInfo.cs b/src/Luban.Job.Cfg/Source/DataSources/Excel/RawSheetTableDefInfo.cs index fc84db8..55e0b63 100644 --- a/src/Luban.Job.Cfg/Source/DataSources/Excel/RawSheetTableDefInfo.cs +++ b/src/Luban.Job.Cfg/Source/DataSources/Excel/RawSheetTableDefInfo.cs @@ -14,9 +14,7 @@ namespace Luban.Job.Cfg.DataSources.Excel public string Type { get; set; } - public string BriefDesc { get; set; } - - public string DetailDesc { get; set; } + public string Desc { get; set; } } class RawSheetTableDefInfo diff --git a/src/Luban.Job.Cfg/Source/DataSources/Excel/Sheet.cs b/src/Luban.Job.Cfg/Source/DataSources/Excel/Sheet.cs index 072d108..25051c8 100644 --- a/src/Luban.Job.Cfg/Source/DataSources/Excel/Sheet.cs +++ b/src/Luban.Job.Cfg/Source/DataSources/Excel/Sheet.cs @@ -20,7 +20,7 @@ namespace Luban.Job.Cfg.DataSources.Excel public string RawUrl { get; } - public List Rows { get; } = new(); + public List<(string Tag, TitleRow Row)> Rows { get; } = new(); public Sheet(string rawUrl, string name) { @@ -28,6 +28,11 @@ namespace Luban.Job.Cfg.DataSources.Excel this.Name = name; } + private string GetRowTag(List row) + { + return row.Count > 0 ? row[0].Value?.ToString() ?? "" : ""; + } + public void Load(RawSheet rawSheet) { var cells = rawSheet.Cells; @@ -41,14 +46,14 @@ namespace Luban.Job.Cfg.DataSources.Excel { continue; } - Rows.Add(ParseOneLineTitleRow(title, row)); + Rows.Add((GetRowTag(row), ParseOneLineTitleRow(title, row))); } } else { foreach (var oneRecordRows in SplitRows(title, cells)) { - Rows.Add(ParseMultiLineTitleRow(title, oneRecordRows)); + Rows.Add((GetRowTag(oneRecordRows[0]), ParseMultiLineTitleRow(title, oneRecordRows))); } } } @@ -178,7 +183,7 @@ namespace Luban.Job.Cfg.DataSources.Excel } } - public IEnumerable GetRows() + public IEnumerable<(string Tag, TitleRow Row)> GetRows() { return Rows; } diff --git a/src/Luban.Job.Cfg/Source/DataSources/Excel/SheetLoadUtil.cs b/src/Luban.Job.Cfg/Source/DataSources/Excel/SheetLoadUtil.cs index 6457e61..dc6dd17 100644 --- a/src/Luban.Job.Cfg/Source/DataSources/Excel/SheetLoadUtil.cs +++ b/src/Luban.Job.Cfg/Source/DataSources/Excel/SheetLoadUtil.cs @@ -13,10 +13,6 @@ namespace Luban.Job.Cfg.DataSources.Excel { private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger(); - private const int TITLE_MIN_ROW_NUM = 2; - private const int TITLE_MAX_ROW_NUM = 10; - private const int TITLE_DEFAULT_ROW_NUM = 3; - public static System.Text.Encoding DetectCsvEncoding(Stream fs) { Ude.CharsetDetector cdet = new Ude.CharsetDetector(); @@ -65,48 +61,18 @@ namespace Luban.Job.Cfg.DataSources.Excel private static RawSheet ParseRawSheet(IExcelDataReader reader) { bool orientRow; - int titleRowNum; - if (!TryParseMeta(reader, out orientRow, out titleRowNum, out var tableName)) + if (!TryParseMeta(reader, out orientRow, out var tableName)) { return null; } - var cells = ParseRawSheetContent(reader, orientRow); - var title = ParseTitle(cells, reader.MergeCells, orientRow, out _); - cells.RemoveRange(0, Math.Min(titleRowNum, cells.Count)); - return new RawSheet() { Title = title, TitleRowCount = titleRowNum, TableName = tableName, Cells = cells }; + var cells = ParseRawSheetContent(reader, orientRow, false); + var title = ParseTitle(cells, reader.MergeCells, orientRow); + cells.RemoveAll(c => c.Count == 0 || IsHeaderRow(c)); + return new RawSheet() { Title = title, TableName = tableName, Cells = cells }; } - private static int GetTitleRowNum(CellRange[] mergeCells, bool orientRow) - { - if (mergeCells == null) - { - return 1; - } - if (orientRow) - { - foreach (var mergeCell in mergeCells) - { - if (mergeCell.FromRow == 1 && mergeCell.FromColumn == 0) - { - return mergeCell.ToRow - mergeCell.FromRow + 1; - } - } - } - else - { - foreach (var mergeCell in mergeCells) - { - if (mergeCell.FromColumn == 1 && mergeCell.FromRow == 0) - { - return mergeCell.ToColumn - mergeCell.FromColumn + 1; - } - } - } - return 1; - } - - public static Title ParseTitle(List> cells, CellRange[] mergeCells, bool orientRow, out int titleRowNum) + public static Title ParseTitle(List> cells, CellRange[] mergeCells, bool orientRow) { var rootTitle = new Title() { @@ -117,9 +83,9 @@ namespace Luban.Job.Cfg.DataSources.Excel ToIndex = cells.Select(r => r.Count).Max() - 1 }; - titleRowNum = GetTitleRowNum(mergeCells, orientRow); + //titleRowNum = GetTitleRowNum(mergeCells, orientRow); - ParseSubTitles(rootTitle, cells, mergeCells, orientRow, 1, titleRowNum); + ParseSubTitles(rootTitle, cells, mergeCells, orientRow, 1); rootTitle.Init(); @@ -168,10 +134,10 @@ namespace Luban.Job.Cfg.DataSources.Excel return (titleName, tags); } - private static void ParseSubTitles(Title title, List> cells, CellRange[] mergeCells, bool orientRow, int curDepth, int maxDepth) + private static void ParseSubTitles(Title title, List> cells, CellRange[] mergeCells, bool orientRow, int curDepth) { - - var titleRow = cells[curDepth - 1]; + var rowIndex = curDepth - 1; + var titleRow = cells[rowIndex]; if (mergeCells != null) { foreach (var mergeCell in mergeCells) @@ -180,7 +146,7 @@ namespace Luban.Job.Cfg.DataSources.Excel if (orientRow) { //if (mergeCell.FromRow <= 1 && mergeCell.ToRow >= 1) - if (mergeCell.FromRow == curDepth && mergeCell.FromColumn >= title.FromIndex && mergeCell.FromColumn <= title.ToIndex) + if (mergeCell.FromRow == rowIndex && mergeCell.FromColumn >= title.FromIndex && mergeCell.FromColumn <= title.ToIndex) { var nameAndAttrs = titleRow[mergeCell.FromColumn].Value?.ToString()?.Trim(); if (IsIgnoreTitle(nameAndAttrs)) @@ -194,7 +160,7 @@ namespace Luban.Job.Cfg.DataSources.Excel } else { - if (mergeCell.FromColumn == curDepth - 1 && mergeCell.FromRow - 1 >= title.FromIndex && mergeCell.FromRow - 1 <= title.ToIndex) + if (mergeCell.FromColumn == rowIndex && mergeCell.FromRow - 1 >= title.FromIndex && mergeCell.FromRow - 1 <= title.ToIndex) { // 标题 行 var nameAndAttrs = titleRow[mergeCell.FromRow - 1].Value?.ToString()?.Trim(); @@ -211,9 +177,9 @@ namespace Luban.Job.Cfg.DataSources.Excel continue; } - if (curDepth < maxDepth) + if (curDepth < cells.Count && IsSubFieldRow(cells[curDepth])) { - ParseSubTitles(subTitle, cells, mergeCells, orientRow, curDepth + 1, maxDepth); + ParseSubTitles(subTitle, cells, mergeCells, orientRow, curDepth + 1); } title.AddSubTitle(subTitle); @@ -229,9 +195,9 @@ namespace Luban.Job.Cfg.DataSources.Excel } var (titleName, tags) = ParseNameAndMetaAttrs(nameAndAttrs); - if (title.SubTitles.TryGetValue(titleName, out var oldTitle)) + if (title.SubTitles.TryGetValue(titleName, out var subTitle)) { - if (oldTitle.FromIndex != i) + if (subTitle.FromIndex != i) { throw new Exception($"列:{titleName} 重复"); } @@ -240,54 +206,46 @@ namespace Luban.Job.Cfg.DataSources.Excel continue; } } - title.AddSubTitle(new Title() { Name = titleName, Tags = tags, FromIndex = i, ToIndex = i }); + subTitle = new Title() { Name = titleName, Tags = tags, FromIndex = i, ToIndex = i }; + if (curDepth < cells.Count && IsSubFieldRow(cells[curDepth])) + { + ParseSubTitles(subTitle, cells, mergeCells, orientRow, curDepth + 1); + } + title.AddSubTitle(subTitle); } } - public static bool TryParseMeta(List cells, out bool orientRow, out int titleRows, out string tableName) + public static bool TryParseMeta(string metaStr, out bool orientRow, out string tableName) { orientRow = true; - titleRows = TITLE_DEFAULT_ROW_NUM; tableName = ""; // meta 行 必须以 ##为第一个单元格内容,紧接着 key:value 形式 表达meta属性 - if (cells.Count == 0 || cells[0] != "##") + if (!metaStr.StartsWith("##")) { return false; } - foreach (var attr in cells.Skip(1)) + foreach (var attr in metaStr.Substring(2).Split("&")) { if (string.IsNullOrWhiteSpace(attr)) { continue; } - var ss = attr.Split('='); - if (ss.Length != 2) - { - throw new Exception($"单元薄 meta 定义出错. attribute:{attr}"); - } - string key = ss[0].Trim(); - string value = ss[1].Trim(); + var sepIndex = attr.IndexOf('='); + string key = sepIndex >= 0 ? attr.Substring(0, sepIndex) : attr; + string value = sepIndex >= 0 ? attr.Substring(sepIndex + 1) : ""; switch (key) { - case "orientation": + case "row": { - orientRow = DefUtil.ParseOrientation(value); + orientRow = true; break; } - case "title_rows": + case "column": { - if (!int.TryParse(value, out var v)) - { - throw new Exception($"单元薄 meta 定义 title_rows:{value} 属性值只能为整数[{TITLE_MIN_ROW_NUM},{TITLE_MAX_ROW_NUM}]"); - } - if (v < TITLE_MIN_ROW_NUM || v > TITLE_MAX_ROW_NUM) - { - throw new Exception($"单元薄 title_rows 应该在 [{TITLE_MIN_ROW_NUM},{TITLE_MAX_ROW_NUM}] 范围内,默认是{TITLE_DEFAULT_ROW_NUM}"); - } - titleRows = v; + orientRow = false; break; } case "table": @@ -297,31 +255,56 @@ namespace Luban.Job.Cfg.DataSources.Excel } default: { - throw new Exception($"非法单元薄 meta 属性定义 {attr}, 合法属性有: orientation=r|row|c|column,title_rows=,table="); + throw new Exception($"非法单元薄 meta 属性定义 {attr}, 合法属性有: row,column,table="); } } } return true; } - public static bool TryParseMeta(IExcelDataReader reader, out bool orientRow, out int titleRows, out string tableName) + public static bool TryParseMeta(IExcelDataReader reader, out bool orientRow, out string tableName) { if (!reader.Read() || reader.FieldCount == 0) { orientRow = true; - titleRows = TITLE_DEFAULT_ROW_NUM; tableName = ""; return false; } - var cells = new List(); - for (int i = 0, n = reader.FieldCount; i < n; i++) - { - cells.Add(reader.GetString(i)?.Trim()); - } - return TryParseMeta(cells, out orientRow, out titleRows, out tableName); + string metaStr = reader.GetString(0)?.Trim(); + return TryParseMeta(metaStr, out orientRow, out tableName); } - private static List> ParseRawSheetContent(IExcelDataReader reader, bool orientRow, int? maxParseRow = null) + private static bool IsSubFieldRow(List row) + { + if (row.Count == 0) + { + return false; + } + var s = row[0].Value?.ToString()?.Trim(); + return s == "##field"; + } + + private static bool IsTypeRow(List row) + { + if (row.Count == 0) + { + return false; + } + var s = row[0].Value?.ToString()?.Trim(); + return s == "##type"; + } + + private static bool IsHeaderRow(List row) + { + if (row.Count == 0) + { + return false; + } + var s = row[0].Value?.ToString()?.Trim(); + return !string.IsNullOrEmpty(s) && s.StartsWith("##"); + } + + private static List> ParseRawSheetContent(IExcelDataReader reader, bool orientRow, bool headerOnly) { // TODO 优化性能 // 几个思路 @@ -330,7 +313,7 @@ namespace Luban.Job.Cfg.DataSources.Excel // 3. 跳过null或者empty的单元格 var originRows = new List>(); int rowIndex = 0; - while (reader.Read()) + do { ++rowIndex; // 第1行是 meta ,标题及数据行从第2行开始 var row = new List(); @@ -339,11 +322,11 @@ namespace Luban.Job.Cfg.DataSources.Excel row.Add(new Cell(rowIndex, i, reader.GetValue(i))); } originRows.Add(row); - if (orientRow && maxParseRow != null && originRows.Count > maxParseRow) + if (orientRow && headerOnly && !IsHeaderRow(row)) { break; } - } + } while (reader.Read()); List> finalRows; @@ -401,22 +384,22 @@ namespace Luban.Job.Cfg.DataSources.Excel private static RawSheetTableDefInfo ParseSheetTableDefInfo(string rawUrl, IExcelDataReader reader) { bool orientRow; - int headerRowNum; - if (!TryParseMeta(reader, out orientRow, out headerRowNum, out var _)) + if (!TryParseMeta(reader, out orientRow, out var _)) { return null; } - var cells = ParseRawSheetContent(reader, orientRow, headerRowNum); - var title = ParseTitle(cells, reader.MergeCells, orientRow, out int titleRowNum); + var cells = ParseRawSheetContent(reader, orientRow, true); + var title = ParseTitle(cells, reader.MergeCells, orientRow); - if (cells.Count <= titleRowNum) + int typeRowIndex = cells.FindIndex(row => IsTypeRow(row)); + + if (typeRowIndex < 0) { throw new Exception($"缺失type行"); } - List typeRow = cells[titleRowNum]; - List briefDescRow = cells.Count > titleRowNum + 1 ? cells[titleRowNum + 1] : null; - List destailDescRow = cells.Count > titleRowNum + 2 ? cells[titleRowNum + 2] : briefDescRow; + List typeRow = cells[typeRowIndex]; + List descRow = cells.Count > typeRowIndex + 1 ? cells[typeRowIndex + 1] : null; var fields = new Dictionary(); foreach (var subTitle in title.SubTitleList) @@ -429,9 +412,8 @@ namespace Luban.Job.Cfg.DataSources.Excel { Name = subTitle.Name, Tags = title.Tags, - Type = typeRow?[subTitle.FromIndex].Value?.ToString() ?? "", - BriefDesc = briefDescRow?[subTitle.FromIndex].Value?.ToString() ?? "", - DetailDesc = destailDescRow?[subTitle.FromIndex].Value?.ToString() ?? "", + Type = typeRow[subTitle.FromIndex].Value?.ToString() ?? "", + Desc = descRow?[subTitle.FromIndex].Value?.ToString() ?? "", }); } diff --git a/src/Luban.Job.Cfg/Source/Datas/Record.cs b/src/Luban.Job.Cfg/Source/DataSources/Record.cs similarity index 85% rename from src/Luban.Job.Cfg/Source/Datas/Record.cs rename to src/Luban.Job.Cfg/Source/DataSources/Record.cs index 1b8209f..5d27274 100644 --- a/src/Luban.Job.Cfg/Source/Datas/Record.cs +++ b/src/Luban.Job.Cfg/Source/DataSources/Record.cs @@ -1,6 +1,7 @@ -using System.Collections.Generic; +using Luban.Job.Cfg.Datas; +using System.Collections.Generic; -namespace Luban.Job.Cfg.Datas +namespace Luban.Job.Cfg.DataSources { public class Record { diff --git a/src/Luban.Job.Cfg/Source/DataVisitors/ValidatorVisitor.cs b/src/Luban.Job.Cfg/Source/DataVisitors/ValidatorVisitor.cs index ea87b1c..1ad671b 100644 --- a/src/Luban.Job.Cfg/Source/DataVisitors/ValidatorVisitor.cs +++ b/src/Luban.Job.Cfg/Source/DataVisitors/ValidatorVisitor.cs @@ -1,5 +1,6 @@ using Luban.Common.Utils; using Luban.Job.Cfg.Datas; +using Luban.Job.Cfg.DataSources; using Luban.Job.Cfg.Defs; using Luban.Job.Cfg.Validators; using Luban.Job.Common.Types; diff --git a/src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs b/src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs index 5833c9c..a1ed49d 100644 --- a/src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs +++ b/src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs @@ -311,17 +311,7 @@ namespace Luban.Job.Cfg.Defs throw new Exception($"table:'{table.Name}' file:{file.OriginFile} title:'{name}' type missing!"); } - // 优先取desc行,如果为空,则取title行 - - cf.Comment = f.BriefDesc; - if (string.IsNullOrWhiteSpace(cf.Comment)) - { - cf.Comment = f.DetailDesc; - } - if (string.IsNullOrWhiteSpace(cf.Comment)) - { - cf.Comment = ""; - } + cf.Comment = f.Desc; cf.Type = attrs[0]; diff --git a/src/Luban.Job.Cfg/Source/Defs/DefAssembly.cs b/src/Luban.Job.Cfg/Source/Defs/DefAssembly.cs index c7a3e53..89feb56 100644 --- a/src/Luban.Job.Cfg/Source/Defs/DefAssembly.cs +++ b/src/Luban.Job.Cfg/Source/Defs/DefAssembly.cs @@ -1,5 +1,6 @@ using Bright.Collections; using Luban.Job.Cfg.Datas; +using Luban.Job.Cfg.DataSources; #if !LUBAN_LITE using Luban.Job.Cfg.l10n; #endif diff --git a/src/Luban.Job.Cfg/Source/Utils/DataConvertUtil.cs b/src/Luban.Job.Cfg/Source/Utils/DataConvertUtil.cs index 16ed186..4e4188c 100644 --- a/src/Luban.Job.Cfg/Source/Utils/DataConvertUtil.cs +++ b/src/Luban.Job.Cfg/Source/Utils/DataConvertUtil.cs @@ -1,5 +1,6 @@ using Luban.Job.Cfg.DataConverts; using Luban.Job.Cfg.Datas; +using Luban.Job.Cfg.DataSources; using Luban.Job.Cfg.Defs; using Luban.Job.Cfg.Utils; using System; diff --git a/src/Luban.Job.Cfg/Source/Utils/DataExporterUtil.cs b/src/Luban.Job.Cfg/Source/Utils/DataExporterUtil.cs index dc97170..0335050 100644 --- a/src/Luban.Job.Cfg/Source/Utils/DataExporterUtil.cs +++ b/src/Luban.Job.Cfg/Source/Utils/DataExporterUtil.cs @@ -2,6 +2,7 @@ using Luban.Job.Cfg.DataConverts; using Luban.Job.Cfg.DataExporters; using Luban.Job.Cfg.Datas; +using Luban.Job.Cfg.DataSources; using Luban.Job.Cfg.DataVisitors; using Luban.Job.Cfg.Defs; using Luban.Job.Cfg.l10n; diff --git a/src/Luban.Job.Cfg/Source/ValidatorContext.cs b/src/Luban.Job.Cfg/Source/ValidatorContext.cs index c7c39c1..527349b 100644 --- a/src/Luban.Job.Cfg/Source/ValidatorContext.cs +++ b/src/Luban.Job.Cfg/Source/ValidatorContext.cs @@ -1,6 +1,7 @@ using Bright.Collections; using Luban.Common.Utils; using Luban.Job.Cfg.Datas; +using Luban.Job.Cfg.DataSources; using Luban.Job.Cfg.DataVisitors; using Luban.Job.Cfg.Defs; using Luban.Job.Cfg.RawDefs; diff --git a/src/Luban.Job.Cfg/Source/l10n/RawTextTable.cs b/src/Luban.Job.Cfg/Source/l10n/RawTextTable.cs index a5c2cfd..7a64485 100644 --- a/src/Luban.Job.Cfg/Source/l10n/RawTextTable.cs +++ b/src/Luban.Job.Cfg/Source/l10n/RawTextTable.cs @@ -1,4 +1,5 @@ using Luban.Job.Cfg.Datas; +using Luban.Job.Cfg.DataSources; using System; using System.Collections.Concurrent;