diff --git a/README.md b/README.md index a5abbeb..aff707e 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,7 @@ luban是一个通用型对象生成与缓存方案, 在此基础上实现了一个功能**完备强大灵活易用**的 **游戏配置解决方案**。 -luban最初为无缝开放世界MMORPG这样的超大型项目而设计,擅长处理大型复杂的配置数据和结构,也适合向下用于卡牌、回合制、SLG等中轻度游戏。 - -luban基于 **meta定义 + 数据源** 的设计,实现了**完备的类型系统**,增强了excel格式,同时提供json、xml、lua等多种数据源支持,统一了数据定义、加载、检验、数据导出及代码生成的游戏配置Pipeline,彻底解决了中大型项目中难以在excel中配置复杂数据以及一个项目中excel、json等多种的配置方案并存的问题。 +luban基于 **meta定义 + 数据源** 的设计,实现了**完备的类型系统**,增强了excel格式,同时提供json、xml、lua等丰富的数据源支持。既可以处理常规的简单配置,也完美处理**AI、技能、副本**等复杂配置,真正实现了统一数据定义、加载、检验、数据导出及代码生成的游戏配置工作流,彻底解决了中大型项目中需要程序员手动处理复杂配置的问题。 Luban生成过程极快。对于普通的导表工具,一个典型的MMORPG项目后期全量生成配置往往需要几十秒。Luban使用client/server的云生成模型,通过多线程并发生成+对象缓存机制,大多数情况下可以1s内完成整个生成过程。 diff --git a/src/Luban.Job.Cfg/Source/DataCreators/ExcelDataCreator.cs b/src/Luban.Job.Cfg/Source/DataCreators/ExcelDataCreator.cs index 881864f..4c9c8e5 100644 --- a/src/Luban.Job.Cfg/Source/DataCreators/ExcelDataCreator.cs +++ b/src/Luban.Job.Cfg/Source/DataCreators/ExcelDataCreator.cs @@ -75,23 +75,52 @@ namespace Luban.Job.Cfg.DataCreators } } + private bool CheckIsDefault(bool namedMode, object value) + { + if (namedMode) + { + if (value == null || (value is string s && string.IsNullOrEmpty(s))) + { + return true; + } + } + return false; + } + public DType Accept(TBool type, object converter, ExcelStream x, DefAssembly ass) { - var d = x.Read(); + if (x.NamedMode && x.IncludeNullAndEmptySize != 1) + { + throw new InvalidExcelDataException("在标题头对应模式下必须正好占据1个单元格"); + } + + var d = x.Read(x.NamedMode); if (CheckNull(type.IsNullable, d)) { return null; } + if (CheckIsDefault(x.NamedMode, d)) + { + return new DBool(false); + } return new DBool(CreateBool(d)); } public DType Accept(TByte type, object converter, ExcelStream x, DefAssembly ass) { - var d = x.Read(); + if (x.NamedMode && x.IncludeNullAndEmptySize != 1) + { + throw new InvalidExcelDataException("在标题头对应模式下必须正好占据1个单元格"); + } + var d = x.Read(x.NamedMode); if (CheckNull(type.IsNullable, d)) { return null; } + if (CheckIsDefault(x.NamedMode, d)) + { + return DByte.Default; + } if (!byte.TryParse(d.ToString(), out byte v)) { throw new InvalidExcelDataException($"{d} 不是 byte 类型值"); @@ -101,11 +130,19 @@ namespace Luban.Job.Cfg.DataCreators public DType Accept(TShort type, object converter, ExcelStream x, DefAssembly ass) { - var d = x.Read(); + if (x.NamedMode && x.IncludeNullAndEmptySize != 1) + { + throw new InvalidExcelDataException("在标题头对应模式下必须正好占据1个单元格"); + } + var d = x.Read(x.NamedMode); if (CheckNull(type.IsNullable, d)) { return null; } + if (CheckIsDefault(x.NamedMode, d)) + { + return DShort.Default; + } if (!short.TryParse(d.ToString(), out short v)) { throw new InvalidExcelDataException($"{d} 不是 short 类型值"); @@ -115,11 +152,19 @@ namespace Luban.Job.Cfg.DataCreators public DType Accept(TFshort type, object converter, ExcelStream x, DefAssembly ass) { - var d = x.Read(); + if (x.NamedMode && x.IncludeNullAndEmptySize != 1) + { + throw new InvalidExcelDataException("在标题头对应模式下必须正好占据1个单元格"); + } + var d = x.Read(x.NamedMode); if (CheckNull(type.IsNullable, d)) { return null; } + if (CheckIsDefault(x.NamedMode, d)) + { + return DFshort.Default; + } if (!short.TryParse(d.ToString(), out short v)) { throw new InvalidExcelDataException($"{d} 不是 short 类型值"); @@ -129,11 +174,19 @@ namespace Luban.Job.Cfg.DataCreators public DType Accept(TInt type, object converter, ExcelStream x, DefAssembly ass) { - var d = x.Read(); + if (x.NamedMode && x.IncludeNullAndEmptySize != 1) + { + throw new InvalidExcelDataException("在标题头对应模式下必须正好占据1个单元格"); + } + var d = x.Read(x.NamedMode); if (CheckNull(type.IsNullable, d)) { return null; } + if (CheckIsDefault(x.NamedMode, d)) + { + return DInt.Default; + } var ds = d.ToString(); if (converter is TEnum te) { @@ -151,11 +204,19 @@ namespace Luban.Job.Cfg.DataCreators public DType Accept(TFint type, object converter, ExcelStream x, DefAssembly ass) { - var d = x.Read(); + if (x.NamedMode && x.IncludeNullAndEmptySize != 1) + { + throw new InvalidExcelDataException("在标题头对应模式下必须正好占据1个单元格"); + } + var d = x.Read(x.NamedMode); if (CheckNull(type.IsNullable, d)) { return null; } + if (CheckIsDefault(x.NamedMode, d)) + { + return DFint.Default; + } var ds = d.ToString(); if (converter is TEnum te) { @@ -173,11 +234,19 @@ namespace Luban.Job.Cfg.DataCreators public DType Accept(TLong type, object converter, ExcelStream x, DefAssembly ass) { - var d = x.Read(); + if (x.NamedMode && x.IncludeNullAndEmptySize != 1) + { + throw new InvalidExcelDataException("在标题头对应模式下必须正好占据1个单元格"); + } + var d = x.Read(x.NamedMode); if (CheckNull(type.IsNullable, d)) { return null; } + if (CheckIsDefault(x.NamedMode, d)) + { + return DLong.Default; + } var ds = d.ToString(); if (converter is TEnum te) { @@ -195,11 +264,19 @@ namespace Luban.Job.Cfg.DataCreators public DType Accept(TFlong type, object converter, ExcelStream x, DefAssembly ass) { - var d = x.Read(); + if (x.NamedMode && x.IncludeNullAndEmptySize != 1) + { + throw new InvalidExcelDataException("在标题头对应模式下必须正好占据1个单元格"); + } + var d = x.Read(x.NamedMode); if (CheckNull(type.IsNullable, d)) { return null; } + if (CheckIsDefault(x.NamedMode, d)) + { + return DFlong.Default; + } var ds = d.ToString(); if (converter is TEnum te) { @@ -217,11 +294,19 @@ namespace Luban.Job.Cfg.DataCreators public DType Accept(TFloat type, object converter, ExcelStream x, DefAssembly ass) { - var d = x.Read(); + if (x.NamedMode && x.IncludeNullAndEmptySize != 1) + { + throw new InvalidExcelDataException("在标题头对应模式下必须正好占据1个单元格"); + } + var d = x.Read(x.NamedMode); if (CheckNull(type.IsNullable, d)) { return null; } + if (CheckIsDefault(x.NamedMode, d)) + { + return DFloat.Default; + } if (!float.TryParse(d.ToString(), out var v)) { throw new InvalidExcelDataException($"{d} 不是 float 类型值"); @@ -231,11 +316,19 @@ namespace Luban.Job.Cfg.DataCreators public DType Accept(TDouble type, object converter, ExcelStream x, DefAssembly ass) { - var d = x.Read(); + if (x.NamedMode && x.IncludeNullAndEmptySize != 1) + { + throw new InvalidExcelDataException("在标题头对应模式下必须正好占据1个单元格"); + } + var d = x.Read(x.NamedMode); if (CheckNull(type.IsNullable, d)) { return null; } + if (CheckIsDefault(x.NamedMode, d)) + { + return DDouble.Default; + } if (!double.TryParse(d.ToString(), out var v)) { throw new InvalidExcelDataException($"{d} 不是 double 类型值"); diff --git a/src/Luban.Job.Cfg/Source/Datas/DByte.cs b/src/Luban.Job.Cfg/Source/Datas/DByte.cs index fec0d46..4b4d12f 100644 --- a/src/Luban.Job.Cfg/Source/Datas/DByte.cs +++ b/src/Luban.Job.Cfg/Source/Datas/DByte.cs @@ -4,6 +4,8 @@ namespace Luban.Job.Cfg.Datas { public class DByte : DType { + public static DByte Default { get; } = new DByte(0); + public DByte(byte x) : base(x) { } diff --git a/src/Luban.Job.Cfg/Source/Datas/DDouble.cs b/src/Luban.Job.Cfg/Source/Datas/DDouble.cs index 2964b27..38ffc3a 100644 --- a/src/Luban.Job.Cfg/Source/Datas/DDouble.cs +++ b/src/Luban.Job.Cfg/Source/Datas/DDouble.cs @@ -4,6 +4,8 @@ namespace Luban.Job.Cfg.Datas { public class DDouble : DType { + public static DDouble Default { get; } = new DDouble(0); + public DDouble(double x) : base(x) { } diff --git a/src/Luban.Job.Cfg/Source/Datas/DFint.cs b/src/Luban.Job.Cfg/Source/Datas/DFint.cs index 1d40629..134ed47 100644 --- a/src/Luban.Job.Cfg/Source/Datas/DFint.cs +++ b/src/Luban.Job.Cfg/Source/Datas/DFint.cs @@ -4,6 +4,8 @@ namespace Luban.Job.Cfg.Datas { public class DFint : DType { + public static DFint Default { get; } = new DFint(0); + public DFint(int x) : base(x) { } diff --git a/src/Luban.Job.Cfg/Source/Datas/DFloat.cs b/src/Luban.Job.Cfg/Source/Datas/DFloat.cs index fca2b39..aec0357 100644 --- a/src/Luban.Job.Cfg/Source/Datas/DFloat.cs +++ b/src/Luban.Job.Cfg/Source/Datas/DFloat.cs @@ -4,6 +4,8 @@ namespace Luban.Job.Cfg.Datas { public class DFloat : DType { + public static DFloat Default { get; } = new DFloat(0); + public DFloat(float x) : base(x) { } diff --git a/src/Luban.Job.Cfg/Source/Datas/DFlong.cs b/src/Luban.Job.Cfg/Source/Datas/DFlong.cs index 9cdd929..1d7fec6 100644 --- a/src/Luban.Job.Cfg/Source/Datas/DFlong.cs +++ b/src/Luban.Job.Cfg/Source/Datas/DFlong.cs @@ -4,6 +4,8 @@ namespace Luban.Job.Cfg.Datas { public class DFlong : DType { + public static DFlong Default { get; } = new DFlong(0); + public DFlong(long x) : base(x) { } diff --git a/src/Luban.Job.Cfg/Source/Datas/DFshort.cs b/src/Luban.Job.Cfg/Source/Datas/DFshort.cs index 41ba1fe..96483cc 100644 --- a/src/Luban.Job.Cfg/Source/Datas/DFshort.cs +++ b/src/Luban.Job.Cfg/Source/Datas/DFshort.cs @@ -4,6 +4,8 @@ namespace Luban.Job.Cfg.Datas { public class DFshort : DType { + public static DFshort Default { get; } = new DFshort(0); + public DFshort(short x) : base(x) { } diff --git a/src/Luban.Job.Cfg/Source/Datas/DInt.cs b/src/Luban.Job.Cfg/Source/Datas/DInt.cs index d99bfce..f3dd7a6 100644 --- a/src/Luban.Job.Cfg/Source/Datas/DInt.cs +++ b/src/Luban.Job.Cfg/Source/Datas/DInt.cs @@ -4,6 +4,8 @@ namespace Luban.Job.Cfg.Datas { public class DInt : DType { + public static DInt Default { get; } = new DInt(0); + public DInt(int x) : base(x) { } diff --git a/src/Luban.Job.Cfg/Source/Datas/DLong.cs b/src/Luban.Job.Cfg/Source/Datas/DLong.cs index 45c66c4..4608413 100644 --- a/src/Luban.Job.Cfg/Source/Datas/DLong.cs +++ b/src/Luban.Job.Cfg/Source/Datas/DLong.cs @@ -4,6 +4,8 @@ namespace Luban.Job.Cfg.Datas { public class DLong : DType { + public static DLong Default { get; } = new DLong(0); + public DLong(long x) : base(x) { } diff --git a/src/Luban.Job.Cfg/Source/Datas/DShort.cs b/src/Luban.Job.Cfg/Source/Datas/DShort.cs index 2a4e0f4..073af78 100644 --- a/src/Luban.Job.Cfg/Source/Datas/DShort.cs +++ b/src/Luban.Job.Cfg/Source/Datas/DShort.cs @@ -4,6 +4,8 @@ namespace Luban.Job.Cfg.Datas { public class DShort : DType { + public static DShort Default { get; } = new DShort(0); + public DShort(short x) : base(x) { }