Skip to content

Instantly share code, notes, and snippets.

@zh32
Last active February 19, 2024 23:48
Show Gist options
  • Star 54 You must be signed in to star a gist
  • Fork 11 You must be signed in to fork a gist
  • Save zh32/7190955 to your computer and use it in GitHub Desktop.
Save zh32/7190955 to your computer and use it in GitHub Desktop.
package de.zh32.slp;
import com.google.gson.Gson;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.List;
/**
*
* @author zh32 <zh32 at zh32.de>
*/
public class ServerListPing17 {
private InetSocketAddress host;
private int timeout = 7000;
private Gson gson = new Gson();
public void setAddress(InetSocketAddress host) {
this.host = host;
}
public InetSocketAddress getAddress() {
return this.host;
}
void setTimeout(int timeout) {
this.timeout = timeout;
}
int getTimeout() {
return this.timeout;
}
public int readVarInt(DataInputStream in) throws IOException {
int i = 0;
int j = 0;
while (true) {
int k = in.readByte();
i |= (k & 0x7F) << j++ * 7;
if (j > 5) throw new RuntimeException("VarInt too big");
if ((k & 0x80) != 128) break;
}
return i;
}
public void writeVarInt(DataOutputStream out, int paramInt) throws IOException {
while (true) {
if ((paramInt & 0xFFFFFF80) == 0) {
out.writeByte(paramInt);
return;
}
out.writeByte(paramInt & 0x7F | 0x80);
paramInt >>>= 7;
}
}
public StatusResponse fetchData() throws IOException {
Socket socket = new Socket();
OutputStream outputStream;
DataOutputStream dataOutputStream;
InputStream inputStream;
InputStreamReader inputStreamReader;
socket.setSoTimeout(this.timeout);
socket.connect(host, timeout);
outputStream = socket.getOutputStream();
dataOutputStream = new DataOutputStream(outputStream);
inputStream = socket.getInputStream();
inputStreamReader = new InputStreamReader(inputStream);
ByteArrayOutputStream b = new ByteArrayOutputStream();
DataOutputStream handshake = new DataOutputStream(b);
handshake.writeByte(0x00); //packet id for handshake
writeVarInt(handshake, 4); //protocol version
writeVarInt(handshake, this.host.getHostString().length()); //host length
handshake.writeBytes(this.host.getHostString()); //host string
handshake.writeShort(host.getPort()); //port
writeVarInt(handshake, 1); //state (1 for handshake)
writeVarInt(dataOutputStream, b.size()); //prepend size
dataOutputStream.write(b.toByteArray()); //write handshake packet
dataOutputStream.writeByte(0x01); //size is only 1
dataOutputStream.writeByte(0x00); //packet id for ping
DataInputStream dataInputStream = new DataInputStream(inputStream);
int size = readVarInt(dataInputStream); //size of packet
int id = readVarInt(dataInputStream); //packet id
if (id == -1) {
throw new IOException("Premature end of stream.");
}
if (id != 0x00) { //we want a status response
throw new IOException("Invalid packetID");
}
int length = readVarInt(dataInputStream); //length of json string
if (length == -1) {
throw new IOException("Premature end of stream.");
}
if (length == 0) {
throw new IOException("Invalid string length.");
}
byte[] in = new byte[length];
dataInputStream.readFully(in); //read json string
String json = new String(in);
long now = System.currentTimeMillis();
dataOutputStream.writeByte(0x09); //size of packet
dataOutputStream.writeByte(0x01); //0x01 for ping
dataOutputStream.writeLong(now); //time!?
readVarInt(dataInputStream);
id = readVarInt(dataInputStream);
if (id == -1) {
throw new IOException("Premature end of stream.");
}
if (id != 0x01) {
throw new IOException("Invalid packetID");
}
long pingtime = dataInputStream.readLong(); //read response
StatusResponse response = gson.fromJson(json, StatusResponse.class);
response.setTime((int) (now - pingtime));
dataOutputStream.close();
outputStream.close();
inputStreamReader.close();
inputStream.close();
socket.close();
return response;
}
public class StatusResponse {
private String description;
private Players players;
private Version version;
private String favicon;
private int time;
public String getDescription() {
return description;
}
public Players getPlayers() {
return players;
}
public Version getVersion() {
return version;
}
public String getFavicon() {
return favicon;
}
public int getTime() {
return time;
}
public void setTime(int time) {
this.time = time;
}
}
public class Players {
private int max;
private int online;
private List<Player> sample;
public int getMax() {
return max;
}
public int getOnline() {
return online;
}
public List<Player> getSample() {
return sample;
}
}
public class Player {
private String name;
private String id;
public String getName() {
return name;
}
public String getId() {
return id;
}
}
public class Version {
private String name;
private String protocol;
public String getName() {
return name;
}
public String getProtocol() {
return protocol;
}
}
}
@mosemister
Copy link

My custom server works with this code as the client, however does not work with the Vanilla client. Is there something else missing from this code that is in modern clients. Im using the 1.9+ version. I have tested this code on a regular vanilla client and it works too so im unsure why this code works on both my server and a regular vannila server, yet my server doesnt work with the vanilla client

@MrKammounYT
Copy link

MrKammounYT commented Aug 20, 2022

java.net.SocketTimeoutException: Read timed out
at java.base/sun.nio.ch.NioSocketImpl.timedRead(NioSocketImpl.java:283)
at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:309)
at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350)
at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:803)
at java.base/java.net.Socket$SocketInputStream.read(Socket.java:966)
at java.base/java.net.Socket$SocketInputStream.read(Socket.java:961)
at java.base/java.io.DataInputStream.readByte(DataInputStream.java:271)
at t.ServerListPinger.readVarInt(ServerListPinger.java:41)
at t.ServerListPinger.fetchData(ServerListPinger.java:95)
at src.main.main(main.java:15)

	InetSocketAddress inet = new InetSocketAddress("EagleMC.net", 25565);
		ServerListPinger slp = new ServerListPinger();
		slp.setAddress(inet);
		try {
			System.out.print("Players: "+slp.fetchData().getPlayers());
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

@AnAverageBeing
Copy link

java.net.SocketTimeoutException: Read timed out at java.base/sun.nio.ch.NioSocketImpl.timedRead(NioSocketImpl.java:283) at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:309) at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350) at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:803) at java.base/java.net.Socket$SocketInputStream.read(Socket.java:966) at java.base/java.net.Socket$SocketInputStream.read(Socket.java:961) at java.base/java.io.DataInputStream.readByte(DataInputStream.java:271) at t.ServerListPinger.readVarInt(ServerListPinger.java:41) at t.ServerListPinger.fetchData(ServerListPinger.java:95) at src.main.main(main.java:15)

	InetSocketAddress inet = new InetSocketAddress("EagleMC.net", 25565);
		ServerListPinger slp = new ServerListPinger();
		slp.setAddress(inet);
		try {
			System.out.print("Players: "+slp.fetchData().getPlayers());
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

bro use the server ip instead of domain
for example
if server address is mc.example.org
and this points to 69.69.69.69 then use
69.69.69.69 as ip

InetSocketAddress inet = new InetSocketAddress("69.69.69.69", 25565);
		ServerListPinger slp = new ServerListPinger();
		slp.setAddress(inet);
		try {
			System.out.print("Players: "+slp.fetchData().getPlayers());
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}```

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment