From 6e127e3b7a4e3fcd363c281ffc87e40fcdbf2438 Mon Sep 17 00:00:00 2001 From: walon Date: Mon, 14 Dec 2020 17:46:55 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E5=AE=8C=E5=96=84=E3=80=91=E5=AE=8C?= =?UTF-8?q?=E5=96=84=20README.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 360 +++++++++++++++++---------------- docs/images/examples/ex_a1.png | Bin 6364 -> 5982 bytes 2 files changed, 185 insertions(+), 175 deletions(-) diff --git a/README.md b/README.md index 59b8a81..56bc5ef 100644 --- a/README.md +++ b/README.md @@ -12,16 +12,16 @@ ## 介绍 -Luban是一个强大的对象生成与缓存工具。生成目标可以是类似protobuf的消息代码、游戏配置代码、游戏配置数据、数据库代码,也可以是游戏资源如assetbundle。 +luban是一个相当完备成熟的游戏配置解决方案,同时也可以用作通用型对象生成与缓存工具。 -luban创新性提出 **定义 + 数据源** 的设计,实现了完备的类型系统,增强了excel格式,同时提供json、xml、lua等多种数据源支持,统一了数据定义、加载、检验、数据导出及代码生成的Pipeline,彻底解决了中大型项目中难以在excel中配置复杂数据以及一个项目中excel、json等多种的配置方案并存的问题。 +luban创新性提出 **定义 + 数据源** 的设计,实现了完备的类型系统,增强了excel格式,同时提供json、xml、lua等多种数据源支持,统一了数据定义、加载、检验、数据导出及代码生成的游戏配置Pipeline,彻底解决了中大型项目中难以在excel中配置复杂数据以及一个项目中excel、json等多种的配置方案并存的问题。 Luban适合有以下需求的开发者: 1. 无法容忍传统excel导表工具的简陋功能,希望找一个快速强大经受过上线项目检验的满足中大型游戏项目配置需求的游戏配置解决方案 2. 不想使用protobuf,希望针对项目需求方便地自定义消息生成,满足严苛的内存和性能的要求 3. 希望做其他自定义生成或者缓存 -Luban另一优点是生成过程极快。对于普通的导表工具,一个典型的MMORPG项目后期全量生成配置往往需要几十秒。Luban使用client/server的云生成模型,多线程生成+对象缓存,大多数情况下可以1s内完成整个生成过程 ^_^,加速了日常工作流的迭代过程,积少成多也能为程序和策划同学节省下可观的时间。 +Luban另一优点是生成过程极快。对于普通的导表工具,一个典型的MMORPG项目后期全量生成配置往往需要几十秒。Luban使用client/server的云生成模型,通过多线程并发生成+对象缓存机制,大多数情况下可以1s内完成整个生成过程。 ## 文档 @@ -71,26 +71,26 @@ Luban另一优点是生成过程极快。对于普通的导表工具,一个典 - 其他所有支持lua的引擎和平台 - 其他所有支持js的引擎和平台 -## 快速入门 - 结构定义和数据配置 +## 结构定义与配置表填写 -与常见的专注于excel的导表工具中定义和数据放在同一个excel文件的做法不同,luban的定义与数据分离,使用单独的xml定义 **表和结构**。 +与常见的专注于excel的导表工具中定义和数据放在同一个excel文件的做法不同,luban的定义与数据分离,使用单独的xml定义 **表和结构**,数据文件只包含数据。 ### 常规的原生数据 ``` - - - - - - - - - - - - - - + + + + + + + + + + + + + + ``` ![](docs/images/examples/ex_2.png) @@ -100,16 +100,16 @@ Luban另一优点是生成过程极快。对于普通的导表工具,一个典 定义枚举类,同时强制配置中必须填写枚举名或者别名,提高配置阅读性。 ``` - - - - - - - - - - + + + + + + + + + + ``` ![](docs/images/examples/ex_12.png) @@ -117,15 +117,15 @@ Luban另一优点是生成过程极快。对于普通的导表工具,一个典 ### 自定义结构 bean ``` - - - - - - - - - + + + + + + + + + ``` ![](docs/images/examples/ex_22.png) @@ -134,46 +134,44 @@ Luban另一优点是生成过程极快。对于普通的导表工具,一个典 支持OOP的类型的继承体系,方便表达多类型的数据,经常用于技能、AI等模块。 ``` - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + - - - - - - + + + + + + + ``` ![](docs/images/examples/ex_32.png) ### 可空数据类型 -配置数据中经常有空值的语义需求,实际项目中往往混杂地使用0或-1表达空值,既不自然清晰也不统一。luban借鉴了c#中的可空变量的概念,特地提供可空数据支持。 - -除了string外的所有原生数据类型,以及enum类型都有相应的可空数据类型。定义方式为 <类型名>?,与c#里的Nullable类型定义方式相同。例如 bool?,int?,long?,double?, EColor? +配置数据中经常有空值的语义需求,实际项目中往往混杂地使用0或-1表达空值,既不自然清晰也不统一。luban借鉴了c#中的可空变量的概念,特地提供可空数据支持。除了string外的所有原生数据类型,以及enum类型都有相应的可空数据类型。定义方式为 <类型名>?,与c#里的Nullable类型定义方式相同。例如 bool?,int?,long?,double?, EColor? ``` - - - - - + + + + + ``` ![](docs/images/examples/ex_42.png) @@ -182,11 +180,11 @@ Luban另一优点是生成过程极快。对于普通的导表工具,一个典 一般来说,既可以在一个单元格内以 逗号","分隔填写,也可以每个单元格填写一个数据。注意!空单元格会被忽略。 ``` - - - - - + + + + + ``` ![](docs/images/examples/ex_52.png) @@ -194,73 +192,73 @@ Luban另一优点是生成过程极快。对于普通的导表工具,一个典 ### 结构列表 对于结构列表类型,有多种填写。策划根据具体情况,选择最合适的填法。 -- 填法1。 全展开。 +- 全展开。 ``` - - - - - - - - - - + + + + + + + + + + ``` ![](docs/images/examples/ex_61.png) -- 填法2。 每个Item在一个单元格内 +- 每个Item在一个单元格内 ``` - - - - - - - - - - + + + + + + + + + + ``` ![](docs/images/examples/ex_62.png) -- 填法3。所有数据都在一个单元格内 +- 所有数据都在一个单元格内 ``` - - - - - - - - - - + + + + + + + + + + ``` ![](docs/images/examples/ex_63.png) ### 多态结构列表 ``` - - - - + + + + ``` ![](docs/images/examples/ex_71.png) ### 双主键表 ``` - - - - - - + + + + + +
``` ![](docs/images/examples/ex_91.png) @@ -270,14 +268,16 @@ Luban另一优点是生成过程极快。对于普通的导表工具,一个典 单例即代码模式中单例的含义,用于配置全局只有一份的数据。 ``` - - - - - -
+ + + + + +
``` +luban支持横表与纵表,默认为横表。对于单例表,纵表填写更舒服一些,因此我们在excel的B1单元格填上 row:0 表示它是纵表。 + ![](docs/images/examples/ex_a1.png) ### json 数据源 @@ -285,39 +285,39 @@ Luban另一优点是生成过程极快。对于普通的导表工具,一个典 定义 ``` - - - - - - - - - - - - - - - - 多态数据结构 - - - - - 使用;来分隔 - - - - - - - - - - + + + + + + + + + + + + + + + + 多态数据结构 + + + + + 使用;来分隔 + + + + + + + + + + -
+
``` 以目录为数据源,递归遍历整个目录树,将每个json数据当作一个记录读入。 @@ -394,23 +394,23 @@ Luban另一优点是生成过程极快。对于普通的导表工具,一个典 1.2,2.3,3.41.2,2.2,3.2,4.31970-01-01 00:00:00 - 1 2 - 1 2 - 1 2 - 1 2 - 1 2 - 1 2 - 1 3 + 1 2 + 1 2 + 1 2 + 1 2 + 1 2 + 1 2 + 1 3 210 330 - 1 true - 2 false + 1 true + 2 false - 1 2 + 1 2 ``` @@ -419,11 +419,11 @@ Luban另一优点是生成过程极快。对于普通的导表工具,一个典 定义 ``` - - <<定义同json>> - + + <<定义同json>> + -
+
``` 以目录为数据源,递归遍历整个目录树,将每个lua数据当作一个记录读入。 @@ -464,23 +464,33 @@ Luban另一优点是生成过程极快。对于普通的导表工具,一个典 ``` ------ -## 生成代码与数据 +## 代码与数据生成 以lua为例: 1. 定义全局环境变量LUBAN_SERVER_IP。如果本地已运行luban.server,则取地址为127.0.0.1;如果没有运行,也可以使用已经部属好的云luan服务(仅供快速测试,建议每个项目独立搭建luban-server),地址为 81.69.4.240 。 -1. 进入 config 目录 -1. 双击 生成 lua 数据.bat +1. 进入 config 目录 & 运行 "生成 lua 数据.bat" -生成的 output_lua 目录中即包含所有导出配置数据文件。如下图: +生成的 output_lua 目录包含所有生成的配置数据文件。如下图: ![](docs/images/examples/ex_a2.png) -bat脚本中的 --output_data_dir 参数为输出lua数据目录,可根据实际情况修改。 +命令中的 --output_data_dir 参数为输出的lua数据目录,可根据实际情况修改。 -![](docs/images/examples/ex_a3.png) +``` +..\src\Luban.Client\bin\Debug\net5.0\Luban.Client.exe ^ + -h %LUBAN_SERVER_IP% ^ + -j cfg ^ + -- ^ + -d Defines/root.xml ^ + --input_data_dir Datas ^ + --output_data_dir output_lua ^ + -s client ^ + --gen_types data_lua ^ + --export_test_data +``` ------ -## 程序使用示例 +## 代码使用示例 ### Lua 使用示例 diff --git a/docs/images/examples/ex_a1.png b/docs/images/examples/ex_a1.png index 57b4865fbe7d8a7095d3a8a066d13d925bc69e4d..ff62cb8094191ceb1ef8d693a2e9289791263d74 100644 GIT binary patch literal 5982 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 literal 6364 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 qHes{%lb9W3p