update doc
parent
27c22cf7d5
commit
c77d29730f
102
README.md
102
README.md
|
|
@ -1,78 +1,88 @@
|
||||||
[//]: # (Author: bug)
|
[//]: # "Author: bug"
|
||||||
[//]: # (Date: 2020-10-20 20:24:07)
|
[//]: # "Date: 2020-10-20 20:24:07"
|
||||||
|
|
||||||
# Luban
|
# Luban
|
||||||
[]
|
|
||||||
|
[](https://opensource.org/licenses/MIT)
|
||||||
[](https://travis-ci.com/focus-creative-games/luban)
|
[](https://travis-ci.com/focus-creative-games/luban)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 介绍
|
## 介绍
|
||||||
|
|
||||||
- Luban 是一个强大的配置生成与缓存工具。
|
- Luban 是一个强大的配置生成与缓存工具。
|
||||||
- Luban 最初是为了解决传统excel导出工具功能过于薄弱,无法很好处理 MMORPG 游戏复杂配置需求的痛点问题。
|
- Luban 最初是为了解决传统 excel 导出工具功能过于薄弱,无法很好处理 MMORPG 游戏复杂配置需求的痛点问题。
|
||||||
- 生成目标可以是常规代码、配置数据、类似 protobuf 的消息代码,也可以是游戏资源如 assetbundle。
|
- 生成目标可以是常规代码、配置数据、类似 protobuf 的消息代码,也可以是游戏资源如 assetbundle。
|
||||||
- 在大型项目中,由于配置或资源数据庞大,生成对象可能会花费相当多的时间。
|
- 在大型项目中,由于配置或资源数据庞大,生成对象可能会花费相当多的时间。
|
||||||
- 比如一个典型的MMORPG项目,后期全量生成配置,即使用了多线程加速,所需时间也在10秒的级别。
|
- 比如一个典型的 MMORPG 项目,后期全量生成配置,即使用了多线程加速,所需时间也在 10 秒的级别。
|
||||||
- 因此除了使用缓存,还使用了 client/server 模式,来加速生成过程。
|
- 因此除了使用缓存,还使用了 client/server 模式,来加速生成过程。
|
||||||
- 自2015年以来,经历过 MMORPG、卡牌、SLG 等多个上线项目的考验,
|
- 自 2015 年以来,经历过 MMORPG、卡牌、SLG 等多个上线项目的考验,
|
||||||
- 实际项目过程中不断迭代和优化,最终由一个增强型的配置工具成为一个相对完备的游戏配置数据解决方案。
|
- 实际项目过程中不断迭代和优化,最终由一个增强型的配置工具成为一个相对完备的游戏配置数据解决方案。
|
||||||
|
|
||||||
|
|
||||||
## 文档
|
## 快速布署一个 lua 例子
|
||||||
* [主页](https://focus-creative-games.github.io/luban/index.html)
|
* [下载例子]并解压至临时目录
|
||||||
* 各语言的简介: [English](README.en-us.md), [简体中文](README.md)
|
* 双击 bat 生成
|
||||||
* [特性](docs/traits.md)
|
|
||||||
* [使用说明](docs/catalog.md)
|
|
||||||
|
|
||||||
|
|
||||||
## 使用示例
|
## 使用示例
|
||||||
* Lua 使用示例
|
|
||||||
``` Lua
|
|
||||||
local data = require("TbDataFromJson")
|
|
||||||
local cfg = data[32]
|
|
||||||
print(cfg.name)
|
|
||||||
```
|
|
||||||
|
|
||||||
* C# 使用示例
|
- Lua 使用示例
|
||||||
``` C#
|
```Lua
|
||||||
// 一行代码可以加载所有配置。 cfg.Tables 包含所有表的一个实例字段。
|
local data = require("TbDataFromJson")
|
||||||
var tables = new cfg.Tables(file => return new ByteBuf(File.ReadAllBytes("output_data/" + file)));
|
local cfg = data[32]
|
||||||
// 访问一个单例表
|
print(cfg.name)
|
||||||
Console.WriteLine(tables.TbSingleton.Name);
|
```
|
||||||
// 访问普通的 key-value 表
|
- C# 使用示例
|
||||||
Console.WriteLine(tables.TbDataFromJson.Get(12).X1);
|
```C#
|
||||||
// 访问 双键表
|
// 一行代码可以加载所有配置。 cfg.Tables 包含所有表的一个实例字段。
|
||||||
Console.WriteLine(tables.TbTwoKey.Get(1, 10).X8);
|
var tables = new cfg.Tables(file => return new ByteBuf(File.ReadAllBytes("output_data/" + file)));
|
||||||
```
|
// 访问一个单例表
|
||||||
* [更多语言的例子](docs/samples.md)
|
Console.WriteLine(tables.TbSingleton.Name);
|
||||||
|
// 访问普通的 key-value 表
|
||||||
|
Console.WriteLine(tables.TbDataFromJson.Get(12).X1);
|
||||||
|
// 访问 双键表
|
||||||
|
Console.WriteLine(tables.TbTwoKey.Get(1, 10).X8);
|
||||||
|
```
|
||||||
|
- [更多语言的例子](docs/samples.md)
|
||||||
|
|
||||||
|
|
||||||
|
## 文档
|
||||||
|
|
||||||
|
- [主页](https://focus-creative-games.github.io/luban/index.html)
|
||||||
|
- [特性](docs/traits.md)
|
||||||
|
- [使用说明](docs/catalog.md)
|
||||||
|
- [常见问题](docs/faq.md)
|
||||||
|
|
||||||
## RoadMap
|
## RoadMap
|
||||||
|
|
||||||
- [ ] 新增 unity 内置编辑器
|
- [ ] 新增 unity 内置编辑器
|
||||||
- [ ] 新增 unreal 内置编辑器
|
- [ ] 新增 unreal 内置编辑器
|
||||||
- [ ] 补充单元测试
|
- [ ] 补充单元测试
|
||||||
- [ ] 支持多国家和地区本地化所需的表merge操作
|
- [ ] 支持多国家和地区本地化所需的表 merge 操作
|
||||||
|
|
||||||
## 布署
|
|
||||||
TODO
|
|
||||||
|
|
||||||
## 开发环境架设
|
## 开发环境架设
|
||||||
* 安装 VS2019 社区版
|
|
||||||
* 安装 .dotnet core sdk 3.1
|
- 安装 [VS2019 社区版](https://visualstudio.microsoft.com/zh-hans/vs/)
|
||||||
|
- 安装 [.dotnet core sdk 3.1](https://dotnet.microsoft.com/download/dotnet-core/3.1)
|
||||||
|
|
||||||
## 如何贡献?
|
## 如何贡献?
|
||||||
* [Contributing](CONTRIBUTING.md) explains what kinds of changes we welcome
|
|
||||||
|
- [Contributing](CONTRIBUTING.md) explains what kinds of changes we welcome
|
||||||
- [Workflow Instructions](docs/workflow/README.md) explains how to build and test
|
- [Workflow Instructions](docs/workflow/README.md) explains how to build and test
|
||||||
|
|
||||||
## Useful Links
|
## Useful Links
|
||||||
|
|
||||||
* [.NET Core source index](https://source.dot.net)
|
- [.NET Core source index](https://source.dot.net)
|
||||||
* 社区的其它实现
|
- 社区的其它实现
|
||||||
* [tabtoy](https://github.com/davyxu/tabtoy)
|
- [tabtoy](https://github.com/davyxu/tabtoy)
|
||||||
|
|
||||||
## 支持和联系
|
## 支持和联系
|
||||||
QQ 群: 692890842
|
|
||||||
邮箱: taojingjian#gmail.com
|
```
|
||||||
|
QQ 群: 692890842
|
||||||
|
邮箱: taojingjian#gmail.com
|
||||||
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@
|
||||||
- 之前用 bean 来定义结构,我们引入的新的 tag “enum” 来定义 枚举。
|
- 之前用 bean 来定义结构,我们引入的新的 tag “enum” 来定义 枚举。
|
||||||
- enum 的 name 属性表示 枚举名。
|
- enum 的 name 属性表示 枚举名。
|
||||||
- 如果生成 c#代码的话,会生成 cfg.item.Equality 类。
|
- 如果生成 c#代码的话,会生成 cfg.item.Equality 类。
|
||||||
- ``` <var name=”xxx” alias=”xx” value=”xx”/> ``` 为检举项。
|
- `<var name=”xxx” alias=”xx” value=”xx”/>` 为检举项。
|
||||||
- 其中 name 为必填项,不可为空,也不能重复。
|
- 其中 name 为必填项,不可为空,也不能重复。
|
||||||
- alias 是可选项,枚举项别名。
|
- alias 是可选项,枚举项别名。
|
||||||
- value 是枚举值,主要给程序使用。
|
- value 是枚举值,主要给程序使用。
|
||||||
|
|
@ -107,7 +107,16 @@
|
||||||
- 有时候希望一个字段是复合类型。
|
- 有时候希望一个字段是复合类型。
|
||||||
- 比如,我们想用一个字段 level_range 来表示道具可以使用的等级范围,它包含两个字段,最小等级和最大等级。
|
- 比如,我们想用一个字段 level_range 来表示道具可以使用的等级范围,它包含两个字段,最小等级和最大等级。
|
||||||
- 此时,可以通过定义 bean 来解决。
|
- 此时,可以通过定义 bean 来解决。
|
||||||

|
[定义](images/adv/def_12.png)
|
||||||
|
```
|
||||||
|
<bean name="IntRange">
|
||||||
|
<var name="min" type="int">
|
||||||
|
<var name="max" type="int">
|
||||||
|
</bean>
|
||||||
|
<bean name="Item">
|
||||||
|
<var name="level_range" type="IntRange">
|
||||||
|
</bean>
|
||||||
|
```
|
||||||
- 之前的字段都在一个单元格内填写,现在这个字段是 bean 类型,有两个值,该怎么填写呢?
|
- 之前的字段都在一个单元格内填写,现在这个字段是 bean 类型,有两个值,该怎么填写呢?
|
||||||
如果也像 list,int 那样把两个数写在一个单元格里(如下图),会发现工具报错了: “10,20” 不是合法的整数值。
|
如果也像 list,int 那样把两个数写在一个单元格里(如下图),会发现工具报错了: “10,20” 不是合法的整数值。
|
||||||

|

|
||||||
|
|
@ -117,7 +126,16 @@
|
||||||

|

|
||||||
2. 使用 sep 分割单元格
|
2. 使用 sep 分割单元格
|
||||||
字段定义中指定 sep 属性,用某些字符分割单元格,这样就能识别为两个整数了。
|
字段定义中指定 sep 属性,用某些字符分割单元格,这样就能识别为两个整数了。
|
||||||

|
[定义](images/adv/def_15.png)
|
||||||
|
```
|
||||||
|
<bean name="IntRange">
|
||||||
|
<var name="min" type="int">
|
||||||
|
<var name="max" type="int">
|
||||||
|
</bean>
|
||||||
|
<bean name="Item">
|
||||||
|
<var name="level_range" type="IntRange" sep="|">
|
||||||
|
</bean>
|
||||||
|
```
|
||||||
如果想用 分号; 或者 竖号 | 分割,只要 sep=”;” 或者 sep=”|“ 即可。
|
如果想用 分号; 或者 竖号 | 分割,只要 sep=”;” 或者 sep=”|“ 即可。
|
||||||

|

|
||||||
|
|
||||||
|
|
@ -125,23 +143,66 @@
|
||||||
|
|
||||||
- 有些时候,我们需要一个 结构列表字段。
|
- 有些时候,我们需要一个 结构列表字段。
|
||||||
比如说 道具不同等级会增加不同的血量。我们定义一个 ItemLevelAttr 结构。
|
比如说 道具不同等级会增加不同的血量。我们定义一个 ItemLevelAttr 结构。
|
||||||

|
[定义](images/adv/def_17.png)
|
||||||
- 对应的 excel 配置如下。
|
|
||||||
|
```
|
||||||
|
<module name="item">
|
||||||
|
<bean name="ItemLevelAttr">
|
||||||
|
<var name="level", type="int">
|
||||||
|
<var name="desc", type="string">
|
||||||
|
<var name="attr", type="float">
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean name="Item">
|
||||||
|
<var name="level_attrs" type="list,ItemLevelAttr" />
|
||||||
|
</bean>
|
||||||
|
</module>
|
||||||
|
```
|
||||||
|
|
||||||
|
配置:
|
||||||

|

|
||||||
|
|
||||||
- 对于多个值构成的字段,填写方式为 在标题头(level_attrs)对应的列范围内,按顺序填值。不需要跟策划的标题头名有对应关系。空白单元格会被忽略。也就是如下填法也是可以的:
|
- 对于多个值构成的字段,填写方式为 在标题头(level_attrs)对应的列范围内,按顺序填值。不需要跟策划的标题头名有对应关系。空白单元格会被忽略。也就是如下填法也是可以的:
|
||||||

|

|
||||||
- 这种填法的缺点是占据在太多的列。如果想如下填,该怎么办呢?
|
- 这种填法的缺点是占据在太多的列。如果想如下填,该怎么办呢?
|
||||||

|

|
||||||
- 有两种办法。
|
- 有两种办法。
|
||||||
1. bean ItemLevelAttr 增加属性 sep=”,”
|
1. bean ItemLevelAttr 增加属性 sep=”,”
|
||||||

|
[定义](images/adv/def_21.png)
|
||||||
|
```
|
||||||
|
<bean name="ItemLevelAttr" sep=",>
|
||||||
|
<var name="level" type="int"/>
|
||||||
|
<var name="desc" type="string"/>
|
||||||
|
<var name="attr" type="float"/>
|
||||||
|
</bean>
|
||||||
|
```
|
||||||
如果不想用逗号”,” ,想用;来分割单元格内的数据,只要将 sep=”;” 即可。
|
如果不想用逗号”,” ,想用;来分割单元格内的数据,只要将 sep=”;” 即可。
|
||||||
2. 字段 level_attrs 增加属性 sep=”,”,即
|
2. 字段 level_attrs 增加属性 sep=”,”,即
|
||||||

|
[定义](images/adv/def_22.png)
|
||||||
|
```
|
||||||
|
<bean name="ItemLevelAttr" sep=",>
|
||||||
|
<var name="level" type="int"/>
|
||||||
|
<var name="desc" type="string"/>
|
||||||
|
<var name="attr" type="float"/>
|
||||||
|
</bean>
|
||||||
|
<bean name="Item">
|
||||||
|
<var name="level_attrs" type="list,ItemLevelAttr" sep=",">
|
||||||
|
</bean>
|
||||||
|
```
|
||||||
如果想所有数据都在一个单元格内填写,又该怎么办呢?
|
如果想所有数据都在一个单元格内填写,又该怎么办呢?
|
||||||

|

|
||||||
想用 | 来分割不同 ItemLevelAttr ,用 , 来分割每个记录的数据。只需要 字段 level_attrs 的 sep=”,|” 即可。
|
想用 | 来分割不同 ItemLevelAttr ,用 , 来分割每个记录的数据。只需要 字段 level_attrs 的 sep=”,|” 即可。
|
||||||

|
[定义](images/adv/def_24.png)
|
||||||
|
```
|
||||||
|
<bean name="ItemLevelAttr" sep=",>
|
||||||
|
<var name="level" type="int"/>
|
||||||
|
<var name="desc" type="string"/>
|
||||||
|
<var name="attr" type="float"/>
|
||||||
|
</bean>
|
||||||
|
<bean name="Item">
|
||||||
|
<var name="level_attrs" type="list,ItemLevelAttr" sep=",|">
|
||||||
|
</bean>
|
||||||
|
```
|
||||||
|
|
||||||
## 多态 bean
|
## 多态 bean
|
||||||
|
|
||||||
|
|
@ -151,12 +212,40 @@
|
||||||
- 假设 item 有一个形状 Shape 类型的字段。Shape 有两种 Circle 和 Rectangle.
|
- 假设 item 有一个形状 Shape 类型的字段。Shape 有两种 Circle 和 Rectangle.
|
||||||
Cicle 有 2 个字段 int id; float radius;
|
Cicle 有 2 个字段 int id; float radius;
|
||||||
Rectangle 有 3 个字段 int id; float width; float height;
|
Rectangle 有 3 个字段 int id; float width; float height;
|
||||||

|
[定义](images/adv/def_25.png)
|
||||||
|
```
|
||||||
|
<bean name="Shape">
|
||||||
|
<var name="id" type="int">
|
||||||
|
<bean name="Circle">
|
||||||
|
<var name="radius" type="float">
|
||||||
|
</bean>
|
||||||
|
<bean name="Rectangle">
|
||||||
|
<var name="width" type="float"/>
|
||||||
|
<var name="height" type="float"/>
|
||||||
|
</bean>
|
||||||
|
</bean>
|
||||||
|
<bean name="Item">
|
||||||
|
<var name="shape" type="Shape"/>
|
||||||
|
</bean>
|
||||||
|
```
|
||||||
|
配置:
|
||||||

|

|
||||||
- 注意到,多态 bean 与普通 bean 填写区别在于,多态 bean 需要一个类型名。这也好理解,如果没有类型名,如何知道使用哪个 bean 呢。
|
- 注意到,多态 bean 与普通 bean 填写区别在于,多态 bean 需要一个类型名。这也好理解,如果没有类型名,如何知道使用哪个 bean 呢。
|
||||||
- 有时间策划不太习惯填写英文,或者说类型名有时候会调整,不希望调整类型名后配置也跟着改变,因为,多态 bean 支持别名的概念。
|
- 有时间策划不太习惯填写英文,或者说类型名有时候会调整,不希望调整类型名后配置也跟着改变,因为,多态 bean 支持别名的概念。
|
||||||

|
[定义](images/adv/def_27.png)
|
||||||
- 这时,可以这样填数据:
|
```
|
||||||
|
<bean name="Shape">
|
||||||
|
<var name="id" type="int"/>
|
||||||
|
<bean name="Circle" alias="圆">
|
||||||
|
<var name="radius" type="float"/>
|
||||||
|
</bean>
|
||||||
|
<bean name="Rectangle" alias="长方形">
|
||||||
|
<var name="width" type="float"/>
|
||||||
|
<var name="height" type="float"/>
|
||||||
|
</bean>
|
||||||
|
</bean>
|
||||||
|
```
|
||||||
|
- 配置
|
||||||

|

|
||||||
- 使用类型名和别名来标识多态都是支持的,可以混合使用。
|
- 使用类型名和别名来标识多态都是支持的,可以混合使用。
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
[//]: # (Author: bug)
|
||||||
|
[//]: # (Date: 2020-11-15 23:59:21)
|
||||||
|
|
||||||
|
|
||||||
|
## 为什么要使用"客户端/服务器"模式
|
||||||
|
* 配置文件需要反复生成与测试
|
||||||
|
* 文件数量上升后,配置生成不可避免地变慢
|
||||||
|
* 再快的技术,也挡不住大量数据的处理
|
||||||
|
* 效率就是生命
|
||||||
Loading…
Reference in New Issue