diff --git a/README.md b/README.md index 74d17f0..89bd1b6 100644 --- a/README.md +++ b/README.md @@ -24,9 +24,12 @@ Luban适合有以下需求的开发者: 3. 希望做其他自定义生成或者缓存 + +====**如果觉得不错,烦请点个star,你的支持会给予我们巨大动力 ^_^**==== + ## 支持和联系 -有使用上的疑问请即时加QQ群询问,随时帮助解决。 +有使用方面的疑问请及时加QQ群询问,随时有人帮助解决。 - QQ 群: 692890842 - 邮箱: taojingjian#gmail.com @@ -44,19 +47,19 @@ Luban适合有以下需求的开发者: - [示例项目](https://github.com/focus-creative-games/luban_examples) ## 特性 -- 支持增强的excel格式,可以在excel里比较简洁填写出任意复杂的数据。 +- 支持增强的excel格式,可以在excel里比较简洁填写出任意复杂的数据 - 支持excel族、json、xml、lua 多种数据格式,基本统一了游戏内的配置数据 -- 灵活的数据源定义。一个表可以来自多个文件或者一个文件内定义多个表或者一个表对应一个目录下所有文件,以及以上的组合。 -- 强大完备的类型系统。支持所有常见原生类型、容器类型list,set,map、枚举和结构、**多态结构**以及**可空类型**。 -- 支持表与字段级别分组。可以选择性地导出客户端或者服务器所用的表及字段。 -- 多种导出数据格式支持。支持binary、json、lua 等导出数据格式。 -- 支持数据标签。 可以选择导出符合要求的数据,发布正式数据时策划不必手动注释掉那些测试或者非正式数据了。 -- 强大的数据校验能力。支持内建数据格式检查;支持ref表引用检查(策划不用担心填错id);支持path资源检查(策划不用担心填错资源路径)。 -- 支持常量别名。策划不必再为诸如 升级丹 这样的道具手写具体道具id了。 +- 强大完备的类型系统。支持所有常见原生类型、容器类型list,set,map、枚举和结构、**多态结构**以及**可空类型** +- 灵活的数据源定义。一个表可以来自多个文件或者一个文件内定义多个表或者一个表对应一个目录下所有文件,以及以上的组合 +- 支持表与字段级别分组。可以选择性地导出客户端或者服务器所用的表及字段 +- 多种导出数据格式支持。支持binary、json、lua 等导出数据格式 +- 支持数据标签。 可以选择导出符合要求的数据,发布正式数据时策划不必手动注释掉那些测试或者非正式数据了 +- 强大的数据校验能力。支持内建数据格式检查;支持ref表引用检查(策划不用担心填错id);支持path资源检查(策划不用担心填错资源路径);支持高级自定义校验(比如两字段和必须100) +- 支持常量别名。策划不必再为诸如 升级丹 这样的道具手写具体道具id了 - 支持多种常见数据表模式。 one(单例表)、map(常规key-value表) -- 支持emmylua anntations。生成的lua包含符合emmylua 格式anntations信息。配合emmylua有良好的配置代码提示能力。 +- 支持emmylua anntations。生成的lua包含符合emmylua 格式anntations信息。配合emmylua有良好的配置代码提示能力 - 支持res资源标记。可以一键导出配置中引用的所有资源列表(icon,ui,assetbundle等等) -- 生成代码良好模块化。 +- 生成代码良好模块化 - **本地化支持** - 支持时间本地化。datetime类型数据会根据指定的timezone,转换为目标地区该时刻的UTC时间,方便程序使用。 - **支持文本静态本地化。导出时所有text类型数据正确替换为最终的本地化字符串。** @@ -200,7 +203,7 @@ Luban适合有以下需求的开发者: ![ex_32](docs/images/examples/ex_32.png) ### 可空数据类型 -配置数据中经常有空值的语义需求,实际项目中往往混杂地使用0或-1表达空值,既不自然清晰也不统一。luban借鉴了c#中的可空变量的概念,特地提供可空数据支持。除了string外的所有原生数据类型,以及enum、bean、和多态bean类型都有相应的可空数据类型。定义方式为 <类型名>?,与c#里的Nullable类型定义方式相同。例如 bool?,int?,long?,double?, EColor?, DemoType? +配置数据中经常有空值的语义需求,实际项目中往往混杂地使用0或-1表达空值,既不自然清晰也不统一。luban借鉴了c#中的可空变量的概念,特地提供可空数据支持。所有原生数据类型,以及enum、bean、和多态bean类型都有相应的可空数据类型。定义方式为 <类型名>?,与c#里的Nullable类型定义方式相同。例如 bool?,int?,long?,double?, EColor?, DemoType? ```xml diff --git a/src/Luban.Job.Cfg/Source/DataCreators/ExcelDataCreator.cs b/src/Luban.Job.Cfg/Source/DataCreators/ExcelDataCreator.cs index c7df47d..3b25d16 100644 --- a/src/Luban.Job.Cfg/Source/DataCreators/ExcelDataCreator.cs +++ b/src/Luban.Job.Cfg/Source/DataCreators/ExcelDataCreator.cs @@ -259,7 +259,19 @@ namespace Luban.Job.Cfg.DataCreators { throw new InvalidExcelDataException("excel string类型在标题头对应模式下必须正好占据一个单元格"); } - return new DString(ParseString(x.Read(x.NamedMode))); + var s = ParseString(x.Read(x.NamedMode)); + if (s == null) + { + if (type.IsNullable) + { + return null; + } + else + { + throw new InvalidExcelDataException("字段不是nullable类型,不能为null"); + } + } + return new DString(s); } public DType Accept(TBytes type, object converter, ExcelStream x, DefAssembly ass) @@ -271,7 +283,7 @@ namespace Luban.Job.Cfg.DataCreators { if (d == null) { - return ""; + return string.Empty; } else if (d is string s) { @@ -290,6 +302,18 @@ namespace Luban.Job.Cfg.DataCreators throw new InvalidExcelDataException("excel text 类型在标题头对应模式下必须正好占据2个单元格"); } string key = ParseString(x.Read(x.NamedMode)); + if (key == null) + { + if (type.IsNullable) + { + return null; + } + else + { + throw new InvalidExcelDataException("该字段不是nullable类型,不能为null"); + } + } + string text = ParseString(x.Read(x.NamedMode)); DataUtil.ValidateText(key, text); return new DText(key, text); diff --git a/src/Luban.Job.Cfg/Source/DataCreators/JsonDataCreator.cs b/src/Luban.Job.Cfg/Source/DataCreators/JsonDataCreator.cs index 35052f3..fb15067 100644 --- a/src/Luban.Job.Cfg/Source/DataCreators/JsonDataCreator.cs +++ b/src/Luban.Job.Cfg/Source/DataCreators/JsonDataCreator.cs @@ -134,15 +134,33 @@ namespace Luban.Job.Cfg.DataCreators { if (x.TryGetProperty(field.Name, out var ele)) { - try + if (ele.ValueKind == JsonValueKind.Null || ele.ValueKind == JsonValueKind.Undefined) { - fields.Add(field.CType.Apply(this, ele, ass)); + if (field.CType.IsNullable) + { + fields.Add(null); + } + else + { + throw new Exception($"结构:{implBean.FullName} 字段:{field.Name} 不能 null or undefined "); + } } - catch (Exception e) + else { - throw new Exception($"结构:{implBean.FullName} 字段:{field.Name} 读取失败 => {e.Message}", e); + try + { + fields.Add(field.CType.Apply(this, ele, ass)); + } + catch (Exception e) + { + throw new Exception($"结构:{implBean.FullName} 字段:{field.Name} 读取失败 => {e.Message}", e); + } } } + else if (field.CType.IsNullable) + { + fields.Add(null); + } else { throw new Exception($"结构:{implBean.FullName} 字段:{field.Name} 缺失"); diff --git a/src/Luban.Job.Cfg/Source/DataCreators/LuaDataCreator.cs b/src/Luban.Job.Cfg/Source/DataCreators/LuaDataCreator.cs index 75ba801..7619559 100644 --- a/src/Luban.Job.Cfg/Source/DataCreators/LuaDataCreator.cs +++ b/src/Luban.Job.Cfg/Source/DataCreators/LuaDataCreator.cs @@ -188,6 +188,10 @@ namespace Luban.Job.Cfg.DataCreators throw new Exception($"结构:{implBean.FullName} 字段:{field.Name} 读取失败 => {e.Message}", e); } } + else if (field.CType.IsNullable) + { + fields.Add(null); + } else { throw new Exception($"结构:{implBean.FullName} 字段:{field.Name} 缺失"); diff --git a/src/Luban.Job.Cfg/Source/DataCreators/XmlDataCreator.cs b/src/Luban.Job.Cfg/Source/DataCreators/XmlDataCreator.cs index 094c576..0e1c082 100644 --- a/src/Luban.Job.Cfg/Source/DataCreators/XmlDataCreator.cs +++ b/src/Luban.Job.Cfg/Source/DataCreators/XmlDataCreator.cs @@ -120,9 +120,13 @@ namespace Luban.Job.Cfg.DataCreators XElement fele = feles.FirstOrDefault(); if (fele == null) { + if (field.CType.IsNullable) + { + fields.Add(null); + continue; + } throw new Exception($"字段:{field.Name} 缺失"); } - try { fields.Add(field.CType.Apply(this, fele, ass)); diff --git a/src/Luban.Job.Cfg/Source/Utils/DataUtil.cs b/src/Luban.Job.Cfg/Source/Utils/DataUtil.cs index 1af1222..d27ea30 100644 --- a/src/Luban.Job.Cfg/Source/Utils/DataUtil.cs +++ b/src/Luban.Job.Cfg/Source/Utils/DataUtil.cs @@ -70,11 +70,12 @@ namespace Luban.Job.Cfg.Utils public static string UnEscapeString(string s) { - if (s == "null" || s == "\"\"") + switch (s) { - return ""; + case "null": return null; + case "\"\"": return string.Empty; + default: return s; } - return s; } public static (string Key, string Text) ExtractText(string rawKeyAndText)