【修复】修复cpp抽象bean不包含字段时,生成的bean代码包含两个空构造函数的bug
【特性】go支持多态普通表 【修复】修复java多态表 getAs 泛型函数的bug 【修复】修复python抽象bean不包含字段时, __init__ 为空,导致编译出错的bug.通过 新增 pass 行解决 【修复】修复java可空变量相关生成的bug 【修复】FileCleaner清理目录时,不再删除meta文件 【优化】优化python的Vector2类缩进过多的问题 【更新】更新 README.mdmain
parent
6e127e3b7a
commit
147ce91166
19
README.md
19
README.md
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
## 介绍
|
||||
|
||||
luban是一个相当完备成熟的游戏配置解决方案,同时也可以用作通用型对象生成与缓存工具。
|
||||
luban是一个比较完备的游戏配置解决方案,同时也可以用作通用型对象生成与缓存工具。
|
||||
|
||||
luban创新性提出 **定义 + 数据源** 的设计,实现了完备的类型系统,增强了excel格式,同时提供json、xml、lua等多种数据源支持,统一了数据定义、加载、检验、数据导出及代码生成的游戏配置Pipeline,彻底解决了中大型项目中难以在excel中配置复杂数据以及一个项目中excel、json等多种的配置方案并存的问题。
|
||||
|
||||
|
|
@ -30,12 +30,13 @@ Luban另一优点是生成过程极快。对于普通的导表工具,一个典
|
|||
- [Excel 配置数据简介](docs/data_excel.md)
|
||||
- [使用说明](docs/catalog.md)
|
||||
- [常见问题](docs/faq.md)
|
||||
- [示例项目](https://github.com/focus-creative-games/luban_examples)
|
||||
|
||||
## 特性
|
||||
- 支持增强的excel格式,可以在excel里比较简洁填写出任意复杂的数据。
|
||||
- 支持excel族、json、xml、lua 多种数据格式
|
||||
- 强大完备的类型系统。支持所有常见原生类型、容器类型list,set,map、枚举和结构、**多态结构**以及**可空类型**
|
||||
- 灵活的数据源定义。一个表可以来自多个文件,或者一个文件内定义多个表或者一个表对应一个目录下所有文件。以及以上的组合
|
||||
- 支持excel族、json、xml、lua 多种数据格式,基本统一了游戏内的配置数据
|
||||
- 灵活的数据源定义。一个表可以来自多个文件或者一个文件内定义多个表或者一个表对应一个目录下所有文件,以及以上的组合。
|
||||
- 强大完备的类型系统。支持所有常见原生类型、容器类型list,set,map、枚举和结构、**多态结构**以及**可空类型**。
|
||||
- 支持表与字段级别分组。可以选择性地导出客户端或者服务器所用的表及字段。
|
||||
- 多种导出数据格式支持。支持binary、json、lua 等导出数据格式。
|
||||
- 支持数据标签。 可以选择导出符合要求的数据,发布正式数据时策划不必手动注释掉那些测试或者非正式数据了。
|
||||
|
|
@ -71,9 +72,9 @@ Luban另一优点是生成过程极快。对于普通的导表工具,一个典
|
|||
- 其他所有支持lua的引擎和平台
|
||||
- 其他所有支持js的引擎和平台
|
||||
|
||||
## 结构定义与配置表填写
|
||||
## 使用预览
|
||||
|
||||
与常见的专注于excel的导表工具中定义和数据放在同一个excel文件的做法不同,luban的定义与数据分离,使用单独的xml定义 **表和结构**,数据文件只包含数据。
|
||||
与常见的专注于excel的导表工具不同,luban的定义与数据分离,使用单独的xml定义 **表和结构**,数据文件只包含数据。
|
||||
|
||||
### 常规的原生数据
|
||||
```
|
||||
|
|
@ -414,7 +415,7 @@ luban支持横表与纵表,默认为横表。对于单例表,纵表填写更
|
|||
</k15>
|
||||
</data>
|
||||
```
|
||||
### json 数据源
|
||||
### lua 数据源
|
||||
|
||||
定义
|
||||
|
||||
|
|
@ -496,7 +497,7 @@ luban支持横表与纵表,默认为横表。对于单例表,纵表填写更
|
|||
|
||||
```Lua
|
||||
-- 直接 require 表
|
||||
local data = require("<--output_data_dir 指向的lua相对路径>.TbFullTypes")
|
||||
local data = require("<lua数据路径>.TbFullTypes")
|
||||
-- 获取 key为1001的道具数据
|
||||
local cfg = data[1]
|
||||
print(cfg.X4)
|
||||
|
|
@ -506,7 +507,7 @@ luban支持横表与纵表,默认为横表。对于单例表,纵表填写更
|
|||
|
||||
```C#
|
||||
// 一行代码可以加载所有配置。 cfg.Tables 包含所有表的一个实例字段。
|
||||
var tables = new cfg.Tables(file => return new ByteBuf(File.ReadAllBytes("<--output_data_dir指向的数据路径>/" + file)));
|
||||
var tables = new cfg.Tables(file => return new ByteBuf(File.ReadAllBytes("<数据路径>/" + file)));
|
||||
// 访问一个单例表
|
||||
Console.WriteLine(tables.TbGlobal.Name);
|
||||
// 访问普通的 key-value 表
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Luban.Common.Utils;
|
||||
|
||||
namespace Luban.Client.Common.Utils
|
||||
{
|
||||
|
|
@ -67,7 +69,7 @@ namespace Luban.Client.Common.Utils
|
|||
{
|
||||
s_logger.Trace("remain file:{file}", file);
|
||||
}
|
||||
else
|
||||
else if(!_ignoreFileExtensions.Contains(FileUtil.GetFileExtension(file)))
|
||||
{
|
||||
s_logger.Info("[remove] file: {file}", file);
|
||||
File.Delete(file);
|
||||
|
|
@ -76,7 +78,7 @@ namespace Luban.Client.Common.Utils
|
|||
|
||||
// 清除空目录
|
||||
var subDirs = new List<string>(Directory.GetDirectories(dir, "*", SearchOption.AllDirectories));
|
||||
subDirs.Sort((a, b) => -a.CompareTo(b));
|
||||
subDirs.Sort((a, b) => -String.Compare(a, b, StringComparison.Ordinal));
|
||||
foreach (var subDir in subDirs)
|
||||
{
|
||||
string fullSubDirPath = Path.GetFullPath(subDir);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,18 @@ namespace Luban.Common.Utils
|
|||
return index >= 0 ? path[..index] : path;
|
||||
}
|
||||
|
||||
public static string GetFileNameWithoutExt(string file)
|
||||
{
|
||||
int index = file.LastIndexOf('.');
|
||||
return index >= 0 ? file.Substring(0, index) : file;
|
||||
}
|
||||
|
||||
public static string GetFileExtension(string file)
|
||||
{
|
||||
int index = file.LastIndexOf('.');
|
||||
return index >= 0 ? file.Substring(index + 1) : "";
|
||||
}
|
||||
|
||||
public static string GetPathRelateRootFile(string rootFile, string file)
|
||||
{
|
||||
return Combine(GetParent(rootFile), file);
|
||||
|
|
|
|||
|
|
@ -125,9 +125,14 @@ namespace Luban.Job.Cfg.DataVisitors
|
|||
line.Append(type.Value);
|
||||
}
|
||||
|
||||
private string EscapeString(string s)
|
||||
{
|
||||
return s.Replace("\\", "\\\\").Replace("'", "\\'");
|
||||
}
|
||||
|
||||
public void Accept(DString type, StringBuilder line)
|
||||
{
|
||||
line.Append('\'').Append(type.Value).Append('\'');
|
||||
line.Append('\'').Append(EscapeString(type.Value)).Append('\'');
|
||||
}
|
||||
|
||||
public void Accept(DBytes type, StringBuilder line)
|
||||
|
|
@ -137,7 +142,7 @@ namespace Luban.Job.Cfg.DataVisitors
|
|||
|
||||
public void Accept(DText type, StringBuilder line)
|
||||
{
|
||||
line.Append('\'').Append(type.Value).Append('\'');
|
||||
line.Append('\'').Append(EscapeString(type.Value)).Append('\'');
|
||||
}
|
||||
|
||||
public void Accept(DBean type, StringBuilder line)
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ namespace Luban.Job.Cfg.Defs
|
|||
var table = field.Assembly.GetCfgTable(field.Ref.FirstTable);
|
||||
if (field.IsNullable)
|
||||
{
|
||||
return $"this.{refVarName} = this.{name} != null ? (({table.FullNameWithTopModule})_tables.get(\"{tableName}\")).get({name}.Value) : null;";
|
||||
return $"this.{refVarName} = this.{name} != null ? (({table.FullNameWithTopModule})_tables.get(\"{tableName}\")).get({name}) : null;";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ class {{name}} : public {{if parent_def_type}} {{parent_def_type.cpp_full_name}}
|
|||
|
||||
}
|
||||
|
||||
{{~if !hierarchy_export_fields.empty?~}}
|
||||
{{name}}({{- for field in hierarchy_export_fields }}{{cpp_define_type field.ctype}} {{field.name}}{{if !for.last}},{{end}} {{end}})
|
||||
{{-if parent_def_type-}}
|
||||
: {{parent_def_type.cpp_full_name}}({{ for field in parent_def_type.hierarchy_export_fields }}{{field.name}}{{if !for.last}}, {{end}}{{end}})
|
||||
|
|
@ -61,7 +62,7 @@ class {{name}} : public {{if parent_def_type}} {{parent_def_type.cpp_full_name}}
|
|||
this->{{field.cpp_style_name}} = {{field.name}};
|
||||
{{~end~}}
|
||||
}
|
||||
|
||||
{{~end~}}
|
||||
virtual ~{{name}}() {}
|
||||
|
||||
bool deserialize(ByteBuf& _buf);
|
||||
|
|
|
|||
|
|
@ -136,6 +136,7 @@ func NewChild{{go_full_name}}(_buf *serialization.ByteBuf) (_v interface{}, err
|
|||
private static Template t_tableRender;
|
||||
public string Render(DefTable p)
|
||||
{
|
||||
// TODO 目前只有普通表支持多态. 单例表和双key表都不支持
|
||||
string package = "cfg";
|
||||
var template = t_tableRender ??= Template.Parse(@"
|
||||
{{-
|
||||
|
|
@ -233,7 +234,16 @@ func New{{go_full_name}}(_buf *serialization.ByteBuf) (*{{go_full_name}}, error)
|
|||
return nil, err2
|
||||
} else {
|
||||
_dataList = append(_dataList, _v)
|
||||
{{~if value_type.is_dynamic ~}}
|
||||
{{- for child in value_type.bean.hierarchy_not_abstract_children}}
|
||||
if __v, __is := _v.(*{{child.go_full_name}}) ; __is {
|
||||
dataMap[__v.{{index_field.cs_style_name}}] = _v
|
||||
continue
|
||||
}
|
||||
{{-end}}
|
||||
{{~else~}}
|
||||
dataMap[_v.{{index_field.cs_style_name}}] = _v
|
||||
{{~end~}}
|
||||
}
|
||||
}
|
||||
return &{{go_full_name}}{_dataList:_dataList, _dataMap:dataMap}, nil
|
||||
|
|
|
|||
|
|
@ -192,7 +192,8 @@ public final class {{name}}
|
|||
public java.util.ArrayList<{{java_box_define_type value_type}}> getDataList() { return _dataList; }
|
||||
|
||||
{{if value_type.is_dynamic}}
|
||||
public T getAs<T extends {{java_box_define_type value_type}}>({{java_define_type key_type1}} key1, {{java_define_type key_type2}} key2) { return (T)_dataMapMap.get(key1).get(key2); }
|
||||
@SuppressWarnings(""unchecked"")
|
||||
public <T extends {{java_box_define_type value_type}}> T getAs({{java_define_type key_type1}} key1, {{java_define_type key_type2}} key2) { return (T)_dataMapMap.get(key1).get(key2); }
|
||||
{{end}}
|
||||
public {{java_box_define_type value_type}} get({{java_define_type key_type1}} key1, {{java_define_type key_type2}} key2) { return _dataMapMap.get(key1).get(key2);}
|
||||
|
||||
|
|
@ -225,7 +226,8 @@ public final class {{name}}
|
|||
public java.util.ArrayList<{{java_box_define_type value_type}}> getDataList() { return _dataList; }
|
||||
|
||||
{{~if value_type.is_dynamic~}}
|
||||
public T getAs<T extends {{java_box_define_type value_type}}>({{java_box_define_type key_type}} key) { return (T)_dataMap.get(key); }
|
||||
@SuppressWarnings(""unchecked"")
|
||||
public <T extends {{java_box_define_type value_type}}> T getAs({{java_define_type key_type}} key) { return (T)_dataMap.get(key); }
|
||||
{{~end~}}
|
||||
public {{java_box_define_type value_type}} get({{java_define_type key_type}} key) { return _dataMap.get(key); }
|
||||
|
||||
|
|
|
|||
|
|
@ -102,6 +102,9 @@ class {{name}} {{if parent_def_type}}({{parent_def_type.py_full_name}}){{end}}:
|
|||
{{~end~}}
|
||||
{{py27_deserialize ('self.' + field.py_style_name) ('_json_[""' + field.name + '""]') field.ctype}}
|
||||
{{~end~}}
|
||||
{{~if export_fields.empty?}}
|
||||
pass
|
||||
{{~end~}}
|
||||
");
|
||||
var result = template.RenderCode(b);
|
||||
|
||||
|
|
|
|||
|
|
@ -97,11 +97,14 @@ class {{name}} {{if parent_def_type}}({{parent_def_type.py_full_name}}){{else if
|
|||
{{parent_def_type.py_full_name}}.__init__(self, _json_)
|
||||
{{~end~}}
|
||||
{{~ for field in export_fields ~}}
|
||||
{{~if !field.ctype.is_nullable~}}
|
||||
{{~if !field.ctype.is_nullable~}}
|
||||
if _json_['{{field.name}}'] == None: raise Exception()
|
||||
{{~end~}}
|
||||
{{~end~}}
|
||||
{{py3_deserialize ('self.' + field.py_style_name) ('_json_[""' + field.name + '""]') field.ctype}}
|
||||
{{~end~}}
|
||||
{{~if export_fields.empty?}}
|
||||
pass
|
||||
{{~end~}}
|
||||
");
|
||||
var result = template.RenderCode(b);
|
||||
|
||||
|
|
|
|||
|
|
@ -529,20 +529,20 @@ export class Vector2 {
|
|||
{
|
||||
@"
|
||||
class Vector2:
|
||||
def __init__(self, x, y):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.a = Vector4(1,2,3,4)
|
||||
def __str__(self):
|
||||
return '{%g,%g}' % (self.x, self.y)
|
||||
def __init__(self, x, y):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.a = Vector4(1,2,3,4)
|
||||
def __str__(self):
|
||||
return '{%g,%g}' % (self.x, self.y)
|
||||
|
||||
@staticmethod
|
||||
def fromJson(_json_):
|
||||
x = _json_['x']
|
||||
y = _json_['y']
|
||||
if (x == None or y == None):
|
||||
raise Exception()
|
||||
return Vector2(x, y)
|
||||
@staticmethod
|
||||
def fromJson(_json_):
|
||||
x = _json_['x']
|
||||
y = _json_['y']
|
||||
if (x == None or y == None):
|
||||
raise Exception()
|
||||
return Vector2(x, y)
|
||||
|
||||
|
||||
class Vector3:
|
||||
|
|
|
|||
Loading…
Reference in New Issue