1
0
mirror of https://e.coding.net/circlecloud/YumCore.git synced 2024-11-27 02:38:48 +00:00

feat: 新的MC信息获取代码

Signed-off-by: 502647092 <admin@yumc.pw>
This commit is contained in:
502647092 2017-09-28 20:54:56 +08:00
parent b5d65c7169
commit 6ea90b46ff
2 changed files with 128 additions and 94 deletions

View File

@ -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.nio.charset.Charset; import java.util.regex.Pattern;
import lombok.Data;
import pw.yumc.YumCore.annotation.NotProguard; import pw.yumc.YumCore.annotation.NotProguard;
/** /**
@ -17,8 +17,37 @@ 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;
@ -59,63 +88,56 @@ public class ServerInfo {
*/ */
public boolean fetchData() { public boolean fetchData() {
try (Socket socket = new Socket()) { try (Socket socket = new Socket()) {
OutputStream outputStream; socket.connect(new InetSocketAddress(getAddress(), getPort()), getTimeout());
DataOutputStream dataOutputStream;
InputStream inputStream;
InputStreamReader inputStreamReader;
socket.setSoTimeout(this.timeout); final DataInputStream in = new DataInputStream(socket.getInputStream());
final DataOutputStream out = new DataOutputStream(socket.getOutputStream());
socket.connect(new InetSocketAddress(this.getAddress(), this.getPort()), this.getTimeout()); //> Handshake
ByteArrayOutputStream handshake_bytes = new ByteArrayOutputStream();
DataOutputStream handshake = new DataOutputStream(handshake_bytes);
outputStream = socket.getOutputStream(); handshake.writeByte(PACKET_HANDSHAKE);
dataOutputStream = new DataOutputStream(outputStream); writeVarInt(handshake, PROTOCOL_VERSION);
writeVarInt(handshake, getAddress().length());
handshake.writeBytes(getAddress());
handshake.writeShort(getPort());
writeVarInt(handshake, STATUS_HANDSHAKE);
inputStream = socket.getInputStream(); writeVarInt(out, handshake_bytes.size());
inputStreamReader = new InputStreamReader(inputStream, Charset.forName("UTF-16BE")); out.write(handshake_bytes.toByteArray());
dataOutputStream.write(new byte[] { (byte) 0xFE, (byte) 0x01 }); //> Status request
int packetId = inputStream.read(); out.writeByte(0x01); // Size of packet
out.writeByte(PACKET_STATUSREQUEST);
if (packetId == -1) { throw new IOException("Premature end of stream."); } //< Status response
if (packetId != 0xFF) { throw new IOException("Invalid packet ID (" + packetId + ")."); } readVarInt(in); // Size
int id = readVarInt(in);
int length = inputStreamReader.read(); int length = readVarInt(in);
if (length == -1) { throw new IOException("Premature end of stream."); } byte[] data = new byte[length];
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);
if (length == 0) { throw new IOException("Invalid string length."); } // Close
handshake.close();
char[] chars = new char[length]; handshake_bytes.close();
out.close();
if (inputStreamReader.read(chars, 0, length) != length) { throw new IOException("Premature end of stream."); } in.close();
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 = "获取失败!";
@ -124,44 +146,36 @@ public class ServerInfo {
return true; return true;
} }
public String getAddress() { /**
return this.address; * @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;
} }
public int getPort() { /**
return this.port; * @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);
public void setTimeout(int timeout) { paramInt >>>= 7;
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;
}
} }

View File

@ -0,0 +1,20 @@
package pw.yumc.YumCore.mc;
import org.junit.Test;
import lombok.val;
/**
* Created with IntelliJ IDEA
*
* @author
* Created on 2017/9/28 18:50.
*/
public class ServerInfoTest {
@Test
public void test() {
val info = new ServerInfo("play.i5mc.com");
info.fetchData();
}
}