Minecraft 有自己的协议。我正在尝试实现客户端。我的世界版本 1.16.5
我请求你花点时间阅读这里写的所有内容,深入研究它,并尝试复制它。我将不胜感激!
协议的本质是客户端和服务器通过TCP协议进行通信,交换数据包。正如协议中所写,我的世界中的数据包是一组字节,由以下部分组成:数据包字节的长度、前缀和内容。(服务器,可本地一键启动,可在此处下载)
示例:要告诉服务器您是新客户端,您需要发送握手请求,其中包括номер протокола
(在 minecraft 版本 1.16.5 上为 754)хост
、порт
和статус
(= 2 用于授权)。
在代码中,它看起来像这样(为了简化再现和准确性,我删除了所有将值转换为字节的辅助类,反之亦然):
var packetLength = new byte[] { 16 }; // длина пакета
var prefix = new byte[] { 0x00 }; // префикс [1 байт]
var protocolVersion = new byte[] { 242, 5 }; // протокол (= 754) [2 байта]
var hostBytesLength = new byte[] { 9 }; // длина байтов хоста [1 байт]
var hostBytes = new byte[] { 108, 11, 99, // хост (= "localhost") [9 байт]
97, 108, 104,
11, 115, 116 };
var port = new byte[] { 221, 99 }; // порт (= 25565) [2 байта]
var nextState = new byte[] { 2 }; // состояние [1 байт]
// stream = client.GetStream(), где client = new TcpClient("localhost", 25565)
stream.Write(packetLength, 0, packetLength.Length);
stream.Write(prefix, 0, prefix.Length);
stream.Write(protocolVersion, 0, protocolVersion.Length);
stream.Write(hostBytesLength, 0, hostBytesLength.Length);
stream.Write(hostBytes, 0, hostBytes.Length);
stream.Write(port, 0, port.Length);
stream.Write(nextState, 0, nextState.Length);
之后,服务器发送响应0x03:
// № байта // значение // описание
[0] 3 длина пакета
[1] 0x03 префикс
[2-3] 128, 2 threshold - максимальный размер пакета (= 256)
上面的一切都很好。我的包裹正确离开,正确的包裹到达。问题在于服务器对我的下一个请求的响应——授权请求。
授权请求仅包括имя игрока
. 所以请求本身:
var packetLength = new byte[] { 6 }; // длина пакета
var prefix = new byte[] { 0x00 }; // префикс [1 байт]
var usernameBytesLength = new byte[] { 4 }; // длина байтов имени игрока [1 байт]
var usernameBytes = new byte[] { 98, 111, // имя игрока (= "bot2") [4 байта]
116, 50 };
stream.Write(packetLength, 0, packetLength.Length);
stream.Write(prefix, 0, prefix.Length);
stream.Write(usernameBytesLength, 0, usernameBytesLength.Length);
stream.Write(usernameBytes, 0, usernameBytes.Length);
作为回应,我得到以下信息:
// № байта // значение // описание
[0] 23 длина пакета
[1] 0x00 префикс
[2] 0x02
[3-23] байты остальные данные
出了点问题。我应该在响应中收到一个数据包0x02,其中包含16-ти значный uuid
和имя игрока
,与请求中的相同。此外,与服务器返回的字节匹配的其他 0x00 数据包在 Wikipedia 上也没有描述。
我试图忽略这个零字节(读取,但不考虑),然后一切都一起增长:
// № байта // значение // описание
[0] 23 длина пакета
[1] 0x00 что-то (проигнорированно)
[2] 0x02 префикс
[3-18] байты uuid
[19] 4 длина байтов имени игрока
[20-23] 98, 111, имя игрока (= "bot2")
116, 50
问题:为什么服务器没有在命中时发送这个空字节?
附言
我试过的:
我在协议中找到了对此的描述。这个晦涩的字节表示“打包”字节包的长度(0 - 未打包):