我正在尝试为 Minecraft 编写一个代理,它应该拦截客户端和服务器之间发送的包。 我让代理正常工作,但我收到的数据包 ID 似乎与协议 wiki 中的数据包 ID 不匹配。
例如:如果玩家/实体移动,客户端应该向服务器发送this数据包(我认为)。 该数据包以 ID 开头:0x2C。当玩家移动时我得到的实际数据包是:1B 00 14 C0 11 76 EE 76 F6 9B C0 40 55 40 00 00 00 00 00 BF FD 0E DF A6 AD 79 0F 01,其数据包ID:(0x)1B。
另一个例子:如果玩家破坏了一个区块,客户端应该将 this 数据包发送到服务器(我认为)。 该数据包以 ID 开头:0x07。当玩家打破方块时,我收到的实际数据包是:03 00 2F 00,其数据包 ID 为 (0x)03。
我显然做错了什么,但我不确定这是否是因为我引用了错误的数据包,或者有一些数据包可以解密。请注意,我在离线模式下运行我的服务器,因此应该有来自 Microsoft/Mojang 的任何身份验证,因此没有加密。
对于任何想知道的人,这是我的代码:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
public class MinecraftProxy {
private static final String SERVER_HOST = "localhost"; // Replace with your actual server host
private static final int SERVER_PORT = 25565; // Replace with your actual server port
public static void main(String[] args) throws IOException {
ServerSocket proxyServerSocket = new ServerSocket(55555); // Proxy server port
while (true) {
Socket clientSocket = proxyServerSocket.accept();
Socket serverSocket = new Socket(SERVER_HOST, SERVER_PORT);
// Create separate threads to handle client-to-server and server-to-client communication
Thread clientToServerThread = new Thread(() -> copyStreams(clientSocket, serverSocket, "Client to Server"));
Thread serverToClientThread = new Thread(() -> copyStreams(serverSocket, clientSocket, "Server to Client"));
clientToServerThread.start();
serverToClientThread.start();
}
}
private static void copyStreams(Socket inputSocket, Socket outputSocket, String direction) {
try {
InputStream inputStream = inputSocket.getInputStream();
OutputStream outputStream = outputSocket.getOutputStream();
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
byte[] packet = Arrays.copyOf(buffer, bytesRead);
// Print the packet being sent or received
if (direction.equals("Client to Server")) {
System.out.println("Packet Sent: " + bytesToString(packet));
} else {
// System.out.println("Packet Received: " + bytesToString(packet));
}
// Data is being received from inputSocket (client) and sent to outputSocket (server)
outputStream.write(buffer, 0, bytesRead);
outputStream.flush();
}
// Input stream closed, so close the output stream and sockets as well
outputStream.close();
inputSocket.close();
outputSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private static String bytesToString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X ", b));
}
return sb.toString();
}
}
编辑:拼写错误
巨大更新:
第一个字节似乎对应于数据包的其余长度。 由于某种原因,第二个字节将始终为 00。 第三个字节将是数据包 ID。
例如,我的第一个示例的第三个字节是:14。这对应于 this 数据包,其中确实包含玩家位置。唯一的区别是这个数据包是服务器绑定的而不是客户端绑定的。
我的第二个例子的第三个字节是:2F。这对应于 this 数据包,而不是破坏块的数据包。现在我想起来了,这更符合逻辑,因为当打破一个方块时,玩家会挥动它的手臂。当然,这里的数据包也是服务器绑定的而不是客户端绑定的。
当我说在这个项目上总共花费了 20 多个小时时,我并没有撒谎,所以我要感谢大家回答我的问题。特别是@Rogue 和@RealSkeptic 提供的答案帮助我进一步前进。
干杯!
第一个字节似乎对应于数据包的其余长度。由于某种原因,第二个字节将始终为 00。第三个字节将是数据包 ID。
例如,我的第一个示例的第三个字节是:14。这对应于确实包含玩家位置的数据包。唯一的区别是这个数据包是服务器绑定的而不是客户端绑定的。
我的第二个例子的第三个字节是:2F。这对应于该数据包而不是破坏块的数据包。现在我想起来了,这更符合逻辑,因为当打破一个方块时,玩家会挥动它的手臂。当然,这里的数据包也是服务器绑定的而不是客户端绑定的。
当我说在这个项目上总共花费了 20 多个小时时,我并没有撒谎,所以我要感谢大家回答我的问题。特别是@Rogue 和@RealSkeptic 提供的答案帮助我进一步前进。
干杯!