打开主菜单

Ballance Wiki β

Database.tdb/zh

Yyc12345讨论 | 贡献2020年2月7日 (五) 12:56的版本
AmboxProfessor.jpeg 专业性词条
此词条含有较多的专业术语,请您确认您是否具有相关的知识储备。如果有任何理解上的困难,可以翻阅相关资料进行理解或咨询相关人士。

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类型存储均是大端序存储模式,Float使用IEEE-754标准进行存储

加密解开

数据库是具有一定加密的,需要通过特定方法解开加密,才能得到可以被阅读的数据,加密的方法为解密的逆向。

交换比特

首先,解密是以字节为单位进行的。每个字节有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 区块大小,即从ColumnsCells的长度
Columns Int32 该表共有多少列
Rows Int32 该表共有多少行
Separator - 为定值:0xFF, 0xFF, 0xFF, 0xFF,疑似充当分隔符
Header - 表头列表存储
Cells - 单元格列表存储

表头列表

表头列表是由左侧表头向右侧表头逐个写入,且每个表头写入规则如下表:

助记符 数据类型 注释
HeaderName String 表头名称
FieldType Int32 表明表头存储的数据类型(表头对应列的数据类型):
  • 1:Int32
  • 2:Float
  • 3:String
  • 4[2]:Object(解析时不会用到)
  • 5[2]:Parameter(解析时不会用到)

单元格列表

单元格从左上角开始存储,与大多数人的通常认知不同,单元格遵循先自增行数,待一列存储完毕,切到下一列从上至下逐行存储的模式,即先行后列。每个数据存储的时候根据其对应类型首尾相接直接写入即可。

被存储的表

下面将叙述这些表的格式,将直接使用Wiki的表格进行描述,Wiki表格的表头即为Virtools Array的表头,第一行为名称,第二行为数据类型。以下所列举的各表的数据均为随意填写,并非特指必须填写为该数字(主要是对列数和行数有一个直观展示,会使得下面见到的表在形状上和在Virtools编辑器中见到的表格几乎完全一致)。如果有需要叙述的会用斜体字标明。

通过上面的了解,您应该了解,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中不存在

以上这些表被定义在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[3]
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"};

按键在此数组中的序号即为需要存储的数据。

注释

  1. 此数据类型指的是数据如何被存储在文件中,与上文表头数据类型无关。
  2. 2.0 2.1 未验证,由Virtools内部的布置猜测。
  3. 这里有一个隐式类型转换,Int32的1相当于True,0相当于False,后文不再标记。