地图的一个像素就是一个字节,其中两位是亮度
61 种基础颜色 × 4 种明暗 = 244 种颜色,来自一个 16,384 字节的数组。四种明暗里只有一种是颜色的满值,另外三种分别被压暗到 86%、71% 和 53%,该数组大小固定是 128×128,无论地图缩放等级是多少都不会变。
Minecraft 中每一张已填充的地图在磁盘上的大小都相同:一个 colors 字节数组,恰好 16,384 项,也就是 128 × 128。无论是覆盖 128 格的尺寸 0 地图,还是覆盖 2,048 格的尺寸 4 地图,都是如此——像素数量从不改变。关于地图画的其他一切,都源自这一事实。
字节一分为二
这 16,384 个字节中的每一个都不是一种颜色,而是基础颜色与明暗打包在一起:
baseColorId = colorId >> 2 // 0–63
shadeIndex = colorId & 3 // 0–3
也就是说,低两位是亮度,其余位表示你看到的是哪种方块。定义了 61 种基础颜色(id 0 是透明/未探索的槽位),所以真实地图中出现的最大字节值是 61 × 4 + 3 = 247。
61 × 4 = 244 种不同的颜色,这就是地图画可用的全部调色板。不是 61 种,也不是 256 种。
只有一种明暗是颜色的满值
四个乘数并非均匀分布,而且其中一个是 1.0:
| 明暗索引 | 乘数 | 百分比 |
|---|---|---|
| 0 | 180 / 255 | 70.6% |
| 1 | 220 / 255 | 86.3% |
| 2 | 255 / 255 | 100% |
| 3 | 135 / 255 | 52.9% |
明暗 2 就是地图颜色自身的 RGB,未经缩放——它是每种颜色 id 的固定值,并非从方块纹理中采样得来。另外三种是它的加深版本,而最暗的明暗 3 亮度只略高于一半。
这就是为什么阶梯式地图画看起来与平面地图画差别如此之大。平面建筑只会产生普通明暗(86%),所以平面地图只有 61 种颜色可用。改变高度则能解锁每种方块更亮和更暗的明暗,让你拥有 183 种。调色板并不会变得更宽——你不会得到新的色相——而是明度层次加深到三倍,而这正是抖动(dithering)所需要的。第四种明暗(53%)根本不会由方块产生:它存在于字节格式中,只有被编辑过的地图文件才会用到它。
还要注意,明暗的顺序并非单调递增:索引 3 是最暗的,而不是最亮的。按索引排序并期待一个渐变,你得到的是 71%、86%、100%、53%。
尺寸放大的是面积,绝不是分辨率
scale 字段的取值范围是 0–4,其覆盖的地面边长为 128 × 2^scale 格:
| 尺寸 | 覆盖格数 | 一个地图像素等于 |
|---|---|---|
| 0 | 128 × 128 | 1 格 |
| 1 | 256 × 256 | 2 × 2 格 |
| 2 | 512 × 512 | 4 × 4 格 |
| 3 | 1,024 × 1,024 | 8 × 8 格 |
| 4 | 2,048 × 2,048 | 16 × 16 格——恰好一个区块 |
一张尺寸 4 的地图用同样的 16,384 字节覆盖了尺寸 0 地图 256 倍的面积。这正是地图画必须在尺寸 0 下建造的全部原因:在任何其他缩放级别下,一个像素都是若干方块的平均值,你精心摆放的图像会被重采样掉。
尺寸 4 那一行还因另一个原因值得记住——一个像素恰好等于一个区块,这让完全放大的地图成为一张可用的区块网格。
这对损坏的文件意味着什么
如果某个地图文件(世界文件夹中的 data/minecraft/maps/<id>.dat)里的 colors 数组不是 16,384 字节,那它并不是一张缺少像素的地图:游戏仍会加载这张地图,但会丢弃像素并显示为空白。不存在长度不完整的形态。该数组永远是完整大小,未探索区域存储为颜色 id 0,而不是被省略。