跳到主要内容
版本:classic

excel格式介绍

创建一个普通的xlsx 配置表

  • 假设你要创建的配置为装备表.
  • 在MyConfigs/Datas 目录下创建 equip.xlsx(实践中推荐按模块创建子目录,在模块目录创建配置,便于维护管理), 其内容如下
##varidnameattrvalue
##typeintstringintfloat
##groupcsc,s
1equip1101.2
2equip2153.4
  • 在 MyConfigs/Datas/__tables__.xlsx 里新增一行。 有些不相关列被忽略了
##varfull_namevalue_typedefine_from_excelinput...
demo.TbItemItemtrueequip.xlsx
  • 至此,完成添加新表工具。 运行 check.bat 检查是否成功生成!

excel 标题头行的介绍

  • 第1列单元格为 ##var 表示这行是字段定义行
  • 第1列单元格为 ##type 表示这行是 类型定义行
  • 第1列单元格为 ##group 表示这行是 导出分组行。此行可选。另外,单元格留空表示对所有分组导出。
  • 第1列单元格以##开头 表示这是注释行,如果有多个##行,默认以第一个行作为代码中字段的注释,你可以通过##comment 显式指定某行为代码注释行。
  • 填写多级字段名行时,以##var表示这是次级字段行
  • 你可以随意调整##xxx和##yyy之类的行的顺序,但注意 如果第一行是注释行,必须使用##comment,而不是##。否则会把第一行当字段名行而出错(这是出于兼容性,早期强制第一行是字段名行,允许只以##开头)
##varidname*stages
##varidnamedesclocationitem_idnum
##typeintstringlist,Stage
##iddesc1desc1desc2desc3desc4desc5desc6
##commentid名字注释1desc2desc3desc4desc5desc6
1task11stage1stage desc11,2,310011
2stage2stage desc21,2,310011
3stage3stage desc31,2,310021
2task21stage1stage desc11,2,310011
2stage2stage desc21,2,310021

注释行或列

当标题行字段名为空或者以'#'、'_'开头时,这个列会被当作注释列而忽略。

当数据行的第一列以##开头时,这一行会被当作注释行而被忽略。

excel文件 读取规则

  • 如果未指定sheet,则默认会读取所有sheet
  • 可以用 sheet@xxx.xlsx 指定只读入这个sheet数据
  • 如果A1单元格数据不以##开头,则会被当作非数据sheet,被忽略

支持的excel文件族

支持 xls、 xlsx、 xlm、 xlmx、csv 。基本上excel能打开的都可以读取。

支持非GKB和UTF-8编码的csv文件

luban会智能猜测出它的编码,正确处理。

灵活的配置文件组织形式

  • 可以几个表都放到一个xlsx中,每个表占一个sheet。 只需要为每个表的input指定为该单元薄即可,如 input="xxx@item/test/abs.xlsx"。
  • 可以一个表拆分为几个xlsx。 如 input="item/a.xlsx,bag/b.xlsx,c.xlsx"。
  • 可以一个读入一个目录下的所有xlsx。 如 input="bag" 。

单元格留空取默认值

除了bean以外的数据,都可以留空。自动取默认值。注意非空字段的默认值是初始值,可空变量的默认值为null。例如int默认值是0,但int?的默认值是null。字符串string的默认值是长度为0的空白字符串,而string?的默认为null。

数据格式

限定列格式与流式格式

如果某个字段通过标题头或者多级标题头限定了列范围,它的解析格式为限定列格式。

如果某个字段只是某个限定列格式的字段的某一个子数据,它的解析格式为流式格式。

示例如下。 标注@的列为 限定列格式, 标注~的列为流式格式。

<bean name="Item">
<var name="item_id" type="int"/>
<var name="num" type="int"/>
<var name="desc" type="string">
</bean>
##varidnameitem items
##typeintstringItemlist,Item
##varitem_idnumdesc
@@@@@~~~~~~~~
1xxxx10011item 120011item2
2xxxx10023item 120011item220022item 2

限定列格式介绍

通过标题行及多级标题行,可以精确限定某个数据在某些列范围内。

对于只有一个原子值的简单类型数据,限定列格式下,由于能够非常清晰知道它的值必然来自某一单元格,所以它支持默认值语义,即如果单元格为空,值取默认值,例如 int类型默认值为0,int?默认值为null。

限定列格式下,多态bean类型需要用 $type 列来指定具体类型名,可空bean类型也需要用$type列来指示是有效bean还是空bean。

如果最低层的限定列的类型为容器或者bean,由于限定列只限定了该数据整体范围,但未限定子数据的范围,因此读取子数据的格式为流式格式,即按顺序读入每个子数据。

综合示例如下:

##varidshapeitem
##typeintShapeItem?
##var$typeradiuswidthheight$typeitem_idnumdesc
1Circle10Item10011item 1
2Rectangle102010012item 1
310null
4Circle10

一些数据结构有特殊的列限定支持。

flags=1 的 enum 类型支持列限定模式。

用枚举项作为列名,最终值为所有非0或空的枚举项的或值。

##vartype
##varABCD
11
11

多态bean支持 $type与$value 分别配置的列限定或流式格式的混合填写方式

即用$type列为限定类型,用$value列来限定bean的实际字段,并且$value中以流式填写bean的所有字段。

##varshape
##var$type$value
Circle10
Rectangle10,20

流式格式介绍

对于没有具体限定列范围的子数据,使用流式格式(也只有这种办法),按顺序读入子数据。

由于流式格式无法区分 默认单元格和空白忽略单元格,因此流格式下,不支持默认值语义,会忽略所有空白单元格。 进而对于默认值必须填上有效值默认值来表示数据,而不能留空来表达。

流式格式下的默认值填写规则如下

  • bool 默认值为 false
  • int,float 之类的默认值为 0
  • string 的默认值为""
  • 可空变量,如int? 的空值为 null
  • 容器变量,需要有右大括号 '}' 来表示空值(用'}'表示容器终止)

如下图,item字段为Item类型,包括多个子数据,但没为它的子字段添加子列限定,因此使用流式格式解析它。

  • id=1的列,所有字段能够正常识别
  • id=2的列,第2个单元格为空,被忽略,因此试图将"item 1"当作num字段解析,抛出格式错误的异常。
  • id=3的列,第3个单元格为空,被忽略,尽管desc字段是string值,能接受空白值,也会抛出 数据缺失的异常。

记录2和3的正确填法如4和5。

##varidnameitem
##typeintstringItem
@@~~~
1xxxx10011item 1
2xxxx1001item 1
3xxxx10011
2xxxx10010item 1
3xxxx10011""

流式格式下,各个类型必须填写非空白值,规则如下

  • bool false,true
  • int,float 之类 有效整数值
  • string 用""表示长度为0的字符串,用其他非值表示值本身
  • enum 非空有效值
  • bean 用流式格式按顺序读入每个字段
  • 多态bean类型 先读入一个字符串,可以是具体的子类名或者子类别名,然后再根据子类名,流式读入该类型的每个字段。
  • 可空bean类型 先读入一个字符串,如果是bean的类型名或者'{}',则流格式读入该类型的所有字段;如果为null,则表示空,结束读取;其他情况则抛出解析失败的异常。
  • array,list,set 如果流结束或者下一个读入的为'}',则读取结束,否则用流格式读入element_type,如此循环。
  • map 如果流结束或者下一个读入的为'}',则读取结束,否则递归读入key_type和value_type,如此循环。

以下是一个非常复杂的bean的流式读取示例

<bean name="Foo">
<var name="x" type="int"/>
<var name="y" type="int"/>
</bean>

<bean name="SubList">
<var name="a" type="int"/>
<var name="b" type="list,string"/>
<var name="c" type="bool"/>
</bean>

<bean name="StreamDemo">
<var name="x1" type="int"/>
<var name="x2" type="Foo"/>
<var name="x2_1" type="string"/>
<var name="x2_2" type="list,int"/>
<var name="x3_1" type="string"/>
<var name="x4" type="list,Foo"/>
<var name="x4_1" type="string"/>
<var name="x5" type="SubList"/>
<var name="x5_1" type="string"/>
<var name="x7" type="list,SubList"/>
<var name="x7_1" type="string"/>
<var name="x8_0" type="map,int,int"/>
<var name="x8" type="int">
</bean>
##varidstream_demo
##typeintStreamDemo
##x1x2x2_1x2_2x2_2 end flagx3_1x4[0]x4[1]x4[2]x4 end flagx4_1x5.ax5.bx5.cx5_1x7[0]x7[1]x7 end flagx7_1x8_0x8_0 end flagx8
1102021x2_1234}x3_1111221223232}x4_1100aaabbbb}truex5_1100aaa1bbbb1}true200aaa2bbbb2}false}x7_111002200}1234

sep 介绍

流式格式中,对于包含多个数据的复合类型数据,有时候希望紧凑地在一个单元格内填写它的多个子数据,使用sep可以实现此目的。

由于sep非常常见,而且用法复杂多样,因此在单独的文档 excel sep格式介绍中介绍

原生数据类型

支持 bool,int,float,string,vector2,vector3,vector4 等等类型,它们的填写跟常规认知一致。

##varx1x3x4x5x6x7s1v2v3v4
##typeboolshortintlongfloatdoublestringvector2vector3vector4
##desc1iddesc4desc5desc6desc7desc1desc2desc3desc4
false1010010001.231.2345hello1,21,2,31,2,3,4
true2020010001.231.2345world1,21,2,31,2,3,4

text 类型

该类型数据包含两个字段, key和text, 其中 key 可以重复出现,但要求text完全相同,否则报错。这么设计是为了防止意外写重了key。注意:不允许key为空而text不为空

如果想填空的本地化字符串, key和text完全留空即可,工具会特殊对待,不会加入 key集合。

text的key和text字段都是string类型,因此在连续单元格或者sep产生的连续数据流模式中,同样要遵循用""来表达空白字符串的规则。

##varidx
##typeinttext#sep=,
1/demo/key1,aaaa
2/demo/key2,bbbb
3

datetime 类型

时间是常用的数据类型。Luban 特地提供了支持。

  • 以纯字符串方式填写,填写格式为 以下 4 种。
    • yyyy-mm-dd hh:mm:ss 如 1999-08-08 01:30:29
    • yyyy-mm-dd hh:mm 如 2000-08-07 07:40
    • yyyy-mm-dd hh 如 2001-09-05 07
    • yyyy-mm-dd 如 2003-04-05
  • 以 excel内置的时间格式填写
##varidx
##typeintdatetime
11999-09-09 01:02:03
21999-09-09 01:02
31999-09-09 01
41999-09-09

可空变量

有时候会有一种变量,我们希望它 功能生效时填一个有效值,功能不生效里,用一个值来表示。 例如 int 类型,常常拿 0 或者-1 作无效值常量。 但有时候,0 或-1 也是有效值时,这种做法就不生效了。或者说 项目组内 有时候拿 0,有时候拿-1 作无效值标记,很不统一。我们借鉴 sql 及 c#,引入 可空值概念,用 null 表达空值。

##varidxcolor
##typeintint?QualityColor?
11A
2nullB
32null

向量类型 vector2,vector3,vector4

vector3 有三个字段 float x, float y, float z, 适合用于表示坐标之类的数据。

##varidx2x3x4
##typeintvector2vector3vector4
11,211,22,3312,33,44,55
22,322,44,556.5,4.7,8.9

原生数据列表

##varidarr1arr2arr3arr4
##typeint(array#sep=;),intlist,int(list#sep=|),stringlist,string
##iddesc1desc2desc3desc4
11;2;312xx|yyxxxzzz
22;4345aaaa|bbbb|ccccaaabbbccc
32;4;63456aaaa|bbbb|ccccaaabbbccc

枚举

以枚举名或者别名或者值的方式填写枚举值。

在xml中定义

<enum name="ItemQuality">
<var name="WHITE" alias="" value="0"/>
<var name="GREEN" alias="绿" value="1"/>
<var name="RED" alias="" value="2"/>
</enum>

或者在 __enums__.xlsx 中 定义

##varfull_nameflagsuniquecommenttags*items
##varnamealiasvaluecommenttags
ItemQualityfalsetrueWHITE0
GREEN绿1
RED2

数据表如下

##varidqualityquality2
##typeintItemQualityItemQuality
1RED
2GREEN
3REDWHITE
410

嵌套子结构

经常会碰到,某个字段是结构,尤其这个结构在很多配置里都会复用。

假设任务中包含一个 奖励信息 字段

在xml中定义

<bean name="Reward">
<var name="item_id" type="int"/>
<var name="count" type="int"/>
<var name="desc" type="string">
</bean>

或者在 __beans__.xlsx 里定义

##varfull_namesepcommentfields
##varnametypegroupcommenttags
Rewarditem_idint道具id
countint个数
descstring描述

数据表如下

##varidreward
##typeintReward
##id道具id个数描述
110011desc1
21002100desc2

简单结构列表

某个字段为结构列表的情形也很常见,比如说奖励信息列表包含多个奖励信息,每个奖励都有多个字段。

假设礼包中包含一个道具信息列表字段。支持3种填写模式,具体选择由策划灵活决定。

  • 所有字段完全展开,每个单元格填一个元素。缺点是占用的列较多。如items1字段。
  • 每个结构占据一个单元格,使用sep分割结构子字段。如items2字段。
  • 整个列表占据一个单元格,使用sep分割列表及结构子字段。如items3字段。

xml中定义如下

<bean name="Reward">
<var name="item_id" type="int"/>
<var name="count" type="int"/>
<var name="desc" type="string">
</bean>

或者也可以在__beans__.xlsx中定义,此处不再赘述,==后面的涉及到结构定义的例子都只给xml的示例==。

数据表如下:

##varidrewards1rewards2rewards3
##typeintlist,Rewardlist,Reward#sep=,(list#sep=|),Reward#sep=,
##idreward list desc1reward list desc2reward list desc3
110011desc110022desc21001,1,desc11002,2,desc21003,3,desc31001,1,desc1|1002,2,desc2
210011desc11001,1,desc11002,2,desc21001,1,desc1|1002,2,desc2|1003,1,desc3

或者可以用多级标题头对每个元素单独限定

##varidnamerewards
##typeintstringlist,Reward
##var012
##varitem_idnumdescitem_idnumdescitem_idnumdesc
1task1110desc1212desc2313desc3
2task1330desc3440desc4
3task1550desc5

多行结构列表

有时候列表结构的每个结构字段较多,如果水平展开则占据太多列,不方便编辑,如果拆表,无论程序还是策划都不方便,此时可以使用多行模式。支持任意层次的多行结构列表(也即多行结构中的每个元素也可以是多行), name#multi_rows=1或者*name 都可以表达一个多行解析的字段。

假设每个任务包含多个阶段,有一个阶段列表字段。

<bean name="Stage">
<var name="id" type="int"/>
<var name="name" type="string"/>
<var name="desc" type="string"/>
<var name="location" type="vector3"/>
<var name="reward_item_id" type="int"/>
<var name="reward_item_count" type="int"/>
</bean>
##varidname*stage2
##typeintstringlist,Stage
##iddescstage info
1task11stage1stage desc11,2,310011
2stage2stage desc21,2,310011
3stage3stage desc31,2,310021
2task21stage1stage desc11,2,310011
2stage2stage desc21,2,310021

列表表 (无主键)

有时候只想得到一个记录列表,无主键。mode="list"并且index为空,表示无主键表。

定义表

<table name="TbNotKeyList" value="NotKeyList" mode="list" input="not_key_list.xlsx"/>

示例数据表

##varxyznum
##typeintlongstringint
11aaa123
11bbb124
12aaa134
21aaa124
56xxx898

多主键表(联合索引)

多个key构成联合唯一主键。使用"+"分割key,表示联合关系。

定义表

<table name="TbUnionMultiKey" value="UnionMultiKey" index="key1+key2+key3" input="union_multi_key.xlsx"/>

示例数据表

##varkey1key2key3num
##typeintlongstringint
11aaa123
11bbb124
12aaa134
21aaa124
56xxx898

多主键表(独立索引)

多个key,各自独立唯一索引。与联合索引写法区别在于使用 ","来划分key,表示独立关系。

定义表

<table name="TbMultiKey" value="MultiKey" index="key1,key2,key3" input="multi_key.xlsx"/>

示例数据表

##varkey1key2key3num
##typeintlongstringint
12aaa123
24bbb124
36ccc134
48ddd124
51eee898

单例表

有一些配置全局只有一份,比如 公会模块的开启等级,背包初始大小,背包上限。此时使用单例表来配置这些数据比较合适。

##varguld_open_levelbag_init_capacitybag_max_capacitynewbie_tasks
##typeintintintlist,int
##desc1desc 2desc 3desc 4
1010050010001,10002

纵表

大多数表都是横表,即一行一个记录。有些表,比如单例表,如果纵着填,一行一个字段,会比较舒服。A1为##column表示使用纵表模式。 上面的单例表,以纵表模式填如下。

##var#column##type##
guild_open_levelintdesc110
bag_init_capacityintdesc2100
bag_max_capacityintdesc3500
newbie_tasks(list#sep=,),intdesc410001,10002

引用检查

游戏配置中经常要填写诸如道具id之类的外键数据,这些数据必须是合法的id值,luban支持生成时检查id的合法性,如果有误,则打出警告。不只是表顶层字段,列表及嵌套结构的子字段也支持完整的引用检查。

<bean name="Reward">
<var name="item_id" type="int" ref="item.TbItem"/>
<var name="count" type="int"/>
<var name="desc" type="string">
</bean>
##variditem_iditemsrewardrewards
##typeintint#ref=item.TbItemlist,int#ref=item.TbItemRewardlist,Reward#sep=,
##iddesc1desc2desc3desc4
110011001,1002100110item11001,10,item11002,2,item2
210021003,1004,1005100210item21004,10,item41005,2,item51010,1,item10

资源检查

配置中经常要填写资源路径,比如道具icon的资源,这些数据都是string类型,非常容易填写出错,导致运行时无法正常显示。luban支持unity与ue4资源的合法性检查以及通用型文件路径检查。不只是表顶层字段,列表及嵌套结构的子字段也支持完整的引用检查。

对于这些字段添加属性 path=unity或者path=ue或path=normal;xxxx。

##varidicon
##typeintstring#path=unity
##idicon desc
1Assets/UI/item1.jpg
2Assets/UI/item2.jpg

分组导出

灵活的分组定义,不仅仅是client和server分组。支持以下分组粒度:

  • 表级别分组
  • 字段级别分组(任意bean字段粒度,而不仅限于顶层字段)

数据标签过滤

开发期经常会制作一些仅供开发使用的配置,比如测试道具,比如自动化测试使用的配置,希望在正式发布时不导出这些数据。

##varidname
##typeintstring
##iddesc1注释
1item1永远导出
##2item2永远不导出
test4item4--export_exclude_tags test 时不导出
TEST5item5--export_exclude_tags test 时不导出
dev6item6--export_exclude_tags dev 时不导出
7item7永远导出

多行记录填写

目前只对容器类型字段支持多行。字段名前加,如stages,或者添加multi_rows=1参数也行,如stages#multi_rows=1。 一旦标记字段为多行,每行会作为字段的一个元素读入,例如 list,bean类型,则每行读入一个bean结构。

多行可以嵌套,即多行字段中,某个字段本身也可以是多行记录。 示例可参见multi_rows_record

<bean name="Stage">
<var name="id" type="int"/>
<var name="name" type="string"/>
<var name="desc" type="string"/>
<var name="location" type="vector3"/>
<var name="reward_item_id" type="int"/>
<var name="reward_item_count" type="int"/>
</bean>
##varidname*stages
##typeintstringlist,Stage
##iddescstage info
1task11stage1stage desc11,2,310011
2stage2stage desc21,2,310011
3stage3stage desc31,2,310021
2task21stage1stage desc11,2,310011
2stage2stage desc21,2,310021

层级标题头 (hierarchy title)

在多行数据或者深层次嵌套的数据中,如果数据字段较多,填写时不易区分子元素。luban提供层级标题实现深层次的子字段对应。以上面的多行数据列表为例,第一列为##var表示这是个子字段行。

  • 普通bean结构的子标题
##varidnamestage
##typeintstringStage
##varnamedesclocationitem_idnum
##idnamedesc2desc3desc4desc5desc6
1task1stage1stage desc11,2,310011
2task2stage2stage desc23,4,520013
  • list,bean 的多行展开多级子标题
##varidname*stages
##typeintstringlist,Stage
##varidnamedesclocationitem_idnum
##iddesc1desc1desc2desc3desc4desc5desc6
1task11stage1stage desc11,2,310011
2stage2stage desc21,2,310011
3stage3stage desc31,2,310021
2task21stage1stage desc11,2,310011
2stage2stage desc21,2,310021
  • list,bean 的水平展开多级子标题
##varidnameitems
##typeintstringlist,Item
##var012
##varitem_idnumdescitem_idnumdescitem_idnumdesc
1task1110desc1212desc2313desc3
2task1330desc3440desc4
3task1550desc5
  • map 类型的多级子标题
##varidlans
##typeintmap,string,string
##varch-znenjpfr
1苹果appleaaaaaa
2香蕉bananabbbbbb

多态结构

示例定义如下

<bean name="Shape">
<bean name="Circle">
<var name="radius" type="float"/>
</bean>
<bean name="Rectangle" alias="长方形">
<var name="width" type="float"/>
<var name="height" type="float"/>
</bean>
<bean name="Curve">
<bean name="Line" alias="直线">
<var name="param_a" type="float"/>
<var name="param_b" type="float"/>
</bean>
<bean name="Parabola" alias="抛物线">
<var name="param_a" type="float"/>
<var name="param_b" type="float"/>
</bean>
</bean>
</bean>

##varidshapes
##typeintlist,Shape#sep=,
##id shape desc
1Circle,10Rectangle,100,200
2Circle,20Rectangle,100,200Line,5,8Parabola,15,30

字段默认值

我们希望excel中单元格留空时,该字段取指定值,而不是默认的false,0之类。通过定义字段的default=xxx属性来指定默认值。

如示例,id=2的记录,x1与x2皆为空,x1=0,x2=-1。

##varidx1x2#default=-1
##typeintintint
##iddesc1desc2
11020
2
330

常量别名

游戏里经常会出现一些常用的类似枚举的值,比如说 升级丹的 id,在很多地方都要填,如果直接它的道具 id,既不直观,也容易出错。 Luban 支持常量替换。如示例,导出时SHENG_JI_DAN会被替换为11220304。

<enum name="EFunctionItemId">
<var name="SHENG_JI_DAN" alias="升级丹" value="11220304"/>
<var name="JIN_JIE_DAN" alias="进阶丹" value="11220506"/>
</enum>
##variditem_id
##typeintint#convert=EFunctionItemId
##iddesc
1SHENG_JI_DAN
2进阶丹
31001

单元格取非0默认值

只对excel格式有效。在字段名上加上 xxx#default=value,则所有留空的单元格都会自动取value。如下图,id=2的记录,count=10,desc=haha。 default是excel格式特有属性,它作用于列,必须填在字段名上。

##varidcount#default=10desc#default=haha
##typeintintstring
11abc
2