![Build Status](https://camo.githubusercontent.com/da7ad7f7d7b56458d886b88cb981fd0dc3c32f94e1687388f1c899bfe04cb7e5/68747470733a2f2f7472617669732d63692e636f6d2f666f6375732d63726561746976652d67616d65732f6c7562616e2e7376673f6272616e63683d6d61696e)
![Docker Build](https://camo.githubusercontent.com/789dc27456187a924363ab0fef8b3958907204e7396974a9fcf1f24a4e667264/68747470733a2f2f696d672e736869656c64732e696f2f646f636b65722f636c6f75642f6275696c642f6875676562756734657665722f6c7562616e2e737667)
![icon](docs/images/icon.png)
luban是你的最佳游戏配置解决方案。
luban高效地处理游戏开发中常见的excel、json、xml之类的数据,检查数据错误,生成c#等各种语言的代码,导出成bytes或json等多种格式。
luban统一了游戏配置开发工作流,极大提升了策划和程序的工作效率。
- 强大的数据解析和转换能力 {excel(csv,xls,xlsx)、json、bson、xml、yaml、lua、unity ScriptableObject} => {binary、json、bson、xml、lua、yaml、erlang、 custom format}
- 增强的excel格式,可以简洁地配置出像简单列表、子结构、结构列表,以及任意复杂的深层次的嵌套结构。
- 完备的类型系统,支持OOP类型继承,搭配excel、json、lua、xml等格式数据灵活优雅表达行为树、技能、剧情、副本之类复杂GamePlay数据
- 支持生成c#、java、go、c++、lua、python、javascript、typescript、erlang、rust、gdscript 代码
- 支持生成 protobuf(schema + binary + json)、flatbuffers(schema + json)、msgpack(binary)
- 强大的数据校验能力。ref引用检查、path资源路径、range范围检查等等
- 完善的本地化支持。静态文本值本地化、动态文本值本地化、时间本地化、main-patch多地区版本
- 强大灵活的自定义能力,支持自定义代码模板和数据模板
- 通用型生成和缓存工具。也可以用于生成协议、数据库之类的代码,甚至可以用作对象缓存服务
- 良好支持主流引擎、全平台、主流热更新方案、主流前后端框架。支持Unity、Unreal、Cocos2x、Godot、微信小游戏等主流引擎。工具自身跨平台,能在Win,Linux,Mac平台良好工作。
完整特性请参见 feature
##var |
id |
x1 |
x5 |
x6 |
s1 |
s2 |
v3 |
t1 |
##type |
int |
bool |
long |
float |
string |
text#sep=| |
vector3 |
datetime |
## |
id |
desc1 |
desc2 |
desc3 |
desc4 |
desc7 |
desc1 |
time |
|
1 |
false |
1000 |
1.2 |
hello |
key1|world1 |
1,2,3 |
1999-10-10 11:12:13 |
|
2 |
true |
1000 |
2.4 |
world |
key2|world2 |
2,4,5 |
1999-10-12 11:12:13 |
##var |
id |
arr1 |
arr2 |
arr3 |
arr4 |
##type |
int
| (array#sep=;),int |
list,int |
(list#sep=|),string |
list,string |
## |
id
| desc1 |
desc2 |
desc3 |
desc4 |
| 1 |
1;2;3 |
1 | 2 | | |
xx|yy |
xxx | zzz | |
| 2 |
2;4 |
3 | 4 | 5 | |
aaaa|bbbb|cccc |
aaa | bbb | ccc |
| 3 |
2;4;6 |
3 | 4 | 5 | 6 |
aaaa|bbbb|cccc |
aaa | bbb | ccc |
Reward为包含 "int item_id; int count; string desc; " 这三个字段的子结构。
##var | id | reward | reward2 | reward3 |
##type | int | Reward | Reward | Reward#sep=, |
##var | | item_id | count | desc | | | | |
| 1 | 1001 | 10 | item 1 | 1002 | 11 | item 2 | 1002,1,item 3 |
| 2 | 2001 | 10 | item 2 | 2002 | 20 | item 4 | 2003,2,item 5 |
##var |
id |
rewards1 |
rewards2 |
##type |
int |
list,Reward |
list,Reward#sep=, |
## |
id |
reward list desc1 |
reward list desc2 |
| 1 |
1001 | 1 | desc1 | 1002 | 2 | desc2 |
1001,1,desc1 | 1002,2,desc2 | 1003,3,desc3 |
| 2 |
1001 | 1 | desc1 | | | |
1001,1,desc1 | 1002,2,desc2 | |
##var |
id |
name |
rewards |
##type |
int |
string |
list,Reward |
##var |
|
|
0 |
1 |
2 |
| 1 | task1 | 1001 | 10 | desc1 | 1002 | 12 | desc2 | 1003 | 13 | desc3 |
| 2 | task1 | 1003 | 30 | desc3 | 1004 | 40 | desc4 | | | |
| 3 | task1 | 1005 | 50 | desc5 | | | | | | |
##var |
id |
name |
rewards |
##type |
int |
string |
list,Reward |
##var |
|
|
0 |
1 |
2 |
##var |
|
| item_id | num | desc |
item_id | num | desc |
item_id | num | desc |
| 1 | task1 | 1001 | 10 | desc1 | 1002 | 12 | desc2 | 1003 | 13 | desc3 |
| 2 | task1 | 1003 | 30 | desc3 | 1004 | 40 | desc4 | | | |
| 3 | task1 | 1005 | 50 | desc5 | | | | | | |
##var |
id |
name |
*stages |
##type |
int |
string |
list,Stage |
##var |
|
| id |
name |
desc |
location |
item_id |
num |
## |
id |
desc1 |
desc1 |
desc2 |
desc3 |
desc4 |
desc5 |
desc6 |
| 1 |
task1 |
1 | stage1 | stage desc1 | 1,2,3 | 1001 | 1 |
| | | 2 | stage2 | stage desc2 | 1,2,3 | 1001 | 1 |
| | | 3 | stage3 | stage desc3 | 1,2,3 | 1002 | 1 |
| 2 |
task2 |
1 | stage1 | stage desc1 | 1,2,3 | 1001 | 1 |
| | | 2 | stage2 | stage desc2 | 1,2,3 | 1002 | 1 |
多行表的列表字段,每个列表元素还可以是多行。支持任意多级的多行嵌套。另外也允许有多个多行字段,每个字段的行数还可以不同。
##var |
id |
name |
*stages |
##type |
int |
string |
list,Stage |
##var |
|
| id |
name |
desc |
*tips |
*rules |
##var |
|
| |
|
|
location |
item_id |
num |
id |
name |
item_id |
num |
## |
id |
desc1 |
desc1 |
desc2 |
desc3 |
desc4 |
desc5 |
desc6 |
id |
desc |
item id |
count |
| 1 |
task1 |
1 | stage1 | stage desc1 | 1,2,3 | 1001 | 1 | 1 | hello | 5001 | 1 |
| | | | | | 2,2,2 | 1002 | 2 | | | | |
| | | 2 | stage2 | stage desc2 | 1,2,3 | 1001 | 1 | 1 | hello | 5001 | 1 |
| | | | | | | | | 2 | hello | 5001 | 1 |
| | | | | | | | | 3 | hello | 5001 | 1 |
| | | 3 | stage3 | stage desc3 | 1,2,3 | 1002 | 1 | 1 | hello | 5001 | 1 |
| | | | | | 2,2,2 | 1002 | 2 | 1 | hello | 5001 | 1 |
| | | | | | 2,2,2 | 1002 | 2 | | | | |
| 2 |
task2 |
1 | stage1 | stage desc1 | 1,2,3 | 1001 | 1 | | | | |
| | | | | | 2,2,2 | 1002 | 2 | | | | |
| | | | | | 2,2,2 | 1002 | 2 | | | | |
| | | 2 | stage2 | stage desc2 | 1,2,3 | 1002 | 1 | 1 | hello | 5001 | 1 |
| | | | | | 2,2,2 | 1002 | 2 | | | | |
##var | id | shape | shape2 |
##type | int | Shape | Shape |
##var | | $type | radius | width | height | | | | |
| 1 | Circle | 10 | | | Circle | 100 | | |
| 2 | Rectangle | | 10 | 20 | 矩形 | 10 | 20 | |
| 3 | 圆 | 10 | | | Triangle | 15 | 15 | 15 |
| 4 | Circle | 10 | | | Rectangle | 30 | 20 | |
多个key构成联合唯一主键。
##var |
key1 |
key2 |
key3 |
num |
##type |
int |
long |
string |
int |
|
1 |
1 |
aaa |
123 |
|
1 |
1 |
bbb |
124 |
|
1 |
2 |
aaa |
134 |
|
2 |
1 |
aaa |
124 |
|
5 |
6 |
xxx |
898 |
多个key独立索引。
##var |
key1 |
key2 |
key3 |
num |
##type |
int |
long |
string |
int |
|
1 |
2 |
aaa |
123 |
|
2 |
4 |
bbb |
124 |
|
3 |
6 |
ccc |
134 |
|
4 |
8 |
ddd |
124 |
|
5 |
10 |
eee |
898 |
有一些配置全局只有一份,比如 公会模块的开启等级,背包初始大小,背包上限。此时使用单例表来配置这些数据比较合适。
##var |
guild_open_level |
bag_init_capacity |
bag_max_capacity |
newbie_tasks |
##type |
int |
int |
int |
list,int |
## |
desc1 |
desc 2 |
desc 3 |
desc 4 |
|
10 |
100 |
500 |
10001,10002 |
##var#column |
##type |
## |
|
guild_open_level | int | desc1 | 10 |
bag_init_capacity | int | desc2 | 100 |
bag_max_capacity | int | desc3 | 500 |
newbie_tasks | list,int | desc4 | 10001,10002 |
以行为树为例,展示json格式下如何配置行为树配置。xml、lua、yaml等等格式请参见 详细文档。
{
"id": 10002,
"name": "random move",
"desc": "demo behaviour tree",
"executor": "SERVER",
"blackboard_id": "demo",
"root": {
"$type": "Sequence",
"id": 1,
"node_name": "test",
"desc": "root",
"services": [],
"decorators": [
{
"$type": "UeLoop",
"id": 3,
"node_name": "",
"flow_abort_mode": "SELF",
"num_loops": 0,
"infinite_loop": true,
"infinite_loop_timeout_time": -1
}
],
"children": [
{
"$type": "UeWait",
"id": 30,
"node_name": "",
"ignore_restart_self": false,
"wait_time": 1,
"random_deviation": 0.5,
"services": [],
"decorators": []
},
{
"$type": "MoveToRandomLocation",
"id": 75,
"node_name": "",
"ignore_restart_self": false,
"origin_position_key": "x5",
"radius": 30,
"services": [],
"decorators": []
}
]
}
}
这儿只简略展示c#、typescript、go、c++ 语言在开发中的用法,更多语言以及更详细的使用范例和代码见示例项目。
// 一行代码可以加载所有配置。 cfg.Tables 包含所有表的一个实例字段。
var tables = new cfg.Tables(file => return new ByteBuf(File.ReadAllBytes($"{gameConfDir}/{file}.bytes")));
// 访问一个单例表
Console.WriteLine(tables.TbGlobal.Name);
// 访问普通的 key-value 表
Console.WriteLine(tables.TbItem.Get(12).Name);
// 支持 operator []用法
Console.WriteLine(tables.TbMail[1001].Desc);
// 一行代码可以加载所有配置。 cfg.Tables 包含所有表的一个实例字段。
let tables = new cfg.Tables(f => JsHelpers.LoadFromFile(gameConfDir, f))
// 访问一个单例表
console.log(tables.TbGlobal.name)
// 访问普通的 key-value 表
console.log(tables.TbItem.get(12).Name)
// 一行代码可以加载所有配置。 cfg.Tables 包含所有表的一个实例字段。
if tables , err := cfg.NewTables(loader) ; err != nil {
println(err.Error())
return
}
// 访问一个单例表
println(tables.TbGlobal.Name)
// 访问普通的 key-value 表
println(tables.TbItem.Get(12).Name)
cfg::Tables tables;
if (!tables.load([](ByteBuf& buf, const std::string& s) { buf.clear(); return buf.loadFromFile("../GenerateDatas/bytes/" + s + ".bytes"); }))
{
std::cout << "== load fail == " << std::endl;
return;
}
std::cout << tables.TbGlobal->name << std::endl;
std::cout << tables.TbItem.get(12)->name << std::endl;
Luban is licensed under the MIT license.