最近闲来无事和朋友闲谈,突然聊到了Minecraft和其中一个文件level.dat。尽管我用软件修改过这个文件,但是如何解析这个文件我并不知道。于是心血来潮尝试了一下。
思路:
- 反编译Minecraft查找相关函数。
- Hex查看,并分析方法。
准备:
- 学习一下NBT相关知识。
- 网上查询可知
level.dat
文件是个压缩文件格式是gzip。故解压得到同名文件level
。level
是一个NBT标签格式的文件,至此问题就变成了如何从零解析nbt格式的文件。 - 用notepad++打开,可以看到,一些字符串和乱码。推测是加密后的数据。
实践1:
打开jd-gui, 把
XXX.jar
丢进去,由于我并没有游戏本体,所以就用服务端代替了。搜索定位到WorldLoader.class
从这段代码可以看出来,它是如何读取dat文件的。这两个箭头分别是解压和读取。
3.之后由于不太了解Java所以并没有找到相关解密代码,所以放弃了这条路,换了另一条路。
实践2:
网上找一个NbtEditor。读取了一下
level.dat
。从图中我们得知,这个文件的结构,最上面是一个空名的TAG_Compound,下面是名为Data的TAG_Compound,然后才是其他的数据。用Sublime Text 打开
level
并用hex模式查看。通过查询资料可知,所有的标签都有一个独立的ID和名称。标签的第一个字节为标签类型(ID),其后两字节为存储名称的长度,之后以UTF-8格式的字符串的方式存储标签。如上图所述,
0a 00 00
第一个字节0a
是代表标签ID,0a
转换成10进制就是10。他所代表的就是TAG_Compound。
后面的00 00
是标签名称的长度,由NBTEditor可知第一个标签并没有名称,所以是零。知道了规矩,我们就可以尝试解析了,我们先用地图种子练练手。
我们可以看到04 00 0a
,其中04
是标签类型对应的是TAG_Long 8 字节 / 64 位;00 0a
是标签名称长度,0a
是十进制中的10,RandomSeed 刚好就是十位。于是我们往RandomSeed后面推8位
74 2a17 004f 4271 c6
这就是种子的值了。于是我们把它转换从10进制就是8370528147518681542
可以看到与之前的结果相同。
至此,我们已经大概了解了如何从头读取level.dat
文件,但是我有些不解,为啥当时Notch不用Json或XML呢?非要自己造个轮子。