前端level.dat编辑器0&1
本帖最后由 类下托泣匹 于 2026-7-1 14:33 编辑建议在电脑端阅读https://klpbbs.com/thread-171663-1-1.html?mobile=no
##前言
由于个人爱好,本教程使用 ClojureScript 编写。但请放心——**文中所有二进制操作调用的都是标准 JavaScript API**:`ArrayBuffer`、`DataView`、`Uint8Array`、`TextEncoder`/`TextDecoder`等。ClojureScript 的语法差异很小,看到 `js/DataView.` 就是 `new DataView()`,`(.getInt32 dv 0 true)` 就是 `dv.getInt32(0, true)`,点号在前只是调用方式的写法不同。如果你熟悉 JS 的二进制操作,阅读本文自然不会有障碍。
---
首先先在页面里创建一个文件选择框
`[:input {:type "file" :id "level"}]`
然后把文件存到变量level里面去
`(def level (js/document.getElementById "level"));;def是绑定变量`
##1,操作文件初步和读取头部
在js中操作二进制,只有三个对象
ArrayBuffer:一块原始内存,你**不能直接读里面的数**
DataView:用来从 `ArrayBuffer` 里按类型读数(Int8/Int16/Int32/Float)
Uint8Array:把 `ArrayBuffer` 当成**字节数组**来用,可以像数组一样取下标。
选了文件后,浏览器给的是 File 对象。用 FileReader 转成 ArrayBuffer:
`(def reader (js/FileReader.))`
(js是`const reader = new FileReader();`)
读取时不会保存到变量,所以我们需要设置:
```clojure
(set! (.-onload reader)
(fn
;; event.target.result 就是 ArrayBuffer
(def file-array (.. event -target -result))
(println "读取完成,大小:" (.-byteLength file-array)))
```
**js里面是**
```javascript
reader.onload = (evt) => {
//赋值
};
```
然后用readAsArrayBuffer方法读取:`(.readAsArrayBuffer reader (-> level .-files (aget 0)))`
---
我们可以包成 Uint8Array来查看这个二进制文件
`(def file-bytes (js/Uint8Array. file-array))`
`(println (vec file-bytes))`
Little-Endian 读取规则:低位在前。
= 85 + 10×256 + 0×65536 + 0×16777216 = 2645。
在处理时用Uint8Array需要手动写代码计算不怎么方便。
所以我们用dataview来读取头部。
```clojure
(defn parse-header
(let
{:version (.getInt32 dv 0 true);;等价于js里的dv.getInt32(…)
:length(.getInt32 dv 4 true)}))
```
我们用getInt32读取32位整数,也就是,在js里的用法是`dataview.getInt32(byteOffset [, littleEndian])`。基岩版使用了littleEndian,故使用时要将littleEndian设为true。
---
等等,上面那是什么意思?接下来我们来剖析level.dat文件本身。
基岩版 level.dat 只有两层:
整个文件 = 头部(8字节) + 身体(N字节)
```clojure
[10 0 0 0 ;; offset 0: 版本号 (Little-Endian Int32) → 10
85 10 0 0 ;; offset 4: 身体长度 (Little-Endian Int32) → 2645
10 0 0 ...] ;; offset 8: 其他都是NBT 数据
```
NBT 标签的通用结构
每个 NBT 标签都是三段式:
示例:一个 Byte 标签 "Difficulty" = 1
```clojure
[1 ;; Type = 1 (Byte)
10 0 ;; NameLength = 10 (Little-Endian Int16)
68 105 102 102 105;; "Diffi"
99 117 108 116 121 ;; "culty"
1] ;; Payload = 1
```
注意⚠️level.dat未被zlib压缩。
下一篇教程我们来读取Body部分的nbt。
页: [1]