diff --git a/src/main/java/com/extendedclip/papi/expansion/pinger/PingerExpansion.java b/src/main/java/com/extendedclip/papi/expansion/pinger/PingerExpansion.java index 9a13260..8b03719 100644 --- a/src/main/java/com/extendedclip/papi/expansion/pinger/PingerExpansion.java +++ b/src/main/java/com/extendedclip/papi/expansion/pinger/PingerExpansion.java @@ -12,7 +12,7 @@ import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketException; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -248,8 +248,19 @@ public boolean fetchData() { DataOutputStream dataOutputStream = new DataOutputStream(outputStream); InputStream inputStream = socket.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, - Charset.forName("UTF-16BE")); - dataOutputStream.write(new byte[]{-2, 1}); + StandardCharsets.UTF_16BE); + + // Send server list ping request, in 1.4-1.5 format + // See https://wiki.vg/Server_List_Ping#1.4_to_1.5 + dataOutputStream.write(0xFE); + dataOutputStream.write(0x01); + + // Then, read the ping response (a kick packet) + // Beta 1.8 - 1.3 servers should respond with this format: https://wiki.vg/Server_List_Ping#Beta_1.8_to_1.3 + // 1.4+ servers should respond with this format: https://wiki.vg/Server_List_Ping#1.4_to_1.5 + // which uses the same response format as: https://wiki.vg/Server_List_Ping#1.6 + + // Read packet ID field (1 byte), should be 0xFF (kick packet ID) int packetId = inputStream.read(); if (packetId == -1) { try { @@ -259,7 +270,7 @@ public boolean fetchData() { socket = null; return false; } - if (packetId != 255) { + if (packetId != 0xFF) { try { socket.close(); } catch (IOException iOException) { @@ -267,6 +278,8 @@ public boolean fetchData() { socket = null; return false; } + + // Read string length field (2 bytes) int length = inputStreamReader.read(); if (length == -1) { try { @@ -284,6 +297,8 @@ public boolean fetchData() { socket = null; return false; } + + // Read string (length bytes) char[] chars = new char[length]; if (inputStreamReader.read(chars, 0, length) != length) { try { @@ -294,8 +309,15 @@ public boolean fetchData() { return false; } String string = new String(chars); - if (string.startsWith("&")) { - String[] data = string.split("\000"); + + // Read the fields of the string + if (string.startsWith("§")) { + // If the string starts with '§', the server is probably running 1.4+ + // See https://wiki.vg/Server_List_Ping#1.4_to_1.5 + // and https://wiki.vg/Server_List_Ping#1.6 + + // In this format, fields are delimited by '\0' characters + String[] data = string.split("\0"); setPingVersion(Integer.parseInt(data[0].substring(1))); setProtocolVersion(Integer.parseInt(data[1])); setGameVersion(data[2]); @@ -303,7 +325,11 @@ public boolean fetchData() { setPlayersOnline(Integer.parseInt(data[4])); setMaxPlayers(Integer.parseInt(data[5])); } else { - String[] data = string.split("&"); + // If the string doesn't start with '§', the server is probably running Beta 1.8 - 1.3 + // See https://wiki.vg/Server_List_Ping#Beta_1.8_to_1.3 + + // In this format, fields are delimited by '§' characters + String[] data = string.split("§"); setMotd(data[0]); setPlayersOnline(Integer.parseInt(data[1])); setMaxPlayers(Integer.parseInt(data[2]));