Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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;
}
}
}
@scizzr

This comment has been minimized.

Copy link

@scizzr scizzr commented Nov 3, 2013

Glad to see they updated to use a more friendly interface. Less byte and more JSON! :)

@ghost

This comment has been minimized.

Copy link

@ghost ghost commented Dec 23, 2013

Thanks!

@winny-

This comment has been minimized.

Copy link

@winny- winny- commented May 2, 2014

Thanks! Found the VarInt code extremely helpful for an implementation in PHP.

@jamezrin

This comment has been minimized.

Copy link

@jamezrin jamezrin commented Mar 19, 2016

It is not working anymore on 1.9 servers, the Json changed and this exception gets thrown
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 17 path $.description at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:200) at com.google.gson.Gson.fromJson(Gson.java:810) at com.google.gson.Gson.fromJson(Gson.java:775) at com.google.gson.Gson.fromJson(Gson.java:724) at com.google.gson.Gson.fromJson(Gson.java:696)

@AppleSa

This comment has been minimized.

Copy link

@AppleSa AppleSa commented May 17, 2016

Thanks!Thanks!Thanks!

@zh32

This comment has been minimized.

Copy link
Owner Author

@zh32 zh32 commented Oct 19, 2016

This code is public domain. Thanks to @Thinkofname for the varint code.

@JusticePro

This comment has been minimized.

Copy link

@JusticePro JusticePro commented Dec 22, 2018

It is not working anymore on 1.9 servers, the Json changed and this exception gets thrown
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 17 path $.description at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:200) at com.google.gson.Gson.fromJson(Gson.java:810) at com.google.gson.Gson.fromJson(Gson.java:775) at com.google.gson.Gson.fromJson(Gson.java:724) at com.google.gson.Gson.fromJson(Gson.java:696)

1.9+:

package me.justicepro.serverspy;
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);
        
        dataOutputStream.close();
        outputStream.close();
        inputStreamReader.close();
        inputStream.close();
        socket.close();
        
        return response;
    }
    
    
    public class StatusResponse {
        private Description description;
        private Players players;
        private Version version;
        private String favicon;
        private int time;

        public Description 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 int protocol;

        public String getName() {
            return name;
        }

        public int getProtocol() {
            return protocol;
        }
    }
    
    public class Description {
        private String text;

        public String getText() {
            return text;
        }

    }
    
}

@Weixiaojun666

This comment has been minimized.

Copy link

@Weixiaojun666 Weixiaojun666 commented Apr 11, 2020

How can I use it?

@NPBeta

This comment has been minimized.

Copy link

@NPBeta NPBeta commented Jul 3, 2020

How can I use it?

自己人我就直接中文说了:

  1. 在你的项目里加入这个类,然后在你自己的代码里创建一个对应的实例。
  2. 创建一个 InetSocketAddress 对象,定义你服务器的域名(或 IP)和端口。
  3. 使用 setAddress() 方法设置你的服务器地址。
  4. 使用 fetchData() 方法拉取数据到 StatusResponse 对象中,并用其提供的方法获取你所需的数据。

Sorry for my poor English, but I think this below still can be useful.

  1. Insert this Class into your project, and create a corresponding instance.
  2. Create a object InetSocketAddress to define your server hostname / IP and port.
  3. Use method setAddress() to set your server address.
  4. Use method fetchData() to fetch data into object StatusResponse, and extract anything you need from it by using its own method.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.