diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..e96534f --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BasicInfoAPI/libs/gson-2.8.7.jar b/BasicInfoAPI/libs/gson-2.8.7.jar new file mode 100644 index 0000000..215e823 Binary files /dev/null and b/BasicInfoAPI/libs/gson-2.8.7.jar differ diff --git a/BasicInfoAPI/src/main/api/IServerInfo.java b/BasicInfoAPI/src/main/api/IServerInfo.java index ab64e5d..3192663 100644 --- a/BasicInfoAPI/src/main/api/IServerInfo.java +++ b/BasicInfoAPI/src/main/api/IServerInfo.java @@ -6,15 +6,20 @@ */ public interface IServerInfo { class Player{ - String name; - String id; + public String name; + public String id; + } + class ExtraDescr{ + public String text; + public String color; } String getVersionName(); int getVersionProtocol(); int getMaxPlayer(); int getOnlinePlayer(); Player[] getPlayerList(); - String getServerDescription(); + String getDefaultDescriptionText(); + String getDefaultDescriptionColor(); + ExtraDescr[] getExtraDescription(); String getFavicon(); - String getJSONRawData(); } diff --git a/BasicInfoAPI/src/main/conn/MinecraftServer.java b/BasicInfoAPI/src/main/conn/MinecraftServer.java index 51b6361..2f10da5 100644 --- a/BasicInfoAPI/src/main/conn/MinecraftServer.java +++ b/BasicInfoAPI/src/main/conn/MinecraftServer.java @@ -1,15 +1,123 @@ package main.conn; +import com.google.gson.Gson; +import main.api.IServerInfo; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.Socket; +import java.nio.charset.StandardCharsets; + /** * A MinecraftServer instance provides methods to create connection to server and communicate with peer. * This is the basic instance and any info-getting function is base on this class. * * @author Rock Chin */ -public class MinecraftServer extends Thread{ +public class MinecraftServer extends Thread implements IServerInfo { + private Socket socket; + private DataOutputStream dataOutputStream; + private DataInputStream dataInputStream; + private String host; + private int port=25565; + private Response response=null; + public MinecraftServer(String host,int port)throws Exception { + socket=new Socket(host,port); + this.host=host; + this.port=port; + dataInputStream=new DataInputStream(socket.getInputStream()); + dataOutputStream=new DataOutputStream(socket.getOutputStream()); + + new PacketSend(0).addVarInt(-1) + .addString(host) + .addShort(port) + .addVarInt(1).write(dataOutputStream); + new PacketSend(0).write(dataOutputStream); + response=new Gson().fromJson(new PacketRecv(dataInputStream).popString(),Response.class); + } + + + public class Response{ + class description{ + String text; + String color; + description[] extra; + } + description description; + class players{ + int max; + int online; + class player{ + String name; + String id; + } + player[] sample; + } + players players; + class version{ + String name; + int protocol; + } + version version; + String favicon; + } + + + @Override + public String getVersionName() { + return response.version.name; + } + + @Override + public int getVersionProtocol() { + return response.version.protocol; + } + @Override - public void run(){ + public int getMaxPlayer() { + return response.players.max; + } + + @Override + public int getOnlinePlayer() { + return response.players.online; + } + @Override + public Player[] getPlayerList() { + int len=response.players.sample.length; + Player[] players=new Player[len]; + for (int i=0;i 5) { + throw new RuntimeException("VarInt is too big"); + } + } while ((read & 0b10000000) != 0); + + return result; + } + + public String popString(){ + int len=popVarInt(); + byte[] b=new byte[len]; + pop(b,0,len); + return new String(b); + } + + + + public int readVarInt()throws IOException { + int numRead = 0; + int result = 0; + byte read; + do { + read = dataInputStream.readByte(); + int value = (read & 0b01111111); + result |= (value << (7 * numRead)); + + numRead++; + if (numRead > 5) { + throw new RuntimeException("VarInt is too big"); + } + } while ((read & 0b10000000) != 0); + + return result; + } + +} diff --git a/BasicInfoAPI/src/main/conn/PacketSend.java b/BasicInfoAPI/src/main/conn/PacketSend.java new file mode 100644 index 0000000..196d19d --- /dev/null +++ b/BasicInfoAPI/src/main/conn/PacketSend.java @@ -0,0 +1,77 @@ +package main.conn; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; + +/** + * Provides a convenient way to make a packet and send it to provided peer. + * Supports chain-style creating methods. + * e.g. packetObj.addVarInt(0).addString("exampleString").addVarInt(2).write(definedDataOutputStreamObj); + * + * @author Rock Chin + */ +public class PacketSend { + private ArrayList dataBuf=new ArrayList<>(); + private int packetID=0; + public int getPacketID(){ + return packetID; + } + public PacketSend(int packetID){ + this.packetID=packetID; + addVarInt(packetID); + } + public void write(DataOutputStream dataOutputStream)throws IOException{ + int size=dataBuf.size(); + writeVarInt(size,dataOutputStream); + byte[] temp=new byte[size]; + for (int i=0;i>> means that the sign bit is shifted with the rest of the number rather than being left alone + value >>>= 7; + if (value != 0) { + temp |= 0b10000000; + } + dataOutputStream.write(temp); + dataOutputStream.flush(); + } while (value != 0); + } + private void append(byte b){ + dataBuf.add(b); + } + private void append(byte[] bArr){ + for (byte b:bArr){ + append(b); + } + } + public PacketSend addVarInt(int i){ + do { + byte temp = (byte)(i & 0b01111111); + // Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone + i >>>= 7; + if (i != 0) { + temp |= 0b10000000; + } + append(temp); + } while (i != 0); + return this; + } + public PacketSend addString(String s){ + byte[] b=s.getBytes(); + addVarInt(b.length); + append(b); + return this; + } + public PacketSend addShort(int s){ + append((byte) ((s >>> 8) & 0xFF)); + append((byte) ((s >>> 0) & 0xFF)); + return this; + } +} diff --git a/BasicInfoAPI/src/test/conn/CommunicateTest.java b/BasicInfoAPI/src/test/conn/CommunicateTest.java index 5e1af6b..09652d3 100644 --- a/BasicInfoAPI/src/test/conn/CommunicateTest.java +++ b/BasicInfoAPI/src/test/conn/CommunicateTest.java @@ -8,7 +8,7 @@ import java.nio.charset.StandardCharsets; public class CommunicateTest { - static String host="192.168.1.3"; + static String host="49.234.30.88"; static int port=25565; static DataOutputStream dataOutputStream; static DataInputStream dataInputStream; @@ -18,16 +18,22 @@ public static void main(String[] args)throws Exception { dataOutputStream=new DataOutputStream(socket.getOutputStream()); dataInputStream=new DataInputStream(socket.getInputStream()); System.out.println("streamObjectCreated."); - writeVarInt(18); + writeVarInt(19); writeVarInt(0x00); writeVarInt(754); - writeString("192.168.1.3"); + writeString("49.234.30.88"); writeVarInt(25567); writeVarInt(1); // dataOutputStream.write(1); // dataOutputStream.flush(); System.out.println("wroteHandshake."); writeVarInt(0); +// System.out.println("recv:"+readVarInt()); +// System.out.println(dataInputStream.readByte()); +// System.out.println(dataInputStream.readByte()); +// System.out.println(dataInputStream.readByte()); +// System.out.println(dataInputStream.readByte()); +// System.out.println(readVarInt()); System.out.println("recv:"+readString()); } public static void writeVarInt(int value)throws Exception { @@ -56,6 +62,10 @@ public static String readString()throws Exception{ dataInputStream.read(b,0,len); return new String(b); } + public static String readSingleString()throws Exception{ + byte[] b=new byte[1024]; + return new String(b); + } public static int readVarInt()throws Exception { int numRead = 0; int result = 0; diff --git a/BasicInfoAPI/src/test/conn/FakeServerTest.java b/BasicInfoAPI/src/test/conn/FakeServerTest.java index d368bc1..e770c85 100644 --- a/BasicInfoAPI/src/test/conn/FakeServerTest.java +++ b/BasicInfoAPI/src/test/conn/FakeServerTest.java @@ -8,7 +8,7 @@ public class FakeServerTest { static DataInputStream dataInputStream; public static void main(String[] args)throws Exception { - ServerSocket socket=new ServerSocket(25567); + ServerSocket socket=new ServerSocket(25565); while (true){ Socket client=socket.accept(); System.out.println("newConn."); diff --git a/BasicInfoAPI/src/test/conn/MinecraftServerTest.java b/BasicInfoAPI/src/test/conn/MinecraftServerTest.java new file mode 100644 index 0000000..7a5891c --- /dev/null +++ b/BasicInfoAPI/src/test/conn/MinecraftServerTest.java @@ -0,0 +1,22 @@ +package test.conn; + +import main.api.IServerInfo; +import main.conn.MinecraftServer; + +public class MinecraftServerTest { + public static void main(String[] args)throws Exception { + MinecraftServer minecraftServer=new MinecraftServer("play.ee-fans.com",25565); + System.out.println("version:name:"+minecraftServer.getVersionName()+" protocol:"+minecraftServer.getVersionProtocol()); + System.out.println("defaultDescription:color:"+minecraftServer.getDefaultDescriptionColor()+" text:"+minecraftServer.getDefaultDescriptionText()); + IServerInfo.ExtraDescr[] extraDescrs=minecraftServer.getExtraDescription(); + for (IServerInfo.ExtraDescr extraDescr:extraDescrs){ + System.out.println("extraDescription:color:"+extraDescr.color+" text:"+extraDescr.text); + } + System.out.println("players:max:"+minecraftServer.getMaxPlayer()+" online:"+minecraftServer.getOnlinePlayer()); + IServerInfo.Player[] players=minecraftServer.getPlayerList(); + for (IServerInfo.Player p:players){ + System.out.println("player:name:"+p.name+" id:"+p.id); + } + System.out.println("favicon:"+minecraftServer.getFavicon()); + } +}