服务器和客户端之间的Minecraft协议是否基于任何标准?

时间:2017-07-22 10:41:31

标签: scala protocol-buffers minecraft

TL; DR

我正在尝试使用Scala编写的客户端使用TCP上的Akka I / O与Minecraft服务器通信,并想知道Minecraft是否在其网络通信中使用官方的标准化协议?

Minecraft's own documentation涵盖了每个数据包的内容,但无法解释数据包本身的编码方式,甚至无法解释数据包的形成方式。

一个小故事

作为我正在研究的个人项目的一部分,用Scala编写,我需要创建一个能够模拟Minecraft客户端并对Minecraft服务器执行操作的界面。经过数周的研究,我遇到了很多几乎我​​正在寻找的Java库,但没有一个非常适合我的确切需求;长话短说,我做了经典,“哦,好吧,为什么不自己写,享受学习曲线”......

问题

The Minecraft protocol documentation在某些方面是彻底的,但在其他方面缺乏,在整个过程中做出了许多假设,并且许多关键信息缺失甚至不正确;在我的案例中,详细的网络规范是最值得注意的。

与Minecraft服务器交谈的一次尝试让我使用了谷歌的协议缓冲区,使用ScalaPB将它们编译成可用的案例类,但谷歌自己的文档和Minecraft之间的数据类型很难解决。

message Handshake {
    <type?> protocolVersion = 1;
    <type?> host = 2;
    <type?> port = 3;
    <type?> nextState = 4;
}

host是一个字符串,因此这是一个简单的胜利,但protocolVersionnextState都是变量整数,当我将它们与有效数据包进行比较时,它们没有按预期编码由具有相同内容的另一个客户端生成(我一直使用第三方库来比较编码数据包的十六进制输出)。

我的hacky解决方案

在努力实现我的目标的过程中,我只是编写了类似下面的方法(这也是第一次迭代,所以要善良!)为Minecraft的文档中声明的每种类型生成所需的编码在Scala本身不支持,虽然这有效,但它只是闻起来我错过了其他人可能知道的明显的东西。

def toVarint(x: Int): Array[Byte] = {
  var number = x
  var output = ArrayBuffer[Int]()

  while (number >= Math.pow(2, 31)) {
    output += number & 0xFF | 0x80
    number /= 128
  }

  while ((number & ~0x7F) > 0) {
    output += number  0xFF | 0x80
    number >>>= 7
  }

  output += number | 0

  output.map(_.toByte).toArray
}

1 个答案:

答案 0 :(得分:0)

这是旧的,但我还是会回答! The wiki you referenced(至少现在)有一个关于数据包格式的部分(压缩之前和之后),以及包括如何处理其varint和varlong类型的示例代码在内的说明!

总而言之,每个数据包的长度都以varint为前缀(在两种压缩模式下),因此您只需要从流中读取varint,分配那么多空间并从流中将那么多字节读取到缓冲区。 / p>

Minecraft varint的每个字节都有一个“要跟随的另一个字节?”标志位,后跟7位实际数据。这7位只是标准int的位(因此,在接收时,您实际上只是忽略了这些标志位,并将其余标志位写入标准int类型)