地图存储格式

来自Minecraft Wiki
跳转到导航 跳转到搜索
  本条目介绍的是地图物品相关的地图数据存储格式。关于存档的存储和文件格式,请见“Java版存档格式”和“基岩版存档格式”。
本文章所述内容仅适用于Java版

地图计数存储文件地图数据存储文件是存档中存储地图数据的文件。

地图计数存储格式[编辑 | 编辑源代码]

游戏在使用地图时,会给每张独立的地图分配一个地图编号(Map ID)。游戏使用地图计数存储文件用于存储下一个可用的地图编号。

地图计数存储文件位于<存档根目录>/data/idcounts.dat,使用GZip压缩的NBT文件格式保存,其内部有下列NBT结构:

  • NBT复合标签/JSON对象 根标签
    • NBT复合标签/JSON对象*
      *
      data
      :地图计数数据。
      • 整型*
        *
        map
        :一个可用的地图编号。
    • 整型*DataVersion:保存此地图计数存储文件的游戏的数据版本。如果此项不存在则游戏认为此项是1343(Java版1.12.2)。

地图数据存储格式[编辑 | 编辑源代码]

游戏不会将地图数据存入地图物品中,而是在存档内单独存储地图数据。

地图数据存储文件位于<存档根目录>/data/map_<地图编号>.dat,使用GZip压缩的NBT文件格式保存,其内部有下列NBT结构:

  • NBT复合标签/JSON对象 根标签
    • NBT复合标签/JSON对象*
      *
      data
      :地图数据。
      • NBT列表/JSON数组*
        *
        banners
        旗帜标记数据。
        • NBT复合标签/JSON对象:一个旗帜标记。
          • 字符串color:(旗帜的颜色,见颜色。如果不存在则为white(白色)。
          • 字符串NBT复合标签/JSON对象NBT列表/JSON数组name:(文本组件)旗帜标记的名称,使用对应旗帜的字符串NBT复合标签/JSON对象NBT列表/JSON数组CustomName名称。
          • 整型数组*
            *
            pos
            :旗帜在世界中的位置。
      • 字节型数组*
        *
        colors
        :地图内部的渲染颜色阵列,总长度16384。如果此数组长度不是16384,游戏将不读取此数组,而是使用全部为0的数组替换。格式见下文。
      • 字符串*
        *
        dimension
        :(命名空间ID)地图所记录的维度。
      • NBT列表/JSON数组*
        *
        frames
        物品展示框显示数据。
        • NBT复合标签/JSON对象:一个物品展示框的数据。
          • 整型*
            *
            entity_id
            :此物品展示框的实体ID。
          • 整型数组*
            *
            pos
            :物品展示框在世界中的位置。
          • 整型*
            *
            rotation
            :物品展示框的旋转角度,以角度计。此值对应水平平面内的旋转,如果物品展示框是向上或向下,则为-90。
      • 布尔型*
        *
        locked
        :地图是否已被锁定。锁定后的地图无法更新内部的显示数据,也不会更新旗帜标记。
      • 字节型*
        *
        scale
        :(0≤值≤4)地图的缩放等级。
      • 布尔型*
        *
        trackingPosition
        :地图是否追踪并显示在地图显示范围内的手持此地图的玩家和物品展示框的位置。当此值不存在时游戏默认为true
      • 布尔型*
        *
        unlimitedTracking
        :地图是否显示距离地图显示范围切比雪夫距离大于320格的正在手持此地图的玩家,这些玩家会以更小的点渲染(地图图标player_off_limits)。
      • 整型*
        *
        xCenter
        :地图中心的世界X坐标。
      • 整型*
        *
        zCenter
        :地图中心的世界Z坐标。
    • 整型*DataVersion:保存此地图数据存储文件的游戏的数据版本。如果此项不存在则游戏认为此项是1343(Java版1.12.2)。

字节型数组colors记录了地图上每一个点的颜色。地图边长为256,内部有16384个点。假设地图内像素点P,按照地图左上角为原点,其横坐标为x,纵坐标为z,那么这个点在数组内的下标是x+128z。每个字节都表示一个颜色,这个颜色并不是真正的RGB或灰度值,而是地图色C

地图色C按照二进制位分为两个部分:高6位代表地图基色B,低2位代表颜色修饰M。下列代码演示了如何计算地图色:

public static byte getMapColor(int baseColor, int modifier) {
	return (byte) (baseColor << 2 | modifier & 3);
}

public static int getBaseColor(byte mapColor) {
	return (((int) mapColor) & 0xFF) >> 2;
}

public static int getModifier(byte mapColor) {
	return mapColor & 3;
}

地图基色B是由游戏硬编码的颜色,是一个枚举,共有62种地图基色。颜色修饰M有4种,对地图基色提供的RGB颜色进行进一步修改。下表为颜色修饰M的取值和对地图基色的影响:

颜色修饰M 枚举名称 修饰效果
0 LOW 对地图基色RGB通道分别乘以180255,获得比较暗的颜色
1 NORMAL 对地图基色RGB通道分别乘以220255,获得亮度适中的颜色
2 HIGH 不对地图基色做处理,获得较亮的颜色
3 LOWEST 对地图基色RGB通道分别乘以135255,获得更暗的颜色

下表为目前游戏中使用的地图基色,以及它们被颜色修饰修饰后的颜色:

所有地图色

存储行为[编辑 | 编辑源代码]

如果存档内没有创建过任何一张地图,那么地图计数存储文件和地图数据存储文件都不存在。当有玩家创建第一张地图时,这两个文件才会被创建和写入。

如果地图计数存储文件内的地图编号是一个已经存在的地图编号,当游戏创建新的地图时,新的地图会覆盖使用同地图编号的地图。

地图更新行为[编辑 | 编辑源代码]

地图并不是时刻都在更新,也不是所有数据都会同步到地图数据内,部分数据由地图物品保存而不是地图数据保存。

在满足下列条件下,地图内的渲染颜色阵列数据会被更新:

  • 地图未被锁定。(布尔型lockedfalse
  • 玩家由主手或副手拿着对应地图编号的地图。
  • 地图所记录维度与玩家所在维度一致。

更新地图的范围为玩家为中心、水平半径128格的世界范围。如果维度类型布尔型has_ceilingtrue,即维度具有天花板(例如下界),那么距离减半,变为64格。如果更新范围内的某个区块未被加载,则这个区块内的地图数据不被更新。

地图颜色按照下列算法计算:

  1. 定义缩放范围r=2s,其中s字节型scale的值。
  2. 对于每个地图内的像素点,定义平均高度h¯,计算地图基色B和平均流体深度d¯
    • 如果维度有天花板,定义平均高度h¯固定为100,平均流体深度d¯固定为0。根据转换后的世界坐标,填充泥土的地图基色(DIRT)或石头的地图基色(STONE):
      • 定义世界坐标为(x,?,z),计算31287121(x+231871z)2+11(x+231871z),转换为二进制后取第21位。如果是0则为泥土,1为石头。
    • 如果维度没有天花板,则取像素点转换到世界坐标后r×r大小的范围:
      1. 计算这个范围内高度图WORLD_SURFACE(最高非空气方块高度)的平均高度作为h¯
      2. 对于范围内的每个水平坐标:
        1. 如果此水平坐标只有空气,则认为控制地图基色的方块是基岩,不进行后续流程。
        2. 从最高非空气方块开始遍历,直到找到一个地图基色不为NONE的方块。如果此水平坐标没有任何地图基色不为NONE的方块,则取最低的方块。
        3. 如果找到的方块含有流体(熔岩或任意含水方块),继续向下查找直到找到第一个不含流体的方块,此方块与之前找到的方块的距离即为流体深度d
        4. 如果找到的方块不含有流体,那么取这个方块作为控制地图基色的方块;如果含有流体,计算方块上表面是否完整,如果完整则仍然取这个方块作为控制地图基色的方块,否则认为流体方块是控制地图基色的方块。计算控制地图基色的方块的地图基色,并记录。
      3. 计算范围内所有流体深度的平均值作为平均流体深度d¯,取出现次数最多的地图基色作为此像素点的地图基色B
  3. 计算颜色修饰M
    • 如果像素点的地图基色B是WATER:
      • 设像素点位置为(u,v),计算m=0.1d¯+0.2(u+vmod2)
        • 如果m大于0.9,则颜色修饰为LOW;如果m小于0.5,则颜色修饰为HIGH;其他情况下为NORMAL。
        • 这代表了平均流体深度小于3格时颜色修饰为HIGH,不小于3格且小于5格时为HIGH和NORMAL渐变,不小于5格且小于7格时为NORMAL,不小于7格且小于9格时为NORMAL和LOW渐变,不小于9格时为LOW。
    • 如果像素点地图基色B不是WATER:
      • 获取上方像素点的平均高度h¯(如果没有上方像素点则假设上方有一个像素点并进行上一步操作计算数据),设像素点位置为(u,v),计算m=4(h¯h¯)r+4+0.4((u+vmod2)0.5)
        • 如果m大于0.6,则颜色修饰为HIGH;如果m小于-0.6,则颜色修饰为LOW;其他情况下为NORMAL。
        • 如果缩放等级字节型scale为0,此公式退化为:如果北方方块高于此方块,则颜色修饰为LOW;如果北方方块与此方块同等高度,则颜色修饰为NORMAL;如果北方方块低于此方块,则颜色修饰为HIGH。
  4. 按照计算得出的地图基色B、颜色修饰M,计算地图色C写入地图渲染颜色阵列数据。
使用了带有起伏的方块结构制作一幅像素画

当所有方块都处于一个高度时,使用缩放等级为0的地图只会使用62种颜色;但如果方块按照南北方向起伏,则可以使地图拥有186种颜色。这种方式可以扩展地图的颜色,以丰富地图上的色彩呈现。

对于探险家地图,地图颜色在物品生成时就被决定,只有在玩家后续更新后才会变成真正和世界同步的地图颜色。探险家地图的地图颜色计算如下:

  1. 获取所有像素点对应世界坐标的生物群系,标记带有#water_on_map_outlines标签(默认为河流类、海洋类、沼泽类生物群系)的生物群系为水系像素点,其他群系则为陆地像素点。
  2. 遍历所有像素点:
    • 获取周围8个像素点是水系像素点的数量w
    • 如果此像素点不是水系像素点,且w为0,则地图基色为NONE,颜色修饰为LOWEST。
    • 如果此像素点不是水系像素点,但w大于0,则地图基色为BROWN。当w大于3时颜色修饰为NORMAL,否则为LOWEST。
    • 如果此像素点是水系像素点,则地图基色为COLOR_ORANGE,设像素点坐标为(u,v)
      • 如果w为8,且v为偶数,计算m=u+7sinv,对m按位右移3位后对5取余。如果m本身为负数,则颜色修饰为LOWEST;如果结果为0或4,则为LOW;如果为1和3,则为NORMAL;如果为2,则为HIGH。
      • 如果w为8,且v为奇数,则地图基色为NONE,颜色修饰为LOWEST。
      • 如果w为6或7,则颜色修饰为NORMAL。
      • 如果w为2、3、4、5,则颜色修饰为LOW。
      • 如果w为0或1,则颜色修饰为LOWEST。

地图的旗帜数据和物品展示框数据由地图数据保存。当玩家使用地图物品加入或删除旗帜标记时,数据会立刻同步到地图数据内。当地图物品放入物品展示框或被移出物品展示框时,地图数据也会立刻被更新。但是除了旗帜标记和物品展示框标记外,其他标记数据都由物品数据保存,例如探险家地图上的标记。换言之,地图的渲染颜色阵列、旗帜标记、物品展示框标记、缩放、锁定是全世界同步的,只要保证地图编号一致,数据就会立刻被全局同步;但是,额外的标记不会被全局同步,因为它们在地图物品数据中而不是全局的地图数据内。

历史[编辑 | 编辑源代码]

Java版Beta
?Notch尝试加入地图,但此时没有使用NBT格式。[1]
1.6Test Build 3加入了地图
此时地图编号使用短整数。[2]
Java版
1.8.1pre1加入了下界颜色NETHER(35),基色数量提升到36。
颜色修饰3的乘数从220改为135。
1.1217w17a基色数量提升到52。
1.1317w47a地图编号不再使用短整数而改用了整数,因为它们不再基于物品的损伤值。
18w19a加入了整型DataVersion以记录地图数据存储文件的数据版本。
1.1419w02a加入了地图锁定。
1.16pre6添加基色CRIMSON_NYLIUM(52)、CRIMSON_STEM(53)、CRIMSON_HYPHAE(54)、WARPED_NYLIUM(55)、WARPED_STEM(56)、WARPED_HYPHAE(57)和WARPED_WART_BLOCK(58),基色数量提升到59。
1.1721w15a添加基色DEEPSLATE(59)和RAW_IRON(60),基色数量提升到了61。
21w16a添加基色GLOW_LICHEN(61),基色数量提升到了62。

参考[编辑 | 编辑源代码]

导航[编辑 | 编辑源代码]