【问题标题】:Cannot read packet from Minecraft correctly in Golang在 Golang 中无法从 Minecraft 正确读取数据包
【发布时间】: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,所以我认为你的原件是错误的。

标签: go tcp minecraft


【解决方案1】:

wiki 中的代码是错误的。

((value &amp; 0x80) != 0x80) 应该是((currentByte &amp; 0x80) != 0x80)

编码工作如下:数字(或其他)被分成 7 位块。然后在每个字节中,最高有效位 (MSB) 表示后面还有更多字节,其余的对数字进行编码。

value |= (currentByte &amp; 0x7F) &lt;&lt; (length * 7); 行基本上使 MSB 为空(0x7F 是用于获取最后七位的掩码,即字节中除 MSB 之外的所有位)。 ((value &amp; 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-05
    • 2018-12-25
    相关资源
    最近更新 更多