【特性】新增validator set, 要求值必须在某一集合内

【重构】重构validator,基于注解获得所有Validator类
main
walon 2021-11-22 15:50:05 +08:00
parent f024ec6974
commit 5e56d35e4a
26 changed files with 160 additions and 67 deletions

View File

@ -18,7 +18,7 @@
## 介绍
在中大型游戏项目中excel配置表时常出现较复杂的数据结构常规的导表工具面对此类需求要么无法支持要么就强迫策划和程序使用拆表等奇技淫巧严重影响设计和开发效率。另外具有复杂GamePlay的游戏中技能、行为树、关卡之类的功能有非常复杂的数据结构往往使用自定义编辑器制作并以json、xml等文件格式保存以excel为中心的导表工具无法处理这些数据给策划和程序的工作流带来麻烦。
在中大型游戏项目中excel配置表时常出现较复杂的数据结构常规的导表工具面对此类需求要么无法支持要么就强迫策划和程序使用拆表等奇技淫巧严重影响设计和开发效率。另外具有复杂GamePlay的游戏中技能、行为树、关卡之类的功能有非常复杂的数据结构,它们往往使用自定义编辑器制作并以json、xml等文件格式保存以excel为中心的导表工具无法处理这些数据给策划和程序的工作流带来麻烦。
luban相较于常规的excel导表工具有以下核心优势
- 增强了excel格式。可以比较简洁地excel配置**任意复杂**的数据,像子结构、结构列表,以及更复杂的深层次的嵌套结构都能直接解析处理。
@ -30,7 +30,7 @@ luban相较于常规的excel导表工具有以下核心优势
## 文档
- [快速上手](docs/start_up.md)
- [wiki](https://github.com/focus-creative-games/luban/wiki) 有使用疑问请先查看此wiki。
- [**wiki**](https://github.com/focus-creative-games/luban/wiki) ,比较完善,有使用疑问请先查看此wiki。
- **示例项目** ([github](https://github.com/focus-creative-games/luban_examples)) ([gitee](https://gitee.com/focus-creative-games/luban_examples))
- [版本变更记录](https://github.com/focus-creative-games/luban/wiki/%E7%89%88%E6%9C%AC%E5%8F%98%E6%9B%B4%E8%AE%B0%E5%BD%95)

View File

@ -49,7 +49,7 @@ namespace Luban.Client.Utils
}
}
private readonly static List<string> _filterSuffixs = new List<string>
private static readonly List<string> _filterSuffixs = new List<string>
{
".xlsx",
".csv",

View File

@ -30,7 +30,7 @@ namespace Luban.Job.Cfg.DataConverts
public override string Accept(DEnum type)
{
return type.Value.ToString();
return $"'{type.StrValue}'";
}
public override string Accept(DBean type)

View File

@ -91,8 +91,8 @@ namespace Luban.Job.Cfg.DataCreators
throw new NotSupportedException();
}
private readonly static YamlScalarNode s_keyNodeName = new("key");
private readonly static YamlScalarNode s_textNodeName = new("text");
private static readonly YamlScalarNode s_keyNodeName = new("key");
private static readonly YamlScalarNode s_textNodeName = new("text");
public DType Accept(TText type, YamlNode x, DefAssembly y)
{
@ -102,7 +102,7 @@ namespace Luban.Job.Cfg.DataCreators
return new DText(key, text);
}
private readonly static YamlScalarNode s_typeNodeName = new(DefBean.TYPE_NAME_KEY);
private static readonly YamlScalarNode s_typeNodeName = new(DefBean.TYPE_NAME_KEY);
public DType Accept(TBean type, YamlNode x, DefAssembly y)
{
@ -204,10 +204,10 @@ namespace Luban.Job.Cfg.DataCreators
return new DMap(type, map);
}
private readonly static YamlScalarNode s_xNodeName = new("x");
private readonly static YamlScalarNode s_yNodeName = new("y");
private readonly static YamlScalarNode s_zNodeName = new("z");
private readonly static YamlScalarNode s_wNodeName = new("w");
private static readonly YamlScalarNode s_xNodeName = new("x");
private static readonly YamlScalarNode s_yNodeName = new("y");
private static readonly YamlScalarNode s_zNodeName = new("z");
private static readonly YamlScalarNode s_wNodeName = new("w");
private static float ParseChildFloatValue(YamlNode node, YamlScalarNode keyName)
{

View File

@ -10,7 +10,7 @@ namespace Luban.Job.Cfg.DataExporters
{
class Json2Exportor : JsonExportor
{
public new static Json2Exportor Ins { get; } = new();
public static new Json2Exportor Ins { get; } = new();
public void WriteAsObject(DefTable table, List<Record> datas, Utf8JsonWriter x)
{

View File

@ -51,7 +51,7 @@ namespace Luban.Job.Cfg.DataSources.Yaml
return records;
}
private readonly static YamlScalarNode s_tagNameNode = new(TAG_KEY);
private static readonly YamlScalarNode s_tagNameNode = new(TAG_KEY);
public override Record ReadOne(TBean type)
{

View File

@ -0,0 +1,23 @@
using Luban.Job.Cfg.Datas;
using Luban.Job.Cfg.Defs;
using Luban.Job.Cfg.Utils;
using System.Collections.Generic;
using System.Text;
namespace Luban.Job.Cfg.DataVisitors
{
class ToStringVisitor2 : ToStringVisitor
{
public static new ToStringVisitor2 Ins { get; } = new();
public override string Accept(DEnum type)
{
return type.Value.ToString();
}
public override string Accept(DString type)
{
return DataUtil.EscapeString(type.Value);
}
}
}

View File

@ -49,7 +49,7 @@ namespace Luban.Job.Cfg.DataVisitors
}
protected override void Append(List<DType> datas, StringBuilder x)
override protected void Append(List<DType> datas, StringBuilder x)
{
x.Append('{');
foreach (var e in datas)

View File

@ -2,6 +2,7 @@ using Luban.Common.Utils;
using Luban.Job.Cfg.Datas;
using Luban.Job.Cfg.DataSources;
using Luban.Job.Cfg.Defs;
using Luban.Job.Cfg.Utils;
using Luban.Job.Cfg.Validators;
using Luban.Job.Common.Types;
using Luban.Job.Common.TypeVisitors;
@ -12,7 +13,6 @@ namespace Luban.Job.Cfg.DataVisitors
{
public class ValidatorVisitor : TypeActionVisitorAdaptor<DType>
{
public const string TAG_UNCHECKED = "unchecked";
private readonly Stack<object> _path = new Stack<object>();
@ -33,7 +33,7 @@ namespace Luban.Job.Cfg.DataVisitors
foreach (Record r in records)
{
if (r.Tags != null && r.Tags.Count > 0 && r.Tags.Contains(TAG_UNCHECKED))
if (DataUtil.IsUnchecked(r))
{
continue;
}

View File

@ -41,6 +41,11 @@ namespace Luban.Job.Cfg.Datas
return visitor.Accept(this, x);
}
public override string ToString()
{
return $"{StrValue}({Value})";
}
public override bool Equals(object obj)
{
switch (obj)

View File

@ -661,7 +661,7 @@ namespace Luban.Job.Cfg.Defs
private static readonly List<string> _fieldRequireAttrs = new List<string> { "name", "type" };
protected override Field CreateField(string defineFile, XElement e)
override protected Field CreateField(string defineFile, XElement e)
{
ValidAttrKeys(defineFile, e, _fieldOptionalAttrs, _fieldRequireAttrs);
@ -726,7 +726,7 @@ namespace Luban.Job.Cfg.Defs
private static readonly List<string> _beanOptinsAttrs = new List<string> { "value_type", "alias", "sep", "comment", "tags" };
private static readonly List<string> _beanRequireAttrs = new List<string> { "name" };
protected override void AddBean(string defineFile, XElement e, string parent)
override protected void AddBean(string defineFile, XElement e, string parent)
{
ValidAttrKeys(defineFile, e, _beanOptinsAttrs, _beanRequireAttrs);

View File

@ -40,7 +40,7 @@ namespace Luban.Job.Cfg.Defs
{
private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger();
public new static DefAssembly LocalAssebmly { get => (DefAssembly)DefAssemblyBase.LocalAssebmly; set => DefAssemblyBase.LocalAssebmly = value; }
public static new DefAssembly LocalAssebmly { get => (DefAssembly)DefAssemblyBase.LocalAssebmly; set => DefAssemblyBase.LocalAssebmly = value; }
public Service CfgTargetService { get; private set; }

View File

@ -103,7 +103,7 @@ namespace Luban.Job.Cfg.Defs
Sep = b.Sep;
}
protected override DefFieldBase CreateField(Common.RawDefs.Field f, int idOffset)
override protected DefFieldBase CreateField(Common.RawDefs.Field f, int idOffset)
{
return new DefField(this, (CfgField)f, idOffset);
}

View File

@ -1,5 +1,6 @@
using Luban.Common.Protos;
using Luban.Job.Cfg.Cache;
using Luban.Job.Cfg.DataVisitors;
using Luban.Job.Cfg.Utils;
using Luban.Job.Common.Utils;
using System.Threading.Tasks;
@ -21,7 +22,7 @@ namespace Luban.Job.Cfg.Generate
foreach (var record in records)
{
var fileName = table.IsMapTable ?
record.Data.GetField(table.IndexField.Name).ToString().Replace("\"", "").Replace("'", "")
record.Data.GetField(table.IndexField.Name).Apply(ToStringVisitor2.Ins).Replace("\"", "").Replace("'", "")
: (++index).ToString();
var file = RenderFileUtil.GetOutputFileName(genType, $"{dirName}/{fileName}", ctx.GenArgs.DataFileExtension);
ctx.Tasks.Add(Task.Run(() =>

View File

@ -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.TypeVisitors;
using Luban.Job.Common.Types;
@ -137,6 +138,14 @@ namespace Luban.Job.Cfg.Utils
return tags.Count > 0 ? tags : null;
}
private const string TAG_UNCHECKED = "unchecked";
public static bool IsUnchecked(Record rec)
{
return rec.Tags != null && rec.Tags.Count > 0 && rec.Tags.Contains(TAG_UNCHECKED);
}
public const string SimpleContainerSep = ",;|";
public static string GetBeanSep(TBean type)

View File

@ -151,10 +151,9 @@ namespace Luban.Job.Cfg.Validators
}
}
[Validator("path")]
public class PathValidator : IValidator
{
public const string NAME = "path";
public string RawPattern { get; }
public TType Type { get; }

View File

@ -6,12 +6,9 @@ using System;
namespace Luban.Job.Cfg.Validators
{
[Validator("range")]
class RangeValidator : IValidator
{
public const string NAME = "range";
public string Name => NAME;
public TType Type { get; }
private readonly string _str;

View File

@ -9,6 +9,7 @@ using System.Linq;
namespace Luban.Job.Cfg.Validators
{
[Validator("ref")]
public class RefValidator : IValidator
{
@ -21,18 +22,16 @@ namespace Luban.Job.Cfg.Validators
#endif
}
public const string NAME = "ref";
public List<string> Tables { get; }
public string FirstTable => GetActualTableName(Tables[0]);
public TType Type { get; }
public RefValidator(TType type, List<string> tables)
public RefValidator(TType type, string tablesStr)
{
Type = type;
this.Tables = new List<string>(tables);
this.Tables = new List<string>(tablesStr.Split(','));
}
public void Validate(ValidatorContext ctx, TType type, DType key)

View File

@ -0,0 +1,50 @@
using Luban.Job.Cfg.DataCreators;
using Luban.Job.Cfg.Datas;
using Luban.Job.Common.Defs;
using Luban.Job.Common.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Luban.Job.Cfg.Validators
{
[Validator("set")]
class SetValidator : IValidator
{
private readonly TType _type;
private readonly HashSet<DType> _datas;
private readonly string _valueSetStr;
public SetValidator(TType ttype, string param)
{
_type = ttype;
_datas = new HashSet<DType>();
_valueSetStr = param;
}
public void Compile(DefFieldBase def)
{
foreach (var p in _valueSetStr.Split(',', ';'))
{
_datas.Add(_type.Apply(StringDataCreator.Ins, p));
}
}
public void Validate(ValidatorContext ctx, TType type, DType data)
{
if (type.IsNullable && data == null)
{
return;
}
if (!_datas.Contains(data))
{
ctx.Assembly.Agent.Error("记录 {0}:{1} (来自文件:{2}) 值不在set:{3}中", ValidatorContext.CurrentRecordPath, data,
ValidatorContext.CurrentVisitor.CurrentValidateRecord.Source, _valueSetStr);
}
}
}
}

View File

@ -9,15 +9,13 @@ using System.Threading.Tasks;
namespace Luban.Job.Cfg.Validators
{
[Validator("size")]
internal class SizeValidator : IValidator
{
public const string NAME = "size";
private readonly TType _field;
private readonly int _size;
public SizeValidator(TType field, string rule)
public SizeValidator(TType type, string rule)
{
this._field = field;
this._size = int.Parse(rule);
}
@ -26,7 +24,7 @@ namespace Luban.Job.Cfg.Validators
}
private string Source => ValidatorContext.CurrentVisitor.CurrentValidateRecord.Source;
private static string Source => ValidatorContext.CurrentVisitor.CurrentValidateRecord.Source;
public void Validate(ValidatorContext ctx, TType type, DType data)
{

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Luban.Job.Cfg.Validators
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
internal class ValidatorAttribute : Attribute
{
public string Name { get; }
public ValidatorAttribute(string name)
{
Name = name;
}
}
}

View File

@ -11,38 +11,31 @@ namespace Luban.Job.Cfg.Validators
{
private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger();
private readonly static List<string> s_validatorNames = new List<string>()
static ValidatorFactory()
{
RefValidator.NAME,
PathValidator.NAME,
RangeValidator.NAME,
SizeValidator.NAME
};
foreach (var type in Bright.Common.ReflectionUtil.GetCallingTypesByAttr(typeof(ValidatorAttribute)))
{
var va = (ValidatorAttribute)type.GetCustomAttributes(typeof(ValidatorAttribute), false)[0];
s_validators.Add(va.Name, type);
s_validatorNames.Add(va.Name);
}
}
private static readonly Dictionary<string, Type> s_validators = new Dictionary<string, Type>();
private static readonly List<string> s_validatorNames = new List<string>();
public static List<string> ValidatorNames => s_validatorNames;
public static IValidator Create(TType field, string type, string rule)
public static IValidator Create(TType ttype, string type, string rule)
{
s_logger.Debug("== create validator {type}:{rule}", type, rule);
switch (type)
if (s_validators.TryGetValue(type, out var validatorType))
{
return (IValidator)System.Activator.CreateInstance(validatorType, ttype, rule);
}
else
{
case RefValidator.NAME:
{
return new RefValidator(field, rule.Split(',').ToList());
}
case PathValidator.NAME:
{
return new PathValidator(field, rule);//.Split(',').ToList());
}
case RangeValidator.NAME:
{
return new RangeValidator(field, rule);
}
case SizeValidator.NAME:
{
return new SizeValidator(field, rule);
}
default:
throw new NotSupportedException("unknown validator type:" + type);
}
}

View File

@ -4,7 +4,7 @@ namespace Luban.Job.Common.TypeVisitors
{
public class CppSharedPtrUnderingDefineTypeName : CppRawUnderingDefineTypeName
{
public new static CppSharedPtrUnderingDefineTypeName Ins { get; } = new();
public static new CppSharedPtrUnderingDefineTypeName Ins { get; } = new();
public override string Accept(TBean type)
{

View File

@ -8,9 +8,9 @@ namespace Luban.Job.Common.Utils
{
public class DefUtil
{
private readonly static char[] s_attrSep = new char[] { '|', '#', '&' };
private static readonly char[] s_attrSep = new char[] { '|', '#', '&' };
private readonly static char[] s_attrKeyValueSep = new char[] { '=', ':' };
private static readonly char[] s_attrKeyValueSep = new char[] { '=', ':' };
public static Dictionary<string, string> ParseAttrs(string tags)
{

View File

@ -59,7 +59,7 @@ namespace Luban.Job.Common.Utils
return fullName + ".bin";
}
private readonly static Dictionary<string, ELanguage> s_name2Lans = new()
private static readonly Dictionary<string, ELanguage> s_name2Lans = new()
{
{ "cs", ELanguage.CS },
{ "java", ELanguage.JAVA },
@ -85,7 +85,7 @@ namespace Luban.Job.Common.Utils
throw new ArgumentException($"not support output data type:{genType}");
}
private readonly static Dictionary<string, string> s_name2Suxxifx = new()
private static readonly Dictionary<string, string> s_name2Suxxifx = new()
{
{ "json", "json" },
{ "lua", "lua" },

View File

@ -6,7 +6,7 @@ namespace Luban.Job.Db.TypeVisitors
{
class DbTypescriptDefineTypeNameVisitor : TypescriptDefineTypeNameVisitor
{
public new static DbTypescriptDefineTypeNameVisitor Ins { get; } = new();
public static new DbTypescriptDefineTypeNameVisitor Ins { get; } = new();
public override string Accept(TArray type)
{