parent
f024ec6974
commit
5e56d35e4a
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(() =>
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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" },
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue