【特性】提供自定义lua和json数据生成所必要的序列化支持

main
walon 2021-08-27 18:45:55 +08:00
parent 7ea907cc5b
commit 2fde2a481e
15 changed files with 404 additions and 10 deletions

View File

@ -58,6 +58,7 @@ Luban适合有以下需求的开发者
- 灵活的数据源定义。一个表可以来自多个文件或者一个文件内定义多个表或者一个目录下所有文件甚至来自云表格,以及以上的组合
- 支持表与字段级别分组。可以选择性地导出客户端或者服务器所用的表及字段
- 多种导出数据格式支持。支持binary、json、lua 等导出数据格式
- 支持自定义数据模板。可以用模板文件定制导出格式。
- 支持数据标签。 可以选择导出符合要求的数据,发布正式数据时策划不必手动注释掉那些测试数据了
- 强大的数据校验能力。支持内建数据格式检查支持ref表引用检查策划不用担心填错id;支持path资源检查策划不用担心填错资源路径;支持range检查
- 支持常量别名。策划不必再为诸如 升级丹 这样的道具手写具体道具id了
@ -945,6 +946,66 @@ k15:
```
### 自定义导出数据格式
支持使用scriban模板文件定制导出数据格式。
lua数据模板 定义
```
// {{table.name}}
{{for d in datas}}
// {{d.impl_type.full_name}}
{{~i = 0~}}
{{~for f in d.fields~}}
{{~if f ~}}
// {{d.impl_type.hierarchy_export_fields[i].name}} = {{f.value}}
{{~end~}}
{{i = i + 1}}
{{~end~}}
{{end}}
```
输出数据
```
// TbItem
// item.Item
// id = 1
// name = 钻石
// major_type = 1
// minor_type = 101
// max_pile_num = 9999999
// quality = 0
// icon = /Game/UI/UIText/UI_TestIcon_3.UI_TestIcon_3
// item.Item
// id = 2
// name = 金币
// major_type = 1
// minor_type = 102
// max_pile_num = 9999999
// quality = 0
// icon = /Game/UI/UIText/UI_TestIcon_1.UI_TestIcon_1
```
-----
## 路线图

View File

@ -1,6 +1,7 @@
using Luban.Job.Cfg.Datas;
using Luban.Job.Cfg.DataVisitors;
using Luban.Job.Cfg.Defs;
using Luban.Job.Cfg.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
@ -100,14 +101,9 @@ namespace Luban.Job.Cfg.DataExporters
line.Append(type.Value);
}
private string EscapeString(string s)
{
return s.Replace("\\", "\\\\").Replace("'", "\\'");
}
public void Accept(DString type, DefAssembly ass, StringBuilder line)
{
line.Append('\'').Append(EscapeString(type.Value)).Append('\'');
line.Append('\'').Append(DataUtil.EscapeString(type.Value)).Append('\'');
}
public void Accept(DBytes type, DefAssembly ass, StringBuilder line)
@ -117,7 +113,7 @@ namespace Luban.Job.Cfg.DataExporters
public void Accept(DText type, DefAssembly ass, StringBuilder line)
{
line.Append($"{{{DText.KEY_NAME}='{type.Key}',{DText.TEXT_NAME}='{EscapeString(type.GetText(ass.ExportTextTable, ass.NotConvertTextSet))}'}}");
line.Append($"{{{DText.KEY_NAME}='{type.Key}',{DText.TEXT_NAME}='{DataUtil.EscapeString(type.GetText(ass.ExportTextTable, ass.NotConvertTextSet))}'}}");
}
public void Accept(DBean type, DefAssembly ass, StringBuilder line)

View File

@ -0,0 +1,201 @@
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 ToJsonStringVisitor : IDataFuncVisitor<string>
{
public static ToJsonStringVisitor Ins { get; } = new();
public string Accept(DBool type)
{
return type.Value ? "true" : "false";
}
public string Accept(DByte type)
{
return type.Value.ToString();
}
public string Accept(DShort type)
{
return type.Value.ToString();
}
public string Accept(DFshort type)
{
return type.Value.ToString();
}
public string Accept(DInt type)
{
return type.Value.ToString();
}
public string Accept(DFint type)
{
return type.Value.ToString();
}
public string Accept(DLong type)
{
return type.Value.ToString();
}
public string Accept(DFlong type)
{
return type.Value.ToString();
}
public string Accept(DFloat type)
{
return type.Value.ToString();
}
public string Accept(DDouble type)
{
return type.Value.ToString();
}
public string Accept(DEnum type)
{
return type.Value.ToString();
}
public string Accept(DString type)
{
return "\"" + DataUtil.EscapeString(type.Value) + "\"";
}
public string Accept(DBytes type)
{
throw new System.NotSupportedException();
}
public virtual string Accept(DText type)
{
var ass = DefAssembly.LocalAssebmly as DefAssembly;
return $"{{\"{DText.KEY_NAME}\":\"{type.Key}\",\"{DText.TEXT_NAME}\":\"{DataUtil.EscapeString(type.GetText(ass.ExportTextTable, ass.NotConvertTextSet))}\"}}";
}
public virtual string Accept(DBean type)
{
var x = new StringBuilder();
var bean = type.ImplType;
if (bean.IsAbstractType)
{
x.Append($"{{ \"_name\":\"{type.ImplType.Name}\",");
}
else
{
x.Append('{');
}
int index = 0;
foreach (var f in type.Fields)
{
if (index >= 1)
{
x.Append(',');
}
var defField = type.ImplType.HierarchyFields[index++];
x.Append('\"').Append(defField.Name).Append('\"').Append(':');
if (f != null)
{
x.Append(f.Apply(this));
}
else
{
x.Append("null");
}
}
x.Append('}');
return x.ToString();
}
protected virtual void Append(List<DType> datas, StringBuilder x)
{
x.Append('[');
int index = 0;
foreach (var e in datas)
{
if (index > 0)
{
x.Append(',');
}
++index;
x.Append(e.Apply(this));
}
x.Append(']');
}
public string Accept(DArray type)
{
var x = new StringBuilder();
Append(type.Datas, x);
return x.ToString();
}
public string Accept(DList type)
{
var x = new StringBuilder();
Append(type.Datas, x);
return x.ToString();
}
public string Accept(DSet type)
{
var x = new StringBuilder();
Append(type.Datas, x);
return x.ToString();
}
public virtual string Accept(DMap type)
{
var x = new StringBuilder();
x.Append('{');
int index = 0;
foreach (var e in type.Datas)
{
if (index > 0)
{
x.Append(',');
}
++index;
x.Append('"').Append(e.Key.ToString()).Append('"');
x.Append(':');
x.Append(e.Value.Apply(this));
}
x.Append('}');
return x.ToString();
}
public virtual string Accept(DVector2 type)
{
var v = type.Value;
return $"{{\"x\":{v.X},\"y\":{v.Y}}}";
}
public virtual string Accept(DVector3 type)
{
var v = type.Value;
return $"{{\"x\":{v.X},\"y\":{v.Y},\"z\":{v.Z}}}";
}
public virtual string Accept(DVector4 type)
{
var v = type.Value;
return $"{{\"x\":{v.X},\"y\":{v.Y},\"z\":{v.Z},\"w\":{v.W}}}";
}
public string Accept(DDateTime type)
{
var ass = DefAssembly.LocalAssebmly as DefAssembly;
return type.GetUnixTime(ass.TimeZone).ToString();
}
}
}

View File

@ -0,0 +1,98 @@
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 ToLuaStringVisitor : ToJsonStringVisitor
{
public static new ToLuaStringVisitor Ins { get; } = new();
public override string Accept(DText type)
{
var ass = DefAssembly.LocalAssebmly as DefAssembly;
return $"{{{DText.KEY_NAME}='{type.Key}',{DText.TEXT_NAME}='{DataUtil.EscapeString(type.GetText(ass.ExportTextTable, ass.NotConvertTextSet))}'}}";
}
public override string Accept(DBean type)
{
var x = new StringBuilder();
var bean = type.ImplType;
if (bean.IsAbstractType)
{
x.Append($"{{ _name='{type.ImplType.Name}',");
}
else
{
x.Append('{');
}
int index = 0;
foreach (var f in type.Fields)
{
var defField = type.ImplType.HierarchyFields[index++];
x.Append(defField.Name).Append('=');
if (f != null)
{
x.Append(f.Apply(this));
}
else
{
x.Append("nil");
}
x.Append(',');
}
x.Append('}');
return x.ToString();
}
protected override void Append(List<DType> datas, StringBuilder x)
{
x.Append('{');
foreach (var e in datas)
{
x.Append(e.Apply(this));
x.Append(',');
}
x.Append('}');
}
public override string Accept(DMap type)
{
var x = new StringBuilder();
x.Append('{');
foreach (var e in type.Datas)
{
x.Append('[');
x.Append(e.Key.Apply(this));
x.Append(']');
x.Append('=');
x.Append(e.Value.Apply(this));
x.Append(',');
}
x.Append('}');
return x.ToString();
}
public override string Accept(DVector2 type)
{
var v = type.Value;
return $"{{x={v.X},y={v.Y}}}";
}
public override string Accept(DVector3 type)
{
var v = type.Value;
return $"{{x={v.X},y={v.Y},z={v.Z}}}";
}
public override string Accept(DVector4 type)
{
var v = type.Value;
return $"{{x={v.X},y={v.Y},z={v.Z},w={v.W}}}";
}
}
}

View File

@ -10,7 +10,7 @@ namespace Luban.Job.Cfg.DataVisitors
public void Accept(DBool type, StringBuilder x)
{
x.Append(type.Value);
x.Append(type.Value ? "true" : "false");
}
public void Accept(DByte type, StringBuilder x)

View File

@ -9,6 +9,8 @@ namespace Luban.Job.Cfg.Datas
public TArray Type { get; }
public List<DType> Datas { get; }
public bool IsArray => true;
public DArray(TArray type, List<DType> datas)
{
this.Type = type;

View File

@ -12,6 +12,8 @@ namespace Luban.Job.Cfg.Datas
public List<DType> Fields { get; }
public bool IsBean => true;
public DBean(DefBean defType, DefBean implType, List<DType> fields)
{
this.Type = defType;

View File

@ -9,6 +9,8 @@ namespace Luban.Job.Cfg.Datas
public TList Type { get; }
public List<DType> Datas { get; }
public bool IsList => true;
public DList(TList type, List<DType> datas)
{
this.Type = type;

View File

@ -10,6 +10,8 @@ namespace Luban.Job.Cfg.Datas
public TMap Type { get; }
public Dictionary<DType, DType> Datas { get; }
public bool IsMap => true;
public DMap(TMap type, Dictionary<DType, DType> datas)
{
this.Type = type;

View File

@ -10,6 +10,8 @@ namespace Luban.Job.Cfg.Datas
public TSet Type { get; }
public List<DType> Datas { get; }
public bool IsSet => true;
public DSet(TSet type, List<DType> datas)
{
this.Type = type;

View File

@ -20,6 +20,10 @@ namespace Luban.Job.Cfg.Datas
this.Apply(ToStringVisitor.Ins, s);
return s.ToString();
}
public string JsonValue => this.Apply(ToJsonStringVisitor.Ins);
public string LuaValue => this.Apply(ToLuaStringVisitor.Ins);
}
public abstract class DType<T> : DType

View File

@ -1,3 +1,4 @@
using Luban.Job.Cfg.Datas;
using Luban.Job.Cfg.TypeVisitors;
using Luban.Job.Common.Defs;
using Luban.Job.Common.Types;
@ -8,6 +9,20 @@ namespace Luban.Job.Cfg.Defs
{
class TTypeTemplateExtends : TTypeTemplateCommonExtends
{
public static DType GetField(DBean bean, string fieldName)
{
int index = 0;
foreach (var f in bean.ImplType.HierarchyExportFields)
{
if (f.Name == fieldName)
{
return bean.Fields[index];
}
++index;
}
return null;
}
public static string CsDefineTextKeyField(DefField field)
{
return $"string {field.GetTextKeyName(field.CsStyleName)}";

View File

@ -78,6 +78,16 @@ namespace Luban.Job.Cfg.Utils
}
}
public static string EscapeString(string s)
{
return s.Replace("\\", "\\\\").Replace("'", "\\'");
}
public static string EscapeStringWithQuote(string s)
{
return "'" + s.Replace("\\", "\\\\").Replace("'", "\\'") + "'";
}
public static (string Key, string Text) ExtractText(string rawKeyAndText)
{
string[] keyAndText = rawKeyAndText.Split('|');

View File

@ -12,7 +12,7 @@
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.8.0" />
<PackageReference Include="Scriban" Version="2.1.4" />
<PackageReference Include="Scriban" Version="4.0.1" />
</ItemGroup>
<ItemGroup>

View File

@ -24,7 +24,6 @@
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.8.0" />
<PackageReference Include="ExcelDataReader" Version="3.6.0" />
<PackageReference Include="Scriban" Version="2.1.4" />
</ItemGroup>
<ItemGroup>