在 Golang 中无法从 Minecraft 正确读取数据包
Posted
技术标签:
【中文标题】在 Golang 中无法从 Minecraft 正确读取数据包【英文标题】:Cannot read packet from Minecraft correctly in Golang 【发布时间】:2022-01-15 14:42:45 【问题描述】:我是 Golang 的初学者。最近我在从 Minecraft 客户端读取数据包时遇到问题。
我的程序就是这样从连接中读取数据包的。
player := &Player
conn: conn,
state: HANDSHAKING,
io: &ConnReadWrite
rdr: bufio.NewReader(conn),
wtr: bufio.NewWriter(conn),
,
inaddr: InAddr
"",
0,
,
keepalive: 0,
compression: false
func (player *Player) ReadVarInt() (i int, err error)
val, _ := binary.ReadUvarint(player.io)
return int(val), nil
刚建立连接时可以正常工作,但后来无法正确读取数据包ID。
工作了好几天,想重写复制wiki.vg的解决方案,但是好像不行
PS:我的副本和原件
val, length := 0, 0
for
current, err := player.io.ReadByte()
if err != nil
return 0, err
val |= int((current & 0x7F) << (length * 7))
length += 1
if length > 5
return 0, errors.New(fmt.Sprintf("%s: VarInt is too big", player.name))
if val&0x80 != 0x80
break
return int(val), nil
int value = 0;
int length = 0;
byte currentByte;
while (true)
currentByte = readByte();
value |= (currentByte & 0x7F) << (length * 7);
length += 1;
if (length > 5)
throw new RuntimeException("VarInt is too big");
if ((value & 0x80) != 0x80)
break;
return value;
【问题讨论】:
我对原作有点困惑。首先,值为 (currentByte&0x7F),表示最高有效位为空。然后 (value & 0x80) 尝试读取所述最高有效位,该位不再存在。在我看来,它应该是 currentByte & 0x80,而不是 value & 0x80。 至少here 代码检查 currentByte 是否设置了最高有效位;还有here,所以我认为你的原件是错误的。 【参考方案1】:wiki 中的代码是错误的。
((value & 0x80) != 0x80)
应该是((currentByte & 0x80) != 0x80)
编码工作如下:数字(或其他)被分成 7 位块。然后在每个字节中,最高有效位 (MSB) 表示后面还有更多字节,其余的对数字进行编码。
value |= (currentByte & 0x7F) << (length * 7);
行基本上使 MSB 为空(0x7F 是用于获取最后七位的掩码,即字节中除 MSB 之外的所有位)。 ((value & 0x80) != 0x80)
正在测试 MSB 是否为 1,不能为 1,因为它只是被清零(0x80 是除 MSB 之外的每一位都清零的掩码)。所以它正在测试错误的值。
这是正确的示例 (source)
def _ReadVarintHelper(self):
"""Helper for the various varint-reading methods above.
Reads an unsigned, varint-encoded integer from the stream and
returns this integer.
Does no bounds checking except to ensure that we read at most as many bytes
as could possibly be present in a varint-encoded 64-bit number.
"""
result = 0
shift = 0
while 1:
if shift >= 64:
raise message.DecodeError('Too many bytes when decoding varint.')
try:
b = ord(self._buffer[self._pos])
except IndexError:
raise message.DecodeError('Truncated varint.')
self._pos += 1
result |= ((b & 0x7f) << shift)
shift += 7
if not (b & 0x80):
return result
【讨论】:
以上是关于在 Golang 中无法从 Minecraft 正确读取数据包的主要内容,如果未能解决你的问题,请参考以下文章
Minecraft 1.64 的 Bukkit 服务器 怎么安装Mod ? 我在客户端里安装了,
如何从 NodeJS 中的用户名中获取 Minecraft 玩家的 UUID?