Difference between revisions of "Zh:Data types"

From wiki.vg
Jump to navigation Jump to search
m
m
 
Line 1: Line 1:
<noinclude>本文章定义了在[[ZH:Protocol|协议]]中使用的'''数据类型'''。</noinclude>所有在网络上发送的数据(除VarInt和VarLong外)都是[[wikipedia:zh:字节顺序#大端序|大字节序]]的,也就是说,字节是从最大的字节到最小的字节发送。大多数日常遇到的电脑都是小字节序的,所以也许有必要在网络上发送数据前更改字节序。<includeonly>
+
<noinclude>本文章定义了在[[ZH:Protocol|协议]]中使用的'''数据类型'''。</noinclude>所有在网络上发送的数据(除VarInt和VarLong外)都是[[wikipedia:zh:字节顺序#大端序|大字节序]]的,也就是说,字节是从最高有效字节到最低有效字节发送。大多数日常遇到的电脑都是小字节序的,所以也许有必要在网络上发送数据前更改字节序。<includeonly>
 
{{#ifeq: {{PAGEID}}|{{PAGEID:ZH:Protocol}}| {{#ifeq: {{REVISIONID}}|{{REVISIONID:ZH:Protocol}}||{{Warning2|注意:这一信息是来自[[ZH:Data types|数据类型]]一文的'''最新'''版本,也许并不适用于当前协议版本。查阅文章历史来看自这一版本起发生的变化。}}}}}}
 
{{#ifeq: {{PAGEID}}|{{PAGEID:ZH:Protocol}}| {{#ifeq: {{REVISIONID}}|{{REVISIONID:ZH:Protocol}}||{{Warning2|注意:这一信息是来自[[ZH:Data types|数据类型]]一文的'''最新'''版本,也许并不适用于当前协议版本。查阅文章历史来看自这一版本起发生的变化。}}}}}}
 
</includeonly><noinclude>
 
</includeonly><noinclude>

Latest revision as of 08:45, 6 May 2020

本文章定义了在协议中使用的数据类型。所有在网络上发送的数据(除VarInt和VarLong外)都是大字节序的,也就是说,字节是从最高有效字节到最低有效字节发送。大多数日常遇到的电脑都是小字节序的,所以也许有必要在网络上发送数据前更改字节序。

定义

名称 大小(字节) 编码 注释
Boolean 1 false或true True被编码为0x01,false为0x00
Byte 1 -128到127之间的整数 有符号8位整数,补码
Unsigned Byte 1 0和255之间的整数 无符号8位整数
Short 2 -32768和32767之间的整数 有符号16位整数,补码
Unsigned Short 2 0和65535之间的整数 无符号16位整数
Int 4 -2147483648和2147483647之间的整数 有符号32位整数,补码
Long 8 -9223372036854775808和9223372036854775807之间的整数 有符号64位整数,补码
Float 4 单精度32位IEEE 754浮点数
Double 8 双精度64位IEEE 754浮点数
String(n) ≥ 1
≤ (n×4) + 3
Unicode标量序列 以它的大小用字节为单位表示对VarInt为前缀的UTF-8字符串。n字符的最大长度随上下文而变化,最多可以使用n × 4字节来编码n个字符,并同时检查这些限制。最大的n值为32767。+ 3是因为有效长度VarInt的最大大小。
Chat ≥ 1
≤ (32767×4) + 3
Chat 编码为最大长度为32767的字符串。
Identifier ≥ 1
≤ (32767×4) + 3
见下方标识符 编码为最大长度为32767的字符串。
VarInt ≥ 1
≤ 5
-2147483648和2147483647之间的整数 编码补码32位整型的可变长度数据,更多信息参阅它们的部分
VarLong ≥ 1
≤ 10
-9223372036854775808和9223372036854775807之间的整数 编码补码64位整型的可变长度数据,更多信息参阅它们的部分
Entity Metadata 可变 有关实体的杂项信息 实体#实体元数据格式
Slot 可变 在物品栏或容器中的一组物品 槽数据
NBT Tag 可变 取决于上下文 NBT
Position 8 一个整型/方块位置: x(-33554432至33554431)、y(-2048至2047)、z(-33554432至33554431) x为26位整数,后面跟着12位整数的y,以及26位整数的z(都是有符号的,补码)。另见下面的部分
Angle 1 一圈的1/256为步长的旋转角度 这是否是有符号的都无所谓,因为结果角度是相同的。
UUID 16 UUID 编码为无符号128整数(或两个无符号64位整数:高64位和低64位)
Optional X 0或X的大小 类型X的字段,或什么都没有 该字段是否出现必须从上下文得知。
Array of X 数量乘上X的大小 类型X的零或更多的字段 数量必须必须从上下文得知。
X Enum X的大小 给定列表中特定的值 可能的值的列表和每个该如何编码为X都必须从上下文中得知。无论哪一边发送的无效值通常都会导致客户端断开连接并产生一个错误甚至崩溃。
Byte Array 可变 取决于上下文 这通常是一个零或更多字节的序列,它的含义会在别的地方解释,例如数据包描述中。长度必须从上下文中得知。

标识符

标识符是一个以minecraft:thing为形式的带命名空间的位置。如果没有提供命名空间,那么它默认为minecraft(即,thing变为minecraft:thing。自定义内容应该总是在它自己的命名空间中,而不是默认的中。命名空间应该只使用这些字符:01​​234​5​6​78​9abcdefghijklmnopqrstuvwxyz-_,实际的名称可能会包含更多符号。命名约定是lower_case_with_underscores(蛇形命名法)。更多信息

VarInt和VarLong

可变长度格式,就像较小的数会使用较少的字节。于Protocol Buffer Varints非常相似:7个最底位用于编码值而最高位用于指示在之后还有多少用于数字下一部分的字节。最低位的组写在最前面,后面跟着更高位的组;因此,VarInts实际上是小字节序的(然而,组是7位而不是8位的)。

VarInts永远不会多余5字节,VarLongs永远不会多于10字节。

读取并写入VarInts和VarLongs的伪代码:

public static int readVarInt() {
    int numRead = 0;
    int result = 0;
    byte read;
    do {
        read = readByte();
        int value = (read & 0b01111111);
        result |= (value << (7 * numRead));

        numRead++;
        if (numRead > 5) {
            throw new RuntimeException("VarInt is too big");
        }
    } while ((read & 0b10000000) != 0);

    return result;
}
public static long readVarLong() {
    int numRead = 0;
    long result = 0;
    byte read;
    do {
        read = readByte();
        int value = (read & 0b01111111);
        result |= (value << (7 * numRead));

        numRead++;
        if (numRead > 10) {
            throw new RuntimeException("VarLong is too big");
        }
    } while ((read & 0b10000000) != 0);

    return result;
}
public static void writeVarInt(int value) {
    do {
        byte temp = (byte)(value & 0b01111111);
        // Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone
        value >>>= 7;
        if (value != 0) {
            temp |= 0b10000000;
        }
        writeByte(temp);
    } while (value != 0);
}
public static void writeVarLong(long value) {
    do {
        byte temp = (byte)(value & 0b01111111);
        // Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone
        value >>>= 7;
        if (value != 0) {
            temp |= 0b10000000;
        }
        writeByte(temp);
    } while (value != 0);
}

Warning.png 注意Minecraft的VarInts不是使用Protocol Buffers编码的,它们只是相似罢了。如果你尝试将Protocol Buffers Varints用于Minecraft的VarInts,你会在某些情况下得到不正确的结果。主要的区别有:

  • Minecraft的VarInts都是有符号的,但不使用ZigZag编码。Protocol buffers有三种类型Varints:uint32(普通编码、无符号)、sint32(ZigZag编码、无符号)和int32(普通编码、有符号)。 Minecraft的是int32种类。因为Minecraft使用正常的编码而不是ZigZag编码,负值总是会使用字节的最大数字。
  • Minecraft的VarInts永远不会多于5字节,VarLongs永不多于10字节,而Protocol Buffer Varints会总是使用10字节来编码负数,即使它是int32

示例VarInts:

十六进制字节 十进制字节
0 0x00 0
1 0x01 1
2 0x02 2
127 0x7f 127
128 0x80 0x01 128 1
255 0xff 0x01 255 1
2147483647 0xff 0xff 0xff 0xff 0x07 255 255 255 255 7
-1 0xff 0xff 0xff 0xff 0x0f 255 255 255 255 15
-2147483648 0x80 0x80 0x80 0x80 0x08 128 128 128 128 8

示例VarLongs:

十六进制字节 十进制字节
0 0x00 0
1 0x01 1
2 0x02 2
127 0x7f 127
128 0x80 0x01 128 1
255 0xff 0x01 255 1
2147483647 0xff 0xff 0xff 0xff 0x07 255 255 255 255 7
9223372036854775807 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x7f 255 255 255 255 255 255 255 255 127
-1 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x01 255 255 255 255 255 255 255 255 255 1
-2147483648 0x80 0x80 0x80 0x80 0xf8 0xff 0xff 0xff 0xff 0x01 128 128 128 128 248 255 255 255 255 1
-9223372036854775808 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x01 128 128 128 128 128 128 128 128 128 1

位置

分隔位三个部分的64位值

  • x:26个最高位
  • z:26个中间位
  • y:12个最低位

如下编码:

((x & 0x3FFFFFF) << 38) | ((z & 0x3FFFFFF) << 12) | (y & 0xFFF)

并如下解码:

val = read_unsigned_long();
x = val >> 38;
y = val & 0xFFF;
z = (val << 26 >> 38);

注意:位移的细节由语言决定,上述内容可能在Java中可以工作但可能不会不经修改就能在其他语言中工作。实际上,你通常会接受到正数,即使实际的坐标是负的。这可以通过加入如下内容修复:

if x >= 2^25 { x -= 2^26 }
if y >= 2^11 { y -= 2^12 }
if z >= 2^25 { z -= 2^26 }

定点数

一些字段被存储为定点数,其中一定数量的为用于表示有符号整数部分(小数点左侧的数字),其余表示小数部分(小数点右侧)。浮点数(float和double),相反,将数字本身(尾数)存储在内存块中,而小数点(指数)的位置存储在其一边。

本质上,虽然定点数有着比浮点数更小的范围,但是对于较大值来说它们的小数精度要更胜一筹。这使得它们用于表示Minecraft实体的全局坐标非常理想,因为比起将它们精确地定位在一个方块(或米)中,准确地保存它的整数部分要重要得多。

坐标经常被表示为32位整数,其中5个最低位用于小数部分,其余存储整数部分。

Java缺乏对分数整数的直接支持,但是你可以使用整数来表示它们。要将double转换成这种整数表示方法,使用以下公式:

 abs_int = (int) (double * 32.0D);

以及反过来:

 double = (double) (abs_int / 32.0D);

粒子

字段名称 字段类型 含义
ID VarInt 粒子类型的ID,见下。
Data 可变 根据粒子类型可变,见下。
粒子名称 粒子ID 数据
minecraft:ambient_entity_effect 0
minecraft:angry_villager 1
minecraft:barrier 2
minecraft:block 3
字段名称 字段类型 含义
BlockState VarInt 方块状态的ID。
minecraft:bubble 4
minecraft:cloud 5
minecraft:crit 6
minecraft:damage_indicator 7
minecraft:dragon_breath 8
minecraft:dripping_lava 9
minecraft:falling_lava 10
minecraft:landing_lava 11
minecraft:dripping_water 12
minecraft:falling_water 13
minecraft:dust 14
字段名称 字段类型 含义
Red Float 红色值,0-1
Green Float 绿色值,0-1
Blue Float 蓝色值,0-1
Scale Float 缩放,会夹在0.01和4之间。
minecraft:effect 15
minecraft:elder_guardian 16
minecraft:enchanted_hit 17
minecraft:enchant 18
minecraft:end_rod 19
minecraft:entity_effect 20
minecraft:explosion_emitter 21
minecraft:explosion 22
minecraft:falling_dust 23
字段名称 字段类型 含义
BlockState VarInt 方块状态的ID。
minecraft:firework 24
minecraft:fishing 25
minecraft:flame 26
minecraft:flash 27
minecraft:happy_villager 28
minecraft:composter 29
minecraft:heart 30
minecraft:instant_effect 31
minecraft:item 32
字段名称 字段类型 含义
Item Slot 将要使用的物品。
minecraft:item_slime 33
minecraft:item_snowball 34
minecraft:large_smoke 35
minecraft:lava 36
minecraft:mycelium 37
minecraft:note 38
minecraft:poof 39
minecraft:portal 40
minecraft:rain 41
minecraft:smoke 42
minecraft:sneeze 43
minecraft:spit 44
minecraft:squid_ink 45
minecraft:sweep_attack 46
minecraft:totem_of_undying 47
minecraft:underwater 48
minecraft:splash 49
minecraft:witch 50
minecraft:bubble_pop 51
minecraft:current_down 52
minecraft:bubble_column_up 53
minecraft:nautilus 54
minecraft:dolphin 55
minecraft:campfire_cosy_smoke 56
minecraft:campfire_signal_smoke 57