我正在尝试使用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
是一个字符串,因此这是一个简单的胜利,但protocolVersion
和nextState
都是变量整数,当我将它们与有效数据包进行比较时,它们没有按预期编码由具有相同内容的另一个客户端生成(我一直使用第三方库来比较编码数据包的十六进制输出)。
在努力实现我的目标的过程中,我只是编写了类似下面的方法(这也是第一次迭代,所以要善良!)为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
}
答案 0 :(得分:0)
这是旧的,但我还是会回答! The wiki you referenced(至少现在)有一个关于数据包格式的部分(压缩之前和之后),以及包括如何处理其varint和varlong类型的示例代码在内的说明!
总而言之,每个数据包的长度都以varint为前缀(在两种压缩模式下),因此您只需要从流中读取varint,分配那么多空间并从流中将那么多字节读取到缓冲区。 / p>
Minecraft varint的每个字节都有一个“要跟随的另一个字节?”标志位,后跟7位实际数据。这7位只是标准int的位(因此,在接收时,您实际上只是忽略了这些标志位,并将其余标志位写入标准int类型)