I'm trying to send a LoginStart packet, but the server responds with an error.
The entire server response:
�{"translate":"disconnect.genericReason","with":["Internal Exception: io.netty.handler.codec.DecoderException: java.lang.IndexOutOfBoundsException: readerIndex(27) + length(8) exceeds writerIndex(34): PooledUnsafeDirectByteBuf(ridx: 27, widx: 34, cap: 34)"]}
MinecraftPlayer class that starting connection:
public class MinecraftPlayer {
public Socket sock;
public DataOutputStream output;
public DataInputStream input;
public MinecraftServer server;
public UUID uuid;
public String name;
public MinecraftPlayer(MinecraftServer server, UUID uuid, String name) {
this.server = server;
this.uuid = uuid;
this.name = name;
}
public void startConnection() {
new Thread(() -> {
try {
this.sock = new Socket();
sock.connect(server.host);
this.output = new DataOutputStream(sock.getOutputStream());
this.input = new DataInputStream(sock.getInputStream());
// Отправляем handshake
sendHandshake();
// Отправляем пакет login start
sendLoginStartPacket();
// Читаем ответ от сервера
if (readLoginSuccessPacket()) {
System.out.println("Login Successful!");
} else {
System.out.println("Login Failed!");
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
private void sendHandshake() throws IOException {
// System.out.println("send handshake");
OutputPacketContainer packet = new OutputPacketContainer((byte) 0x00);
packet.writeVarInt(server.protocol_version); // Protocol version
packet.writeString(server.host.getHostString()); // Server address
packet.writeShort((short) server.host.getPort()); // Server port as// unsigned short
packet.writeVarInt(2); // Next state (2 for login)
packet.sendPacket(this);
}
private void sendLoginStartPacket() throws IOException {
// System.out.println("send login start");
OutputPacketContainer packet = new OutputPacketContainer((byte) 0x00);
packet.writeString(name);
packet.writeUUID(uuid);
packet.sendPacket(this);
}
private boolean readLoginSuccessPacket() throws IOException {
int length = readVarInt(input);
int packetId = readVarInt(input);
if (packetId == 0x02) { // Packet ID for login success
UUID uuid = new UUID(input.readLong(), input.readLong()); // UUID is received
String username = readString(input); // Username is received as String
System.out.println("UUID: " + uuid + ", Username: " + username);
return true;
} else if (packetId == 0x00) {
Main.logInputPacket(length, packetId, input.readAllBytes());
// System.out.println((String)((List<Object>)((Map<String,Object>)JSON.load(readString(input))).get("with")).get(0));
}
return false;
}
private int readVarInt(DataInputStream in) throws IOException {
int value = 0;
int bitOffset = 0;
byte b;
do {
b = in.readByte();
value |= (b & 127) << bitOffset;
bitOffset += 7;
} while ((b & 128) == 128);
return value;
}
private String readString(DataInputStream in) throws IOException {
int length = readVarInt(in); // Length of string
byte[] bytes = new byte[length];
in.readFully(bytes); // Read string bytes
return new String(bytes, StandardCharsets.UTF_8); // Create string
}
}
OutputPacketContainer class that creates packet:
public class OutputPacketContainer {
private ByteArrayOutputStream buffer;
private DataOutputStream output;
private byte packet_id;
public OutputPacketContainer(byte packet_id) {
this.packet_id = packet_id;
buffer = new ByteArrayOutputStream();
output = new DataOutputStream(buffer);
writeVarInt(packet_id);
}
public ByteArrayOutputStream getBuffer() {
return buffer;
}
public DataOutputStream getOutput() {
return output;
}
public byte getPacketId() {
return packet_id;
}
public void writeByte(byte v) {
try {
output.writeByte(v);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void writeShort(short v) {
try {
output.writeShort(v);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void writeString(String v, Charset charset) {
byte[] bytes = v.getBytes(charset);
writeVarInt(bytes.length);
writeBytes(bytes);
}
public void writeString(String v) {
writeString(v,StandardCharsets.UTF_8);
}
public void writeVarInt(int v) {
writeVarInt(output,v);
}
public void writeVarLong(long v) {
writeVarLong(output,v);
}
public void writeBytes(byte[] v) {
try {
output.write(v);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void writeUUID(UUID v) {
try {
output.writeLong(v.getMostSignificantBits());
output.writeLong(v.getLeastSignificantBits());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void sendPacket(MinecraftPlayer player) {
byte[] message = buffer.toByteArray();
try {
writeVarInt(player.output, message.length);
player.output.write(message);
player.output.flush();
Main.logOutputPacket(message.length, packet_id, message);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static final int SEGMENT_BITS = 0x7F;
private static final int CONTINUE_BIT = 0x80;
private static void writeVarInt(DataOutputStream output, int v) {
try {
while (true) {
if ((v & ~SEGMENT_BITS) == 0) {
output.writeByte(v);
return;
}
output.writeByte((v & SEGMENT_BITS) | CONTINUE_BIT);
// Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone
v >>>= 7;
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static void writeVarLong(DataOutputStream output, long v) {
try {
while (true) {
if ((v & ~((long) SEGMENT_BITS)) == 0) {
output.writeByte((int) v);
return;
}
output.writeByte((int) ((v & SEGMENT_BITS) | CONTINUE_BIT));
// Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone
v >>>= 7;
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
I think the problem is OutputPacketContainer#writeUUID, but couldn’t find a solution. Wrote code based on wiki.vg