“Database.tdb/zh”的版本间的差异
小 (以最新结果修改部分叙述) |
(写完了) |
||
第18行: | 第18行: | ||
后文叙述中,比特之间左为高位,字节之间右为高位。(与HxD排布一致) | 后文叙述中,比特之间左为高位,字节之间右为高位。(与HxD排布一致) | ||
− | + | 后文中有关字符串的存储是指:先以ASCII进行序列化。然后与C语言类似,在字符串的末尾存储<code>0x00</code>以表示字符串结束。 | |
− | + | 后文中的Int32类型和Float类型存储均是大端序存储模式 | |
=== 加密解开 === | === 加密解开 === | ||
− | + | 数据库是具有一定加密的,需要通过特定方法解开加密,才能得到可以被阅读的数据,加密的方法为解密的逆向。 | |
==== 交换比特 ==== | ==== 交换比特 ==== | ||
− | + | 首先,解密是以字节为单位进行的。每个字节有8个比特,解密的第一步是还原比特顺序,将这8个比特的高位3比特和低位5比特交换位置,完成解密的第一步。如下图: | |
<code>BIT_1 BIT_2 BIT_3 BIT_4 BIT_5 BIT_6 BIT_7 BIT_8</code>经过变换后得到<code>BIT_4 BIT_5 BIT_6 BIT_7 BIT_8 BIT_1 BIT_2 BIT_3</code> | <code>BIT_1 BIT_2 BIT_3 BIT_4 BIT_5 BIT_6 BIT_7 BIT_8</code>经过变换后得到<code>BIT_4 BIT_5 BIT_6 BIT_7 BIT_8 BIT_1 BIT_2 BIT_3</code> | ||
第40行: | 第40行: | ||
可通过代码(<nowiki>C#</nowiki>)实现:<code>j = (byte)(-(j ^ 0xAF));</code> | 可通过代码(<nowiki>C#</nowiki>)实现:<code>j = (byte)(-(j ^ 0xAF));</code> | ||
− | === | + | === Virtools Array === |
− | + | 再进一步叙述内容之前,您需要先对Virtools Array有一个初步的了解。 | |
+ | |||
+ | Virtools Array与您常见的Excel表格类似,就是一种表格,每一个单元格都可以存储数据。行和列限制了这个表格的大小。每个Virtools Array都具有一个表头,表头记录了某一列的'''表头名称'''以及这一列的单元格是何种'''数据类型'''。每一行都可以记录数据。 | ||
+ | |||
+ | 如果您了解数据库,那么就更好理解了,表头分别记录了每一个字段的字段名和类型,而每一行就是一个记录。 | ||
+ | |||
+ | 如果您需要找寻示例,您可以使用[[Virtools]]打开位于<code>3D Entities</code>文件夹下的[[Balls.nmo]]或者其他NMO文件,然后在Level Manager中展开到表格部分,随便打开一个就是一个实例。 | ||
+ | |||
+ | === 存储格式 === | ||
+ | |||
+ | 既然已经了解了Virtools Array,那么现在可以直接说,Database.tdb在解码之后就是'''一个个Virtools Array首尾相接存储'''而成。下面将介绍每一个Virtools Array是如何存储的。 | ||
+ | |||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! 助记符 !! 数据类型<ref>此数据类型指的是数据如何被存储在文件中,与上文表头数据类型无关</ref> !! 注释 | ||
+ | |- | ||
+ | | SheetHeader || String || 表名,Virtools Array的名称 | ||
+ | |- | ||
+ | | ChunkSize || Int32 || 区块大小,即从<code>Columns</code>到<code>Cells</code>的长度 | ||
+ | |- | ||
+ | | Columns || Int32 || 该表共有多少列 | ||
+ | |- | ||
+ | | Rows || Int32 || 该表共有多少行 | ||
+ | |- | ||
+ | | {{color|Separator|orange}} || - || 为定值:<code>0xFF, 0xFF, 0xFF, 0xFF</code>,疑似充当分隔符 | ||
+ | |- | ||
+ | | Header || - || 表头列表存储 | ||
+ | |- | ||
+ | | Cells || - || 单元格列表存储 | ||
+ | |} | ||
+ | |||
+ | ==== 表头列表 ==== | ||
+ | |||
+ | 表头列表是由左侧表头向右侧表头逐个写入,且每个表头写入规则如下表: | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
− | ! 助记符 !! | + | ! 助记符 !! 数据类型 !! 注释 |
|- | |- | ||
− | | | + | | HeaderName || String || 表头名称 |
|- | |- | ||
− | | | + | | FieldType || Int32 || 表明表头存储的数据类型(表头对应列的数据类型):<br /> |
+ | * <code>1</code>:Int32 | ||
+ | * <code>2</code>:Float | ||
+ | * <code>3</code>:String | ||
+ | * <code>4</code><ref>未验证,由Virtools内部的布置猜测</ref>:Object(解析时不会用到) | ||
+ | * <code>5</code><ref>未验证,由Virtools内部的布置猜测</ref>:Parameter(解析时不会用到) | ||
+ | |} | ||
+ | |||
+ | ==== 单元格列表 ==== | ||
+ | |||
+ | 单元格从左上角开始存储,与大多数人的通常认知不同,单元格遵循先自增行数,待一列存储完毕,切到下一列从上至下逐行存储的模式,即先行后列。每个数据存储的时候'''根据其对应类型'''首尾相接直接写入即可。 | ||
+ | |||
+ | == 被存储的表 == | ||
+ | |||
+ | 通过上面的了解,您应该了解,Database.tdb存储了一系列表,那么Database.tdb到底存储了哪些表呢?Database.tdb存储的表格如下表所列,请注意表的存储先后是需要注意的。 | ||
+ | |||
+ | {| class="wikitable" | ||
|- | |- | ||
− | + | ! 表名 !! 注释 | |
|- | |- | ||
− | | | + | | DB_Highscore_Lv01 || 第1关高分榜 |
|- | |- | ||
− | | | + | | DB_Highscore_Lv02 || 第2关高分榜 |
|- | |- | ||
− | | | + | | DB_Highscore_Lv03 || 第3关高分榜 |
|- | |- | ||
− | | | + | | DB_Highscore_Lv04 || 第4关高分榜 |
|- | |- | ||
− | | | + | | DB_Highscore_Lv05 || 第5关高分榜 |
|- | |- | ||
− | | | + | | DB_Highscore_Lv06 || 第6关高分榜 |
|- | |- | ||
− | | | + | | DB_Highscore_Lv07 || 第7关高分榜 |
|- | |- | ||
− | | | + | | DB_Highscore_Lv08 || 第8关高分榜 |
|- | |- | ||
− | | | + | | DB_Highscore_Lv09 || 第9关高分榜 |
|- | |- | ||
− | | | + | | DB_Highscore_Lv10 || 第10关高分榜 |
|- | |- | ||
− | | | + | | DB_Highscore_Lv11 || 第11关高分榜 |
|- | |- | ||
− | | | + | | DB_Highscore_Lv12 || 第12关高分榜 |
|- | |- | ||
− | | | + | | DB_Levelfreischaltung || 关卡激活(Freischaltung为德语激活的意思) |
|- | |- | ||
− | | | + | | DB_Options || 游戏设置 |
|- | |- | ||
− | | | + | | DB_Highscore_Lv13 || 第13关高分榜 |
|- | |- | ||
− | | | + | | DB_Highscore_Lv14 || 第14关高分榜(无用处) |
|- | |- | ||
− | | | + | | DB_Highscore_Lv15 || 第15关高分榜(无用处) |
|- | |- | ||
− | | | + | | DB_Highscore_Lv16 || 第16关高分榜(无用处) |
|- | |- | ||
− | | | + | | DB_Highscore_Lv17 || 第17关高分榜(无用处) |
+ | |- | ||
+ | | DB_Highscore_Lv18 || 第18关高分榜(无用处) | ||
+ | |- | ||
+ | | DB_Highscore_Lv19 || 第19关高分榜(无用处) | ||
+ | |- | ||
+ | | DB_Highscore_Lv20 || 第20关高分榜(无用处) | ||
|} | |} | ||
− | + | 需要注意的是表<code>DB_Highscore_Lv13</code>至表<code>DB_Highscore_Lv20</code>在v1.0版本Ballance的Database.tdb中不存在 | |
− | + | 下面将叙述这些表的格式,将直接使用Wiki的表格进行描述,Wiki表格的表头即为Virtools Array的表头,第一行为名称,第二行为数据类型。表格中的数据是随便填写的(主要是对列数和行数有一个直观展示,会使得下面见到的表和在Virtools编辑器中见到的表格几乎完全一致),如果有需要叙述的会用''斜体字''标明。 | |
− | + | 以上这些表被定义在[[base.cmo]]中。 | |
− | === | + | === DB_Highscore === |
− | + | DB_Highscore类型的表共有20个,分别代表每一关的高分榜,每一个表都遵循如下格式: | |
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
− | ! | + | ! Playername<br />{{color|String|green}} !! Points<br />{{color|Int32|green}} |
|- | |- | ||
− | | | + | | Mr. Default || 0 |
|- | |- | ||
− | | | + | | Mr. Default || 0 |
|- | |- | ||
− | | | + | | Mr. Default || 0 |
|- | |- | ||
− | | | + | | Mr. Default || 0 |
|- | |- | ||
− | | | + | | Mr. Default || 0 |
|- | |- | ||
− | | | + | | Mr. Default || 0 |
|- | |- | ||
− | | | + | | Mr. Default || 0 |
|- | |- | ||
− | | | + | | Mr. Default || 0 |
|- | |- | ||
− | | | + | | Mr. Default || 0 |
|- | |- | ||
− | | | + | | Mr. Default || 0 |
+ | |} | ||
+ | |||
+ | === DB_Levelfreischaltung === | ||
+ | |||
+ | DB_Levelfreischaltung记录了前12关的解锁信息。遵循如下格式: | ||
+ | |||
+ | {| class="wikitable" | ||
|- | |- | ||
− | | | + | ! Freigeschaltet?<br />{{color|Boolean|green}}<ref>这里有一个隐式类型转换,Int32的1相当于True,0相当于False,后文不再标记</ref> |
|- | |- | ||
− | | | + | | 1 |
|- | |- | ||
− | | | + | | 0 |
|- | |- | ||
− | | | + | | 0 |
|- | |- | ||
− | | | + | | 0 |
+ | |- | ||
+ | | 0 | ||
+ | |- | ||
+ | | 0 | ||
+ | |- | ||
+ | | 0 | ||
+ | |- | ||
+ | | 0 | ||
+ | |- | ||
+ | | 0 | ||
+ | |- | ||
+ | | 0 | ||
+ | |- | ||
+ | | 0 | ||
+ | |- | ||
+ | | 0 | ||
+ | |} | ||
+ | |||
+ | === DB_Options === | ||
+ | |||
+ | DB_Options存储了游戏的一些常用设置。遵循如下格式: | ||
+ | |||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! style="min-width: 4em" | Volume<br />{{color|Float|green}} !! style="min-width: 4em" | Synch to Screen?<br />{{color|Boolean|green}} !! style="min-width: 4em" | Key Forward<br />{{color|Int32|green}} !! style="min-width: 4em" | Key Backward<br />{{color|Int32|green}} !! style="min-width: 4em" | Key Left<br />{{color|Int32|green}} !! style="min-width: 4em" | Key Right<br />{{color|Int32|green}} !! style="min-width: 4em" | Key Rotate Cam<br />{{color|Int32|green}} !! style="min-width: 4em" | Key Lift Cam<br />{{color|Int32|green}} !! style="min-width: 4em" | Invert Cam Rotation?<br />{{color|Boolean|green}} !! style="min-width: 4em" | LastPlayer<br />{{color|String|green}} !! style="min-width: 4em" | CloudLayer?<br />{{color|Boolean|green}} | ||
+ | |- | ||
+ | | ''音量,从0-1取值'' || ''是否垂直同步'' || ''前进按键'' || ''后退按键'' || ''左行按键'' || ''右行按键'' || ''旋转摄像机按键'' || ''提升摄像机按键'' || ''是否反转摄像机旋转'' || ''最近在高分榜姓名处输入的名称'' || ''是否开启云层'' | ||
|} | |} | ||
− | ==== | + | 对于按键,遵循以下代码(C#): |
+ | |||
+ | <pre> | ||
+ | private static readonly List<string> keys = new List<string>() {"1","2","3","4","5","6","7","8","9","0","-","=","BackSpace","Tab","Q","W","E","R","T","Y","U","I","O","P", | ||
+ | "[","]","Ctrl","A","S","D","F","G","H","J","K","L",";","'","`","Shift","\\","Z","X","C","V","B","N","M",",",".","/", | ||
+ | "Right Shift","Alt","Space","Num 7","Num 8","Num 9","Num -","Num 4","Num 5","Num 6","Num +","Num 1","Num 2","Num 3","Num 0","Num Del","<","Up","Down","Left","Right"}; | ||
+ | </pre> | ||
+ | |||
+ | 按键在此数组中的序号即为需要存储的数据。 | ||
+ | |||
+ | == 注释 == | ||
− | + | <references /> | |
[[Category:游戏文件]] | [[Category:游戏文件]] |
2020年1月3日 (五) 22:15的版本
不完善的条目 | ||
---|---|---|
Database.tdb是位于Ballance游戏根目录下的一个数据库文件。负责存储游戏每一关的高分榜,关卡是否开启;以及一些游戏设置,例如按键设置,是否开启云层等。
目录
简介
在早期游戏过程中,玩家可以通过替换Database.tdb文件来修改其掌控的数据,例如关卡全开tdb文件,其一度流传广泛。
后来,在BallanceRecordChanger出现后,直接复制替换Database.tdb变得不再是最佳方法,使用BallanceRecordChanger可以精确修改Database.tdb文件中的每一个数据,而并不像替换Database.tdb文件一样,“眉毛胡子一把抓”。
Database.tdb是由游戏内部脚本自行创建修改的,且附带加密。有一段时间有一些人曾以高分榜的成绩作为竞速依据[来源请求],但在Database.tdb真正可以被定制修改之前很久,此方法就已经因证据不够确凿而被废弃(例如可以修改地图或使用球补丁等达到更高分数),取而代之的是视频验证。
文件结构
此处介绍的是针对1.13版本,即具有13关补丁的Database.tdb的文件格式进行介绍。此外还有一个版本的Database.tdb,其对应Ballance v1.0版本。由于1.0版本的文件结构中仅仅缺少了v1.13中的部分字段,因此会在后续介绍v1.13版本的结构中标明哪些字段在v1.0版本的文件结构中不存在
后文叙述中,比特之间左为高位,字节之间右为高位。(与HxD排布一致)
后文中有关字符串的存储是指:先以ASCII进行序列化。然后与C语言类似,在字符串的末尾存储0x00
以表示字符串结束。
后文中的Int32类型和Float类型存储均是大端序存储模式
加密解开
数据库是具有一定加密的,需要通过特定方法解开加密,才能得到可以被阅读的数据,加密的方法为解密的逆向。
交换比特
首先,解密是以字节为单位进行的。每个字节有8个比特,解密的第一步是还原比特顺序,将这8个比特的高位3比特和低位5比特交换位置,完成解密的第一步。如下图:
BIT_1 BIT_2 BIT_3 BIT_4 BIT_5 BIT_6 BIT_7 BIT_8
经过变换后得到BIT_4 BIT_5 BIT_6 BIT_7 BIT_8 BIT_1 BIT_2 BIT_3
可通过代码(C#)实现:j = (byte)(j << 3 | j >> 5);
异或补码变换
此后需要进行异或补码变换,首先将交换比特结束后的字节与0xAF
做异或(XOR)运算,然后对得到的字节再取补码,即最高位取反,其余位取反后+1。此时,文件的加密已解开。
可通过代码(C#)实现:j = (byte)(-(j ^ 0xAF));
Virtools Array
再进一步叙述内容之前,您需要先对Virtools Array有一个初步的了解。
Virtools Array与您常见的Excel表格类似,就是一种表格,每一个单元格都可以存储数据。行和列限制了这个表格的大小。每个Virtools Array都具有一个表头,表头记录了某一列的表头名称以及这一列的单元格是何种数据类型。每一行都可以记录数据。
如果您了解数据库,那么就更好理解了,表头分别记录了每一个字段的字段名和类型,而每一行就是一个记录。
如果您需要找寻示例,您可以使用Virtools打开位于3D Entities
文件夹下的Balls.nmo或者其他NMO文件,然后在Level Manager中展开到表格部分,随便打开一个就是一个实例。
存储格式
既然已经了解了Virtools Array,那么现在可以直接说,Database.tdb在解码之后就是一个个Virtools Array首尾相接存储而成。下面将介绍每一个Virtools Array是如何存储的。
助记符 | 数据类型[1] | 注释 |
---|---|---|
SheetHeader | String | 表名,Virtools Array的名称 |
ChunkSize | Int32 | 区块大小,即从Columns 到Cells 的长度
|
Columns | Int32 | 该表共有多少列 |
Rows | Int32 | 该表共有多少行 |
Separator | - | 为定值:0xFF, 0xFF, 0xFF, 0xFF ,疑似充当分隔符
|
Header | - | 表头列表存储 |
Cells | - | 单元格列表存储 |
表头列表
表头列表是由左侧表头向右侧表头逐个写入,且每个表头写入规则如下表:
助记符 | 数据类型 | 注释 |
---|---|---|
HeaderName | String | 表头名称 |
FieldType | Int32 | 表明表头存储的数据类型(表头对应列的数据类型): |
单元格列表
单元格从左上角开始存储,与大多数人的通常认知不同,单元格遵循先自增行数,待一列存储完毕,切到下一列从上至下逐行存储的模式,即先行后列。每个数据存储的时候根据其对应类型首尾相接直接写入即可。
被存储的表
通过上面的了解,您应该了解,Database.tdb存储了一系列表,那么Database.tdb到底存储了哪些表呢?Database.tdb存储的表格如下表所列,请注意表的存储先后是需要注意的。
表名 | 注释 |
---|---|
DB_Highscore_Lv01 | 第1关高分榜 |
DB_Highscore_Lv02 | 第2关高分榜 |
DB_Highscore_Lv03 | 第3关高分榜 |
DB_Highscore_Lv04 | 第4关高分榜 |
DB_Highscore_Lv05 | 第5关高分榜 |
DB_Highscore_Lv06 | 第6关高分榜 |
DB_Highscore_Lv07 | 第7关高分榜 |
DB_Highscore_Lv08 | 第8关高分榜 |
DB_Highscore_Lv09 | 第9关高分榜 |
DB_Highscore_Lv10 | 第10关高分榜 |
DB_Highscore_Lv11 | 第11关高分榜 |
DB_Highscore_Lv12 | 第12关高分榜 |
DB_Levelfreischaltung | 关卡激活(Freischaltung为德语激活的意思) |
DB_Options | 游戏设置 |
DB_Highscore_Lv13 | 第13关高分榜 |
DB_Highscore_Lv14 | 第14关高分榜(无用处) |
DB_Highscore_Lv15 | 第15关高分榜(无用处) |
DB_Highscore_Lv16 | 第16关高分榜(无用处) |
DB_Highscore_Lv17 | 第17关高分榜(无用处) |
DB_Highscore_Lv18 | 第18关高分榜(无用处) |
DB_Highscore_Lv19 | 第19关高分榜(无用处) |
DB_Highscore_Lv20 | 第20关高分榜(无用处) |
需要注意的是表DB_Highscore_Lv13
至表DB_Highscore_Lv20
在v1.0版本Ballance的Database.tdb中不存在
下面将叙述这些表的格式,将直接使用Wiki的表格进行描述,Wiki表格的表头即为Virtools Array的表头,第一行为名称,第二行为数据类型。表格中的数据是随便填写的(主要是对列数和行数有一个直观展示,会使得下面见到的表和在Virtools编辑器中见到的表格几乎完全一致),如果有需要叙述的会用斜体字标明。
以上这些表被定义在base.cmo中。
DB_Highscore
DB_Highscore类型的表共有20个,分别代表每一关的高分榜,每一个表都遵循如下格式:
Playername String |
Points Int32 |
---|---|
Mr. Default | 0 |
Mr. Default | 0 |
Mr. Default | 0 |
Mr. Default | 0 |
Mr. Default | 0 |
Mr. Default | 0 |
Mr. Default | 0 |
Mr. Default | 0 |
Mr. Default | 0 |
Mr. Default | 0 |
DB_Levelfreischaltung
DB_Levelfreischaltung记录了前12关的解锁信息。遵循如下格式:
Freigeschaltet? Boolean[4] |
---|
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
DB_Options
DB_Options存储了游戏的一些常用设置。遵循如下格式:
Volume Float |
Synch to Screen? Boolean |
Key Forward Int32 |
Key Backward Int32 |
Key Left Int32 |
Key Right Int32 |
Key Rotate Cam Int32 |
Key Lift Cam Int32 |
Invert Cam Rotation? Boolean |
LastPlayer String |
CloudLayer? Boolean |
---|---|---|---|---|---|---|---|---|---|---|
音量,从0-1取值 | 是否垂直同步 | 前进按键 | 后退按键 | 左行按键 | 右行按键 | 旋转摄像机按键 | 提升摄像机按键 | 是否反转摄像机旋转 | 最近在高分榜姓名处输入的名称 | 是否开启云层 |
对于按键,遵循以下代码(C#):
private static readonly List<string> keys = new List<string>() {"1","2","3","4","5","6","7","8","9","0","-","=","BackSpace","Tab","Q","W","E","R","T","Y","U","I","O","P", "[","]","Ctrl","A","S","D","F","G","H","J","K","L",";","'","`","Shift","\\","Z","X","C","V","B","N","M",",",".","/", "Right Shift","Alt","Space","Num 7","Num 8","Num 9","Num -","Num 4","Num 5","Num 6","Num +","Num 1","Num 2","Num 3","Num 0","Num Del","<","Up","Down","Left","Right"};
按键在此数组中的序号即为需要存储的数据。