游戏客户端,服务器的策划表格数据导出
将电子表格文件根据制定proto及字段转化规则,导出为Protobuf文本格式(*.pbt)
使用者通过读取Protobuf文本格式直接获取到所有的格式化数据
本转化器无需依赖vbs,vba.跨平台
直接输出基于Protobuf文本的格式化数据, 直接读取
字段位置随意调整, 自动检查错误, 精确报错位置
充分利用CPU多核进行导出, 是已知的现有导出器中最快的
-
2011年: 一代导出器,基于VBA的表格内建导出器,速度慢,复用困难,容易错,不安全
-
2012年: 二代导出器,基于C++和Protobuf的导出器,内容格式与导出器混合编写,需要vbs导出csv,速度慢
-
2013年: 三代导出器,在二代基础上做到内容格式与导出器独立,但依然依赖csv前置导出,增加逗号分隔格子内容,导出速度慢
-
2015年: 四代导出器,基于Golang导出器,增加ID重复检查,数组格的多重写法, 支持a.b.c栏位导出, 导出速度大大提高
-
2016年: 五代导出器,在四代基础上重构,开源,支持并发导出,速度达到极致
前面多个版本都在本人项目中使用
53个Excel源文件, 格式xlsm, 大小3.8M
导出速度
-
9.4s 第四代导出器
-
4.9s 第五代导出器单线程
-
2.4s 第五代导出器i7-4790 8核并发
go get github.com/davyxu/tabtoy
go install github.com/davyxu/tabtoy
syntax = "proto3";
package test;
enum ActorType
{
Fighter = 0; // [tabtoy] Alias:"格斗士" #使用#号可在meta后方添加注释
Power = 21; // [tabtoy] Alias: "超能"
}
message Prop
{
int32 HP = 1;
float AttackRate = 2;
}
// 代表每一行对应的整个字段描述
message ActorDefine
{
// 唯一ID
int32 ID = 1; // [tabtoy] RepeatCheck: true #ID重复检查
// 角色名称
string Name = 5;
Prop Struct = 10;
repeated int32 BuffID = 20; // 重复字段可以用多列进行读取
// 角色类型
ActorType Type = 30;
repeated int32 SkillID = 40; // [tabtoy] String2ListSpliter: "," #使用,切割字符串
Prop StrStruct = 50; // [tabtoy] String2Struct: true
}
// 代表导出文件
message ActorFile
{
repeated ActorDefine Actor = 1; // 每一个元素代表电子表格的一行
}
..\proto\protoc.exe test.proto --plugin=protoc-gen-meta=..\..\..\..\..\bin\protoc-gen-meta.exe --proto_path "." --meta_out test.pb:.
..\..\..\..\..\bin\tabtoy.exe --mode=xls2pbt --pb=test.pb --outdir=. Actor.xlsx
导出文件样式
# Generated by github.com/davyxu/tabtoy
Actor {ID: 100 Name: "黑猫警长" Struct {HP: 100 AttackRate: 0.6} BuffID: 0 BuffID: 0 SkillID: 4 SkillID: 6 SkillID: 7}
Actor {ID: 101 Name: "葫芦娃" Struct {AttackRate: 0.8} BuffID: 3 BuffID: 1 Type: Power SkillID: 1}
Actor {ID: 102 Name: "舒克" Struct {AttackRate: 0.7} BuffID: 0 BuffID: 0 SkillID: 0 StrStruct {HP: 2 AttackRate: 0.5}}
Actor {ID: 103 Name: "贝塔" Struct {HP: 205} BuffID: 0 BuffID: 0 SkillID: 0}
Actor {ID: 104 Name: "邋遢大王" Struct {AttackRate: 1} BuffID: 0 BuffID: 0 SkillID: 0}
Google Protobuf 官方支持的格式 可通过官方protobuf库读取,写入这种格式 与json区别在于: json的字段名必须是带双引号, 且数组需要用[]圈住, 多重字段尾部必须加逗号
-
格式 key1: value1 key2: value2 冒号组合key,value, 空格分隔字段
#作为注释
proto文件格式范例参考test/test.proto 需要配合github.com/davyxu/pbmeta的protobuf插件protoc-gen-meta导出proto文件的meta信息
在proto的字段后方的注释中以[tabtoy]开头的注释将被理解为meta信息, 用于描述字段导出功能修饰 例如: // [tabtoy] RepeatCheck: true #ID重复检查
[tabtoy] 后方的格式为Protobuf Text, 使用#作为注释
具体的meta功能请参考后面的小节
必须放在需要导出的Sheet的1,1位置
格式: ProtoTypeName: "package名.message名" RowFieldName: "导出字段"
Proto字段列, 必须放在第二行
用于描述字段功能, 必须放在第三行
从第四行开始, 一直到 第一列为空 时表示数据行结束, 后续行不再导出
当枚举值字段meta信息中填写Alias: "别名"时 单元格值中即可填写原枚举的程序枚举类型, 也可以填写别名
当字段类型为结构体A, 实例名为a时, 若需要设置结构体内部的某字段类型B, 实例名为b时 只需要在Proto字段行中填写a.b即可
本功能仅限于非repeated字段
当字段meta信息中填写String2Struct: true时, 将把单元格的值理解为Protobuf Text格式并检查输出
当字段meta信息中填写RepeatCheck: true时, 将检查列中的本字段是否有重复字段(字符串方式)
当字段类型为repeated类型时, 可将字段按同名方式切成多个字段导出
当字段类型为repeated类型时, 且字段meta信息中填写String2ListSpliter: "分隔字符串"时 字段值会用"分隔字符串"切割并存储到repeated字段中
-
建议每个proto文件对应1个电子表格(xls,xlsm),名字统一
例: Actor.proto 对应的电子表格名Actor.xls,最终导出文件为Actor.pbt
-
一个电子表格内的所有Sheet都是合并导出为一个pbt 例: Actor.xls中拥有名为ActorA ActorB的Sheet,最终导出的Actor.pbt中将包含ActorA和ActorB的数据
-
没有导出头(单元格1,1)的格子不会被导出
引用github.com/golang/protobuf库
例子:
func LoadPBTFile(filename string, msg proto.Message) error {
content, err := ioutil.ReadFile(filename)
if err != nil {
return err
}
return proto.UnmarshalText(string(content), msg)
}
// 准备你的消息结构
var msg gamedef.YourMessage
// 直接读取pbt文件
LoadPBTFile( "Data.pbt", &msg )
步骤
-
使用github.com/davyxu/mergepbt 将多个pbt合并并转为二进制
-
使用protobuf-net库加载对应的二进制文件并读取
例如:
using (var stream = File.OpenRead(pathToPbt))
{
var yourmsg = ProtoBuf.Serializer.Deserialize<gamedef.ClientConfig>(stream);
stream.Close();
}
- 支持protobuf文本格式的语言可以直接读取pbt文件
例如: 官方包内的支持的C++, C#, Java, Golang等等
- 不支持文本格式的语言需要使用github.com/davyxu/mergepbt进行合并转换, 使用二进制读取
例如: Unity3D使用的protobuf-net
-
为什么输出文本格式,而不是二进制?
从设计角度: 文本只需要字段就可以导出, 而二进制需要复杂的二进制连接操作,设计复杂度较低
从使用角度: 文本调试,查看很方便
-
为什么只有Protobuf Text输出没有json或者其他格式?
Protobuf 2.X时是对Protobuf Text有良好的支持, 包括Golang
进入3.0 后, 大概由于Protobuf Text不是主流格式, 因此官方还是提供json格式支持
-
C++和C#支持么?
C++用官方的Protobuf库可以读取导出格式, C#的protobuf-net无法读取, 需要自己根据你的消息格式转换文本到二进制才可读取
-
导出meta信息时, 多个proto文件写的批处理很长, 怎么办?
批处理的多行连接符是^, 例如
protoc a.proto ^
b.proto ^
c.proto
注意 空格不能少
-
为什么并发导出时, 日志顺序是乱的?
Visual Studio并发编译C++时也是乱的, 当然它可以调顺序模式
乱和速度不可兼得, 因为懒:)
支持proto3 map及根据id查配置的代码生成
感觉不错请star, 谢谢!
博客: http://www.cppblog.com/sunicdavy