generated from mingliqiye/lib-tem
This commit is contained in:
parent
07150a4827
commit
9796338c72
@ -38,6 +38,8 @@ dependencies {
|
|||||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||||
implementation("org.jetbrains:annotations:24.0.0")
|
implementation("org.jetbrains:annotations:24.0.0")
|
||||||
annotationProcessor("org.jetbrains:annotations:24.0.0")
|
annotationProcessor("org.jetbrains:annotations:24.0.0")
|
||||||
|
implementation("com.alibaba.fastjson2:fastjson2:2.0.57")
|
||||||
|
implementation("com.mingliqiye:network-endpoint:1.0.3")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.test {
|
tasks.test {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
GROUPSID=com.mingliqiye
|
GROUPSID=com.mingliqiye
|
||||||
ARTIFACTID=socket-utilts
|
ARTIFACTID=minecraft-SLP
|
||||||
VERSIONS=1.0.1
|
VERSIONS=1.0.1
|
||||||
MAINCLASS=com.mingliqiye.Main
|
MAINCLASS=com.mingliqiye.minecraftSLP.Main
|
||||||
JDKVERSIONS=1.8
|
JDKVERSIONS=1.8
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
package com.mingliqiye;
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
/**
|
|
||||||
* @param args []
|
|
||||||
*/
|
|
||||||
public static void main(String[] args) {
|
|
||||||
System.out.print("Hello and welcome!");
|
|
||||||
for (int i = 1; i <= 5; i++) {
|
|
||||||
System.out.println("i = " + i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
69
src/main/java/com/mingliqiye/minecraftSLP/Main.java
Normal file
69
src/main/java/com/mingliqiye/minecraftSLP/Main.java
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package com.mingliqiye.minecraftSLP;
|
||||||
|
|
||||||
|
import com.mingliqiye.network.endpoint.NetworkEndpoint;
|
||||||
|
import com.mingliqiye.network.endpoint.NetworkException;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
if (args.length != 1) {
|
||||||
|
System.err.println("请使用 {地址}:{端口号}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
NetworkEndpoint networkEndpoints = NetworkEndpoint.of(args[0]);
|
||||||
|
MinecraftServerStatus minecraftServerStatus = SLP.getServerStatus(
|
||||||
|
networkEndpoints
|
||||||
|
);
|
||||||
|
System.out.printf(
|
||||||
|
"服务器 %s %n",
|
||||||
|
networkEndpoints.toHostPortString()
|
||||||
|
);
|
||||||
|
System.out.printf(
|
||||||
|
"版本号 %s 协议版本 %s %n",
|
||||||
|
minecraftServerStatus.getVersion().getName(),
|
||||||
|
minecraftServerStatus.getVersion().getProtocol()
|
||||||
|
);
|
||||||
|
System.out.printf(
|
||||||
|
"描述信息 %s %n",
|
||||||
|
minecraftServerStatus.getDescription().getText()
|
||||||
|
);
|
||||||
|
System.out.printf(
|
||||||
|
"玩家数 %s/%s %n",
|
||||||
|
minecraftServerStatus.getPlayers().getOnline(),
|
||||||
|
minecraftServerStatus.getPlayers().getMax()
|
||||||
|
);
|
||||||
|
if (minecraftServerStatus.getPlayers().getOnline() != 0) {
|
||||||
|
System.out.println("在线玩家:");
|
||||||
|
minecraftServerStatus
|
||||||
|
.getPlayers()
|
||||||
|
.getSample()
|
||||||
|
.forEach(v -> {
|
||||||
|
System.out.printf(
|
||||||
|
"玩家 %s UUID %s %n",
|
||||||
|
v.getName(),
|
||||||
|
v.getId()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
System.out.println("源数据:");
|
||||||
|
System.out.println(minecraftServerStatus.getJsonData());
|
||||||
|
} catch (NetworkException e) {
|
||||||
|
System.err.printf(
|
||||||
|
"服务器地址 %s DNS 查询失败 %s %s %n",
|
||||||
|
args[0],
|
||||||
|
e.getClass().getName(),
|
||||||
|
e.getMessage()
|
||||||
|
);
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.printf(
|
||||||
|
"%s 查询失败 %s %s %n",
|
||||||
|
args[0],
|
||||||
|
e.getClass().getName(),
|
||||||
|
e.getMessage()
|
||||||
|
);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,234 @@
|
|||||||
|
package com.mingliqiye.minecraftSLP;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class MinecraftServerStatus {
|
||||||
|
|
||||||
|
private Description description;
|
||||||
|
private Players players;
|
||||||
|
private Version version;
|
||||||
|
private String favicon;
|
||||||
|
private boolean enforcesSecureChat;
|
||||||
|
private boolean previewsChat;
|
||||||
|
private String jsonData;
|
||||||
|
|
||||||
|
// Getters and Setters
|
||||||
|
public Description getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(Description description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Players getPlayers() {
|
||||||
|
return players;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPlayers(Players players) {
|
||||||
|
this.players = players;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Version getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVersion(Version version) {
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFavicon() {
|
||||||
|
return favicon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFavicon(String favicon) {
|
||||||
|
this.favicon = favicon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnforcesSecureChat() {
|
||||||
|
return enforcesSecureChat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnforcesSecureChat(boolean enforcesSecureChat) {
|
||||||
|
this.enforcesSecureChat = enforcesSecureChat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPreviewsChat() {
|
||||||
|
return previewsChat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPreviewsChat(boolean previewsChat) {
|
||||||
|
this.previewsChat = previewsChat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJsonData() {
|
||||||
|
return jsonData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJsonData(String jsonData) {
|
||||||
|
this.jsonData = jsonData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nested Classes
|
||||||
|
public static class Description {
|
||||||
|
|
||||||
|
private String text;
|
||||||
|
private Extra[] extra;
|
||||||
|
|
||||||
|
public String getText() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setText(String text) {
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Extra> getExtra() {
|
||||||
|
return Arrays.asList(extra);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExtra(Extra[] extra) {
|
||||||
|
this.extra = extra;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Extra {
|
||||||
|
|
||||||
|
private String text;
|
||||||
|
private String color;
|
||||||
|
private Boolean bold;
|
||||||
|
private Boolean italic;
|
||||||
|
|
||||||
|
// 其他样式字段...
|
||||||
|
|
||||||
|
public String getText() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setText(String text) {
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor(String color) {
|
||||||
|
this.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getBold() {
|
||||||
|
return bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBold(Boolean bold) {
|
||||||
|
this.bold = bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getItalic() {
|
||||||
|
return italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setItalic(Boolean italic) {
|
||||||
|
this.italic = italic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Players {
|
||||||
|
|
||||||
|
private int max;
|
||||||
|
private int online;
|
||||||
|
private PlayerSample[] sample;
|
||||||
|
|
||||||
|
public int getMax() {
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMax(int max) {
|
||||||
|
this.max = max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getOnline() {
|
||||||
|
return online;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnline(int online) {
|
||||||
|
this.online = online;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<PlayerSample> getSample() {
|
||||||
|
return Arrays.asList(sample);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSample(PlayerSample[] sample) {
|
||||||
|
this.sample = sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PlayerSample {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return String.format(
|
||||||
|
"Player(name=%s,id=%s)",
|
||||||
|
getName(),
|
||||||
|
getId()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Version {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private int protocol;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getProtocol() {
|
||||||
|
return protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProtocol(int protocol) {
|
||||||
|
this.protocol = protocol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 实用方法
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format(
|
||||||
|
"Version: %s (Protocol %d), Players: %d/%d, Description: %s",
|
||||||
|
version != null ? version.name : "?",
|
||||||
|
version != null ? version.protocol : 0,
|
||||||
|
players != null ? players.online : 0,
|
||||||
|
players != null ? players.max : 0,
|
||||||
|
description != null ? description.text : ""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
166
src/main/java/com/mingliqiye/minecraftSLP/SLP.java
Normal file
166
src/main/java/com/mingliqiye/minecraftSLP/SLP.java
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
package com.mingliqiye.minecraftSLP;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.mingliqiye.network.endpoint.NetworkEndpoint;
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
|
public class SLP {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 int32 4个字节 转换为 short 2 个字节
|
||||||
|
* @param value int32
|
||||||
|
* @return short
|
||||||
|
*/
|
||||||
|
public static byte[] toUnsignedShort(int value) {
|
||||||
|
byte[] array = new byte[2];
|
||||||
|
ByteBuffer.wrap(array, 0, 2)
|
||||||
|
.order(ByteOrder.BIG_ENDIAN)
|
||||||
|
.putShort((short) (value & 0xFFFF));
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 和服务器握手使用的字节
|
||||||
|
* @param serverIP 服务器地址
|
||||||
|
* @param serverPort 服务器端口号
|
||||||
|
* @param type 类型 1为 Status
|
||||||
|
* @return 字节数组
|
||||||
|
*/
|
||||||
|
public static byte[] getHandshakePack(
|
||||||
|
String serverIP,
|
||||||
|
int serverPort,
|
||||||
|
int type
|
||||||
|
) throws IOException {
|
||||||
|
ByteArrayOutputStream pack = new ByteArrayOutputStream();
|
||||||
|
ByteArrayOutputStream byteArrayOutputStream =
|
||||||
|
new ByteArrayOutputStream();
|
||||||
|
pack.write(0x00);
|
||||||
|
pack.write(toVarInt(1156));
|
||||||
|
byte[] sip = serverIP.getBytes();
|
||||||
|
pack.write(toVarInt(sip.length));
|
||||||
|
pack.write(sip);
|
||||||
|
pack.write(toUnsignedShort(serverPort));
|
||||||
|
pack.write(toVarInt(type));
|
||||||
|
byteArrayOutputStream.write(toVarInt(pack.size()));
|
||||||
|
byteArrayOutputStream.write(pack.toByteArray());
|
||||||
|
|
||||||
|
return byteArrayOutputStream.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取信息的字节 是固定值
|
||||||
|
* @return 信息的字节
|
||||||
|
*/
|
||||||
|
public static byte[] getStatusPack() {
|
||||||
|
return new byte[] { 0x01, 0x00 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从输入流中读取 服务器信息
|
||||||
|
* @param inputStream 输入流
|
||||||
|
* @return 服务器信息实体
|
||||||
|
* @throws IOException 读取错误
|
||||||
|
*/
|
||||||
|
public static MinecraftServerStatus getStatusJsonEntity(
|
||||||
|
DataInputStream inputStream
|
||||||
|
) throws IOException {
|
||||||
|
readVarInt(inputStream);
|
||||||
|
inputStream.readByte();
|
||||||
|
int lengthjson = readVarInt(inputStream);
|
||||||
|
byte[] data = new byte[lengthjson];
|
||||||
|
inputStream.readFully(data);
|
||||||
|
MinecraftServerStatus serverStatus = JSON.parseObject(
|
||||||
|
data,
|
||||||
|
MinecraftServerStatus.class
|
||||||
|
);
|
||||||
|
serverStatus.setJsonData(new String(data));
|
||||||
|
return serverStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从输入流中读取 varint 1-5字节
|
||||||
|
* @param in 输入流
|
||||||
|
* @return int
|
||||||
|
* @throws IOException 读取错误
|
||||||
|
*/
|
||||||
|
public static int readVarInt(DataInputStream in) throws IOException {
|
||||||
|
int value = 0;
|
||||||
|
int length = 0;
|
||||||
|
byte currentByte;
|
||||||
|
do {
|
||||||
|
currentByte = in.readByte();
|
||||||
|
value |= (currentByte & 0x7F) << (length * 7);
|
||||||
|
length += 1;
|
||||||
|
if (length > 5) {
|
||||||
|
throw new RuntimeException("VarInt too long");
|
||||||
|
}
|
||||||
|
} while ((currentByte & 0x80) != 0);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将int32转换为 1-5个字节的 varint
|
||||||
|
* @param value int32
|
||||||
|
* @return varint 字节数组
|
||||||
|
*/
|
||||||
|
public static byte[] toVarInt(int value) {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
while (true) {
|
||||||
|
if ((value & 0xFFFFFF80) == 0) {
|
||||||
|
buffer.write(value); // 写入单个字节
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buffer.write((value & 0x7F) | 0x80); // 写入字节并设置继续位
|
||||||
|
value >>>= 7;
|
||||||
|
}
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Socket getNewConnect(NetworkEndpoint networkEndpoint)
|
||||||
|
throws IOException {
|
||||||
|
Socket socket = new Socket();
|
||||||
|
socket.setSoTimeout(5000);
|
||||||
|
socket.connect(networkEndpoint.toInetSocketAddress());
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param s 域名IP+端口号字符串 示例 "127.0.0.1:25565"
|
||||||
|
* @return MinecraftServerStatus 服务器回执状态实体
|
||||||
|
* @throws IOException 网络错误
|
||||||
|
*/
|
||||||
|
public static MinecraftServerStatus getServerStatus(String s)
|
||||||
|
throws IOException {
|
||||||
|
return getServerStatus(NetworkEndpoint.of(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param s 域名IP
|
||||||
|
* @param i 端口号
|
||||||
|
* @return MinecraftServerStatus 服务器回执状态实体
|
||||||
|
* @throws IOException 网络错误
|
||||||
|
*/
|
||||||
|
public static MinecraftServerStatus getServerStatus(String s, Integer i)
|
||||||
|
throws IOException {
|
||||||
|
return getServerStatus(NetworkEndpoint.of(s, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param e 域名IP+端口号实例
|
||||||
|
* @return MinecraftServerStatus 服务器回执状态实体
|
||||||
|
* @throws IOException 网络错误
|
||||||
|
* @see NetworkEndpoint
|
||||||
|
*/
|
||||||
|
public static MinecraftServerStatus getServerStatus(NetworkEndpoint e)
|
||||||
|
throws IOException {
|
||||||
|
Socket socket = getNewConnect(e);
|
||||||
|
OutputStream out = socket.getOutputStream();
|
||||||
|
DataInputStream in = new DataInputStream(socket.getInputStream());
|
||||||
|
out.write(getHandshakePack(e.getHost(), e.getPort(), 1));
|
||||||
|
out.write(getStatusPack());
|
||||||
|
return getStatusJsonEntity(in);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user