mirror of
				https://e.coding.net/circlecloud/YumCore.git
				synced 2025-11-03 23:06:02 +00:00 
			
		
		
		
	@@ -4,7 +4,7 @@ import pw.yumc.YumCore.annotation.NotProguard;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Minecraft工具类
 | 
					 * Minecraft工具类
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 * @author 喵♂呜
 | 
					 * @author 喵♂呜
 | 
				
			||||||
 * @since 2017/1/26 0026
 | 
					 * @since 2017/1/26 0026
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -12,9 +12,9 @@ import pw.yumc.YumCore.annotation.NotProguard;
 | 
				
			|||||||
public class MinecraftTools {
 | 
					public class MinecraftTools {
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 获得服务器信息
 | 
					     * 获得服务器信息
 | 
				
			||||||
     * 
 | 
					     *
 | 
				
			||||||
     * @param address
 | 
					     * @param address
 | 
				
			||||||
     *            服务器地址
 | 
					     *         服务器地址
 | 
				
			||||||
     * @return {@link ServerInfo} 服务器信息
 | 
					     * @return {@link ServerInfo} 服务器信息
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public static ServerInfo getServerInfo(String address) {
 | 
					    public static ServerInfo getServerInfo(String address) {
 | 
				
			||||||
@@ -25,4 +25,20 @@ public class MinecraftTools {
 | 
				
			|||||||
            return new ServerInfo(address);
 | 
					            return new ServerInfo(address);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 获得服务器信息
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param address
 | 
				
			||||||
 | 
					     *         服务器地址
 | 
				
			||||||
 | 
					     * @return {@link ServerInfo} 服务器信息
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static ServerPing getServerPing(String address) {
 | 
				
			||||||
 | 
					        if (address.contains(":")) {
 | 
				
			||||||
 | 
					            String[] args = address.split(":");
 | 
				
			||||||
 | 
					            return new ServerPing(args[0], Integer.parseInt(args[1]));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return new ServerPing(address);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,14 +1,14 @@
 | 
				
			|||||||
package pw.yumc.YumCore.mc;
 | 
					package pw.yumc.YumCore.mc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.ByteArrayOutputStream;
 | 
					 | 
				
			||||||
import java.io.DataInputStream;
 | 
					 | 
				
			||||||
import java.io.DataOutputStream;
 | 
					import java.io.DataOutputStream;
 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.io.InputStream;
 | 
				
			||||||
 | 
					import java.io.InputStreamReader;
 | 
				
			||||||
 | 
					import java.io.OutputStream;
 | 
				
			||||||
import java.net.InetSocketAddress;
 | 
					import java.net.InetSocketAddress;
 | 
				
			||||||
import java.net.Socket;
 | 
					import java.net.Socket;
 | 
				
			||||||
import java.util.regex.Pattern;
 | 
					import java.nio.charset.Charset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import lombok.Data;
 | 
					 | 
				
			||||||
import pw.yumc.YumCore.annotation.NotProguard;
 | 
					import pw.yumc.YumCore.annotation.NotProguard;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -17,37 +17,8 @@ import pw.yumc.YumCore.annotation.NotProguard;
 | 
				
			|||||||
 * @author 喵♂呜
 | 
					 * @author 喵♂呜
 | 
				
			||||||
 * @since 2017/1/26 0026
 | 
					 * @since 2017/1/26 0026
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@Data
 | 
					 | 
				
			||||||
@NotProguard
 | 
					@NotProguard
 | 
				
			||||||
public class ServerInfo {
 | 
					public class ServerInfo {
 | 
				
			||||||
    private static byte PACKET_HANDSHAKE = 0x00, PACKET_STATUSREQUEST = 0x00, PACKET_PING = 0x01;
 | 
					 | 
				
			||||||
    private static int PROTOCOL_VERSION = 4;
 | 
					 | 
				
			||||||
    private static int STATUS_HANDSHAKE = 1;
 | 
					 | 
				
			||||||
    private static Pattern pattern = Pattern.compile(".*\"description\":\"(.*)\".*");
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * {
 | 
					 | 
				
			||||||
     * "version": {"name": "BungeeCord 1.8.x, 1.9.x, 1.10.x, 1.11.x", "protocol": 316},
 | 
					 | 
				
			||||||
     * "players": {"max": 922, "online": 921},
 | 
					 | 
				
			||||||
     * "description": {
 | 
					 | 
				
			||||||
     * "extra": [
 | 
					 | 
				
			||||||
     * {"color": "white", "text": "                       "},
 | 
					 | 
				
			||||||
     * {"color": "aqua", "bold": true, "text": "梦世界 "},
 | 
					 | 
				
			||||||
     * {"color": "red","bold": true, "obfuscated": true, "text": "|"},
 | 
					 | 
				
			||||||
     * {"color": "white", "text": " "},
 | 
					 | 
				
			||||||
     * {"color": "white", "bold": true, "text": "i5mc.com\n"},
 | 
					 | 
				
			||||||
     * {"color": "white", "text": "       " },
 | 
					 | 
				
			||||||
     * {"color": "yellow", "bold": true, "text": "★"},
 | 
					 | 
				
			||||||
     * {"color": "red", "bold": true, "text": "1.8-1.11"},
 | 
					 | 
				
			||||||
     * {"color": "yellow", "bold": true, "text": "★  ★"},
 | 
					 | 
				
			||||||
     * {"color": "yellow", "text": "黄金周末"},
 | 
					 | 
				
			||||||
     * {"color": "gray", "text": "-"},
 | 
					 | 
				
			||||||
     * {"color": "green", "text": "空岛战争"},
 | 
					 | 
				
			||||||
     * {"color": "red", "bold": true, "text": "双倍硬币"},
 | 
					 | 
				
			||||||
     * {"color": "green", "text": "奖励"},
 | 
					 | 
				
			||||||
     * {"color": "yellow", "bold": true, "text": "★"}
 | 
					 | 
				
			||||||
     * ],"text": "" }
 | 
					 | 
				
			||||||
     * }
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    private String address = "localhost";
 | 
					    private String address = "localhost";
 | 
				
			||||||
    private int port = 25565;
 | 
					    private int port = 25565;
 | 
				
			||||||
    private int timeout = 1500;
 | 
					    private int timeout = 1500;
 | 
				
			||||||
@@ -88,56 +59,63 @@ public class ServerInfo {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public boolean fetchData() {
 | 
					    public boolean fetchData() {
 | 
				
			||||||
        try (Socket socket = new Socket()) {
 | 
					        try (Socket socket = new Socket()) {
 | 
				
			||||||
            socket.connect(new InetSocketAddress(getAddress(), getPort()), getTimeout());
 | 
					            OutputStream outputStream;
 | 
				
			||||||
 | 
					            DataOutputStream dataOutputStream;
 | 
				
			||||||
 | 
					            InputStream inputStream;
 | 
				
			||||||
 | 
					            InputStreamReader inputStreamReader;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            final DataInputStream in = new DataInputStream(socket.getInputStream());
 | 
					            socket.setSoTimeout(this.timeout);
 | 
				
			||||||
            final DataOutputStream out = new DataOutputStream(socket.getOutputStream());
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            //> Handshake
 | 
					            socket.connect(new InetSocketAddress(this.getAddress(), this.getPort()), this.getTimeout());
 | 
				
			||||||
            ByteArrayOutputStream handshake_bytes = new ByteArrayOutputStream();
 | 
					 | 
				
			||||||
            DataOutputStream handshake = new DataOutputStream(handshake_bytes);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            handshake.writeByte(PACKET_HANDSHAKE);
 | 
					            outputStream = socket.getOutputStream();
 | 
				
			||||||
            writeVarInt(handshake, PROTOCOL_VERSION);
 | 
					            dataOutputStream = new DataOutputStream(outputStream);
 | 
				
			||||||
            writeVarInt(handshake, getAddress().length());
 | 
					 | 
				
			||||||
            handshake.writeBytes(getAddress());
 | 
					 | 
				
			||||||
            handshake.writeShort(getPort());
 | 
					 | 
				
			||||||
            writeVarInt(handshake, STATUS_HANDSHAKE);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            writeVarInt(out, handshake_bytes.size());
 | 
					            inputStream = socket.getInputStream();
 | 
				
			||||||
            out.write(handshake_bytes.toByteArray());
 | 
					            inputStreamReader = new InputStreamReader(inputStream, Charset.forName("UTF-16BE"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            //> Status request
 | 
					            dataOutputStream.write(new byte[]{(byte) 0xFE, (byte) 0x01});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            out.writeByte(0x01); // Size of packet
 | 
					            int packetId = inputStream.read();
 | 
				
			||||||
            out.writeByte(PACKET_STATUSREQUEST);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            //< Status response
 | 
					            if (packetId == -1) { throw new IOException("Premature end of stream."); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            readVarInt(in); // Size
 | 
					            if (packetId != 0xFF) { throw new IOException("Invalid packet ID (" + packetId + ")."); }
 | 
				
			||||||
            int id = readVarInt(in);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            int length = readVarInt(in);
 | 
					            int length = inputStreamReader.read();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            byte[] data = new byte[length];
 | 
					            if (length == -1) { throw new IOException("Premature end of stream."); }
 | 
				
			||||||
            in.readFully(data);
 | 
					 | 
				
			||||||
            String json = new String(data, "UTF-8");
 | 
					 | 
				
			||||||
            System.out.println(json);
 | 
					 | 
				
			||||||
            //            //> Ping
 | 
					 | 
				
			||||||
            //
 | 
					 | 
				
			||||||
            //            out.writeByte(0x09); // Size of packet
 | 
					 | 
				
			||||||
            //            out.writeByte(PACKET_PING);
 | 
					 | 
				
			||||||
            //            out.writeLong(System.currentTimeMillis());
 | 
					 | 
				
			||||||
            //
 | 
					 | 
				
			||||||
            //            //< Ping
 | 
					 | 
				
			||||||
            //            readVarInt(in); // Size
 | 
					 | 
				
			||||||
            //            id = readVarInt(in);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Close
 | 
					            if (length == 0) { throw new IOException("Invalid string length."); }
 | 
				
			||||||
            handshake.close();
 | 
					
 | 
				
			||||||
            handshake_bytes.close();
 | 
					            char[] chars = new char[length];
 | 
				
			||||||
            out.close();
 | 
					
 | 
				
			||||||
            in.close();
 | 
					            if (inputStreamReader.read(chars, 0, length) != length) { throw new IOException("Premature end of stream."); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            String string = new String(chars);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (string.startsWith("§")) {
 | 
				
			||||||
 | 
					                String[] data = string.split("\0");
 | 
				
			||||||
 | 
					                this.pingVersion = Integer.parseInt(data[0].substring(1));
 | 
				
			||||||
 | 
					                this.protocolVersion = Integer.parseInt(data[1]);
 | 
				
			||||||
 | 
					                this.gameVersion = data[2];
 | 
				
			||||||
 | 
					                this.motd = data[3];
 | 
				
			||||||
 | 
					                this.playersOnline = Integer.parseInt(data[4]);
 | 
				
			||||||
 | 
					                this.maxPlayers = Integer.parseInt(data[5]);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                String[] data = string.split("§");
 | 
				
			||||||
 | 
					                this.motd = data[0];
 | 
				
			||||||
 | 
					                this.playersOnline = Integer.parseInt(data[1]);
 | 
				
			||||||
 | 
					                this.maxPlayers = Integer.parseInt(data[2]);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            dataOutputStream.close();
 | 
				
			||||||
 | 
					            outputStream.close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            inputStreamReader.close();
 | 
				
			||||||
 | 
					            inputStream.close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            socket.close();
 | 
				
			||||||
        } catch (IOException exception) {
 | 
					        } catch (IOException exception) {
 | 
				
			||||||
            gameVersion = "获取失败!";
 | 
					            gameVersion = "获取失败!";
 | 
				
			||||||
            motd = "获取失败!";
 | 
					            motd = "获取失败!";
 | 
				
			||||||
@@ -146,36 +124,44 @@ public class ServerInfo {
 | 
				
			|||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    public String getAddress() {
 | 
				
			||||||
     * @author thinkofdeath
 | 
					        return this.address;
 | 
				
			||||||
     * See: https://gist.github.com/thinkofdeath/e975ddee04e9c87faf22
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    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 int getPort() {
 | 
				
			||||||
     * @author thinkofdeath
 | 
					        return this.port;
 | 
				
			||||||
     * See: https://gist.github.com/thinkofdeath/e975ddee04e9c87faf22
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    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 void setTimeout(int timeout) {
 | 
				
			||||||
 | 
					        this.timeout = timeout;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public int getTimeout() {
 | 
				
			||||||
 | 
					        return this.timeout;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public int getPingVersion() {
 | 
				
			||||||
 | 
					        return this.pingVersion;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public int getProtocolVersion() {
 | 
				
			||||||
 | 
					        return this.protocolVersion;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public String getGameVersion() {
 | 
				
			||||||
 | 
					        return this.gameVersion;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public String getMotd() {
 | 
				
			||||||
 | 
					        return this.motd;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public int getPlayersOnline() {
 | 
				
			||||||
 | 
					        return this.playersOnline;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public int getMaxPlayers() {
 | 
				
			||||||
 | 
					        return this.maxPlayers;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										223
									
								
								src/main/java/pw/yumc/YumCore/mc/ServerPing.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										223
									
								
								src/main/java/pw/yumc/YumCore/mc/ServerPing.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,223 @@
 | 
				
			|||||||
 | 
					package pw.yumc.YumCore.mc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.ByteArrayOutputStream;
 | 
				
			||||||
 | 
					import java.io.DataInputStream;
 | 
				
			||||||
 | 
					import java.io.DataOutputStream;
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.net.InetSocketAddress;
 | 
				
			||||||
 | 
					import java.net.Socket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.script.ScriptException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import jdk.nashorn.api.scripting.ScriptObjectMirror;
 | 
				
			||||||
 | 
					import lombok.Data;
 | 
				
			||||||
 | 
					import lombok.SneakyThrows;
 | 
				
			||||||
 | 
					import pw.yumc.YumCore.annotation.NotProguard;
 | 
				
			||||||
 | 
					import pw.yumc.YumCore.bukkit.Log;
 | 
				
			||||||
 | 
					import pw.yumc.YumCore.engine.MiaoScriptEngine;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Minecraft服务器数据获取类
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @author 喵♂呜
 | 
				
			||||||
 | 
					 * @since 2017/1/26 0026
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Data
 | 
				
			||||||
 | 
					@NotProguard
 | 
				
			||||||
 | 
					public class ServerPing {
 | 
				
			||||||
 | 
					    private static byte PACKET_HANDSHAKE = 0x00, PACKET_STATUSREQUEST = 0x00, PACKET_PING = 0x01;
 | 
				
			||||||
 | 
					    private static int PROTOCOL_VERSION = 4;
 | 
				
			||||||
 | 
					    private static int STATUS_HANDSHAKE = 1;
 | 
				
			||||||
 | 
					    private static MiaoScriptEngine engine = new MiaoScriptEngine();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            engine.eval("function parse(json) {\n" +
 | 
				
			||||||
 | 
					                        "    var color = [];\n" +
 | 
				
			||||||
 | 
					                        "    color['black'] = '0';\n" +
 | 
				
			||||||
 | 
					                        "    color['dark_blue'] = '1';\n" +
 | 
				
			||||||
 | 
					                        "    color['dark_green'] = '2';\n" +
 | 
				
			||||||
 | 
					                        "    color['dark_aqua'] = '3';\n" +
 | 
				
			||||||
 | 
					                        "    color['dark_red'] = '4';\n" +
 | 
				
			||||||
 | 
					                        "    color['dark_purple'] = '5';\n" +
 | 
				
			||||||
 | 
					                        "    color['gold'] = '6';\n" +
 | 
				
			||||||
 | 
					                        "    color['gray'] = '7';\n" +
 | 
				
			||||||
 | 
					                        "    color['dark_gray'] = '8';\n" +
 | 
				
			||||||
 | 
					                        "    color['blue'] = '9';\n" +
 | 
				
			||||||
 | 
					                        "    color['green'] = 'a';\n" +
 | 
				
			||||||
 | 
					                        "    color['aqua'] = 'b';\n" +
 | 
				
			||||||
 | 
					                        "    color['red'] = 'c';\n" +
 | 
				
			||||||
 | 
					                        "    color['light_purple'] = 'd';\n" +
 | 
				
			||||||
 | 
					                        "    color['yellow'] = 'e';\n" +
 | 
				
			||||||
 | 
					                        "    color['white'] = 'f';\n" +
 | 
				
			||||||
 | 
					                        "    var obj = JSON.parse(json);\n" +
 | 
				
			||||||
 | 
					                        "    // noinspection JSUnresolvedVariable\n" +
 | 
				
			||||||
 | 
					                        "    var motd = obj.description.text;\n" +
 | 
				
			||||||
 | 
					                        "    // noinspection JSUnresolvedVariable\n" +
 | 
				
			||||||
 | 
					                        "    if (obj.description.extra) {\n" +
 | 
				
			||||||
 | 
					                        "        // noinspection JSUnresolvedVariable\n" +
 | 
				
			||||||
 | 
					                        "        obj.description.extra.forEach(function (part) {\n" +
 | 
				
			||||||
 | 
					                        "            // noinspection JSUnresolvedVariable\n" +
 | 
				
			||||||
 | 
					                        "            if (part.obfuscated) {\n" +
 | 
				
			||||||
 | 
					                        "                motd += \"§k\";\n" +
 | 
				
			||||||
 | 
					                        "            }\n" +
 | 
				
			||||||
 | 
					                        "            if (part.bold) {\n" +
 | 
				
			||||||
 | 
					                        "                motd += \"§l\";\n" +
 | 
				
			||||||
 | 
					                        "            }\n" +
 | 
				
			||||||
 | 
					                        "            // noinspection JSUnresolvedVariable\n" +
 | 
				
			||||||
 | 
					                        "            if (part.strikethrough) {\n" +
 | 
				
			||||||
 | 
					                        "                motd += \"§m\";\n" +
 | 
				
			||||||
 | 
					                        "            }\n" +
 | 
				
			||||||
 | 
					                        "            // noinspection JSUnresolvedVariable\n" +
 | 
				
			||||||
 | 
					                        "            if (part.underline) {\n" +
 | 
				
			||||||
 | 
					                        "                motd += \"§n\";\n" +
 | 
				
			||||||
 | 
					                        "            }\n" +
 | 
				
			||||||
 | 
					                        "            // noinspection JSUnresolvedVariable\n" +
 | 
				
			||||||
 | 
					                        "            if (part.italic) {\n" +
 | 
				
			||||||
 | 
					                        "                motd += \"§o\";\n" +
 | 
				
			||||||
 | 
					                        "            }\n" +
 | 
				
			||||||
 | 
					                        "            if (part.reset) {\n" +
 | 
				
			||||||
 | 
					                        "                motd += \"§r\";\n" +
 | 
				
			||||||
 | 
					                        "            }\n" +
 | 
				
			||||||
 | 
					                        "            if (part.color) {\n" +
 | 
				
			||||||
 | 
					                        "                motd += '§' + color[part.color];\n" +
 | 
				
			||||||
 | 
					                        "            }\n" +
 | 
				
			||||||
 | 
					                        "            motd += part.text;\n" +
 | 
				
			||||||
 | 
					                        "        })\n" +
 | 
				
			||||||
 | 
					                        "    }\n" +
 | 
				
			||||||
 | 
					                        "    obj.version_name = obj.version.name;\n" +
 | 
				
			||||||
 | 
					                        "    obj.version_protocol = obj.version.protocol;\n" +
 | 
				
			||||||
 | 
					                        "    obj.players_max = obj.players.max;\n" +
 | 
				
			||||||
 | 
					                        "    obj.players_online = obj.players.online;\n" +
 | 
				
			||||||
 | 
					                        "    obj.description = motd;\n" +
 | 
				
			||||||
 | 
					                        "    return obj;\n" +
 | 
				
			||||||
 | 
					                        "}");
 | 
				
			||||||
 | 
					        } catch (ScriptException e) {
 | 
				
			||||||
 | 
					            Log.w("警告! MOTD 解析脚本初始化失败!");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private String address = "localhost";
 | 
				
			||||||
 | 
					    private int port = 25565;
 | 
				
			||||||
 | 
					    private int timeout = 1500;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private String versionName = "初始化中...";
 | 
				
			||||||
 | 
					    private int versionProtocol = -1;
 | 
				
			||||||
 | 
					    private int playersOnline = -1;
 | 
				
			||||||
 | 
					    private int playersMax = -1;
 | 
				
			||||||
 | 
					    private String motd = "初始化中...";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Minecraft服务器数据获取类
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param address
 | 
				
			||||||
 | 
					     *         服务器地址 默认端口25565
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public ServerPing(String address) {
 | 
				
			||||||
 | 
					        this(address, 25565);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Minecraft服务器数据获取类
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param address
 | 
				
			||||||
 | 
					     *         服务器地址
 | 
				
			||||||
 | 
					     * @param port
 | 
				
			||||||
 | 
					     *         服务器端口
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public ServerPing(String address, int port) {
 | 
				
			||||||
 | 
					        this.address = address;
 | 
				
			||||||
 | 
					        this.port = port;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 获取服务器数据
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return 是否获取成功
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @SneakyThrows
 | 
				
			||||||
 | 
					    public boolean fetchData() {
 | 
				
			||||||
 | 
					        try (Socket socket = new Socket()) {
 | 
				
			||||||
 | 
					            socket.connect(new InetSocketAddress(getAddress(), getPort()), getTimeout());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            final DataInputStream in = new DataInputStream(socket.getInputStream());
 | 
				
			||||||
 | 
					            final DataOutputStream out = new DataOutputStream(socket.getOutputStream());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //> Handshake
 | 
				
			||||||
 | 
					            ByteArrayOutputStream handshake_bytes = new ByteArrayOutputStream();
 | 
				
			||||||
 | 
					            DataOutputStream handshake = new DataOutputStream(handshake_bytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            handshake.writeByte(PACKET_HANDSHAKE);
 | 
				
			||||||
 | 
					            writeVarInt(handshake, PROTOCOL_VERSION);
 | 
				
			||||||
 | 
					            writeVarInt(handshake, getAddress().length());
 | 
				
			||||||
 | 
					            handshake.writeBytes(getAddress());
 | 
				
			||||||
 | 
					            handshake.writeShort(getPort());
 | 
				
			||||||
 | 
					            writeVarInt(handshake, STATUS_HANDSHAKE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            writeVarInt(out, handshake_bytes.size());
 | 
				
			||||||
 | 
					            out.write(handshake_bytes.toByteArray());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //> Status request
 | 
				
			||||||
 | 
					            out.writeByte(0x01); // Size of packet
 | 
				
			||||||
 | 
					            out.writeByte(PACKET_STATUSREQUEST);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //< Status response
 | 
				
			||||||
 | 
					            readVarInt(in); // Size
 | 
				
			||||||
 | 
					            int id = readVarInt(in);
 | 
				
			||||||
 | 
					            int length = readVarInt(in);
 | 
				
			||||||
 | 
					            byte[] data = new byte[length];
 | 
				
			||||||
 | 
					            in.readFully(data);
 | 
				
			||||||
 | 
					            String json = new String(data, "UTF-8");
 | 
				
			||||||
 | 
					            ScriptObjectMirror mirror = (ScriptObjectMirror) engine.invokeFunction("parse", json);
 | 
				
			||||||
 | 
					            versionName = (String) mirror.get("version_name");
 | 
				
			||||||
 | 
					            versionProtocol = (int) mirror.get("version_protocol");
 | 
				
			||||||
 | 
					            playersMax = (int) mirror.get("players_max");
 | 
				
			||||||
 | 
					            playersOnline = (int) mirror.get("players_online");
 | 
				
			||||||
 | 
					            motd = (String) mirror.get("description");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Close
 | 
				
			||||||
 | 
					            handshake.close();
 | 
				
			||||||
 | 
					            handshake_bytes.close();
 | 
				
			||||||
 | 
					            out.close();
 | 
				
			||||||
 | 
					            in.close();
 | 
				
			||||||
 | 
					        } catch (IOException exception) {
 | 
				
			||||||
 | 
					            versionName = "§c获取失败!";
 | 
				
			||||||
 | 
					            motd = "§c获取失败!";
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @author thinkofdeath
 | 
				
			||||||
 | 
					     * See: https://gist.github.com/thinkofdeath/e975ddee04e9c87faf22
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @author thinkofdeath
 | 
				
			||||||
 | 
					     * See: https://gist.github.com/thinkofdeath/e975ddee04e9c87faf22
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    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;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										22
									
								
								src/test/java/pw/yumc/YumCore/mc/ServerPingTest.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/test/java/pw/yumc/YumCore/mc/ServerPingTest.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					package pw.yumc.YumCore.mc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.junit.Test;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import lombok.val;
 | 
				
			||||||
 | 
					import pw.yumc.YumCore.bukkit.Log;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Created with IntelliJ IDEA
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @author 喵♂呜
 | 
				
			||||||
 | 
					 * Created on 2017/9/29 13:05.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class ServerPingTest {
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    public void test() {
 | 
				
			||||||
 | 
					        val ping = new ServerPing("server.yumc.pw");
 | 
				
			||||||
 | 
					        ping.fetchData();
 | 
				
			||||||
 | 
					        Log.i("version: %s max: %s online: %s motd: %s",
 | 
				
			||||||
 | 
					              ping.getVersionName(), ping.getPlayersMax(), ping.getPlayersOnline(), ping.getMotd());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user