Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand All @@ -259,14 +270,16 @@ public boolean fetchData() {
socket = null;
return false;
}
if (packetId != 255) {
if (packetId != 0xFF) {
try {
socket.close();
} catch (IOException iOException) {
}
socket = null;
return false;
}

// Read string length field (2 bytes)
int length = inputStreamReader.read();
if (length == -1) {
try {
Expand All @@ -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 {
Expand All @@ -294,16 +309,27 @@ 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]);
setMotd(data[3]);
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]));
Expand Down