diff --git a/libs.gradle b/libs.gradle
index 33ed495..fc2589b 100644
--- a/libs.gradle
+++ b/libs.gradle
@@ -15,7 +15,8 @@ ext {
lang3 : 'org.apache.commons:commons-lang3:3.11',
netty : 'io.netty:netty-all:4.1.22.Final',
reactor : 'io.projectreactor:reactor-core:3.4.5',
- yaml : 'org.yaml:snakeyaml:1.28'
+ yaml : 'org.yaml:snakeyaml:1.28',
+ json : 'com.eclipsesource.minimal-json:minimal-json:0.9.5'
]
libs.logger = [
diff --git a/protocol/build.gradle b/protocol/build.gradle
index 4677d8a..1a4110a 100644
--- a/protocol/build.gradle
+++ b/protocol/build.gradle
@@ -4,6 +4,7 @@ dependencies {
implementation libs.netty
implementation libs.reactor
implementation libs.guava
+ implementation libs.json
testImplementation libs.lang3
}
diff --git a/protocol/src/main/java/mc/protocol/State.java b/protocol/src/main/java/mc/protocol/State.java
index 0190377..b849adf 100644
--- a/protocol/src/main/java/mc/protocol/State.java
+++ b/protocol/src/main/java/mc/protocol/State.java
@@ -10,7 +10,7 @@ import mc.protocol.packets.client.HandshakePacket;
import mc.protocol.packets.client.LoginStartPacket;
import mc.protocol.packets.client.StatusServerRequestPacket;
import mc.protocol.packets.server.DisconnectPacket;
-import mc.protocol.packets.server.StatusServerResponsePacket;
+import mc.protocol.packets.server.StatusServerResponse;
import javax.annotation.Nullable;
import java.util.Collections;
@@ -31,7 +31,7 @@ public enum State {
),
// server side
Map.of(
- StatusServerResponsePacket.class, 0x00,
+ StatusServerResponse.class, 0x00,
PingPacket.class, 0x01
)
),
diff --git a/protocol/src/main/java/mc/protocol/model/ServerInfo.java b/protocol/src/main/java/mc/protocol/model/ServerInfo.java
new file mode 100644
index 0000000..002d52b
--- /dev/null
+++ b/protocol/src/main/java/mc/protocol/model/ServerInfo.java
@@ -0,0 +1,47 @@
+package mc.protocol.model;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+import lombok.RequiredArgsConstructor;
+import lombok.EqualsAndHashCode;
+
+import java.util.List;
+
+@Getter
+@Setter
+@ToString
+public class ServerInfo {
+
+ private final Version version = new Version();
+ private final Players players = new Players();
+
+ private String description;
+ private String favicon;
+
+ @Getter
+ @Setter
+ @ToString
+ public static class Version {
+ private String name;
+ private int protocol;
+ }
+
+ @Getter
+ @Setter
+ @ToString
+ public static class Players {
+ private int max;
+ private int online;
+ private List Структура пакета Пример JSON Reason Пример: Информация о сервере Структура пакета
+ * Пример JSON Response Информация о сервере Структура пакета
- *
- * | FIELD | TYPE | NOTES |
- * |--------|------|----------------------------------|
- * | Reason | Text | Причина отключения. Опционально. |
+ * | FIELD | TYPE | NOTES |
+ * |-------------|--------|----------------------------------|
+ * | JSON Reason | String | Причина отключения. Опционально. |
+ *
+ *
+ *
+ * {
+ * "text": "foo"
+ * }
*
*
* @see Disconnect
@@ -25,18 +33,11 @@ public class DisconnectPacket implements ServerSidePacket {
/**
* Причина отключения.
- *
- *
- * {
- * "text": "foo"
- * }
- *
*/
private String reason;
@Override
public void writeSelf(NetByteBuf netByteBuf) {
- netByteBuf.writeString(reason);
+ netByteBuf.writeString(Json.object().add("text", reason).toString());
}
}
diff --git a/protocol/src/main/java/mc/protocol/packets/server/StatusServerResponse.java b/protocol/src/main/java/mc/protocol/packets/server/StatusServerResponse.java
new file mode 100644
index 0000000..a238d20
--- /dev/null
+++ b/protocol/src/main/java/mc/protocol/packets/server/StatusServerResponse.java
@@ -0,0 +1,92 @@
+package mc.protocol.packets.server;
+
+import com.eclipsesource.json.Json;
+import com.eclipsesource.json.JsonArray;
+import com.eclipsesource.json.JsonObject;
+import com.google.common.collect.Streams;
+import lombok.Data;
+import mc.protocol.io.NetByteBuf;
+import mc.protocol.model.ServerInfo;
+import mc.protocol.packets.ServerSidePacket;
+
+import java.util.stream.Collector;
+
+/**
+ * Status server packet, response.
+ *
+ *
+ * | FIELD | TYPE | NOTES |
+ * |---------------|--------|-----------------------------------------|
+ * | JSON Response | String | Информация о сервере в JSON формате [1] |
+ *
+ * [1] - Server List Ping: Response
+ *
+ *
+ *
+ * {
+ * "version": {
+ * "name": "1.8.7",
+ * "protocol": 47
+ * },
+ * "players": {
+ * "max": 100,
+ * "online": 5,
+ * "sample": [
+ * {
+ * "name": "thinkofdeath",
+ * "id": "4566e69f-c907-48ee-8d71-d7ba5aa00d20"
+ * }
+ * ]
+ * },
+ * "description": {
+ * "text": "Hello world"
+ * },
+ * "favicon": "data:image/png;base64,<data>"
+ * }
+ *
+ */
+@Data
+public class StatusServerResponse implements ServerSidePacket {
+
+ /**
+ * Информация о серере.
+ */
+ private ServerInfo info;
+
+ @Override
+ public void writeSelf(NetByteBuf netByteBuf) {
+ netByteBuf.writeString(Json.object()
+ .add("version", createVersionObj())
+ .add("players", createPlayersObj())
+ .add("description", Json.object().add("text", info.description()))
+ .toString());
+ }
+
+ private JsonObject createVersionObj() {
+ return Json.object()
+ .add("name", info.version().name())
+ .add("protocol", info.version().protocol());
+ }
+
+ private JsonObject createPlayersObj() {
+ JsonArray sampleArr = info.players().sample().stream()
+ .map(samplePlayer -> Json.object()
+ .add("name", samplePlayer.name())
+ .add("id", samplePlayer.id()))
+ .collect(Collector.of(Json::array, JsonArray::add, StatusServerResponse::jsonArrayAddAll));
+
+ return Json.object()
+ .add("max", info.players().max())
+ .add("online", info.players().online())
+ .add("sample", sampleArr);
+ }
+
+ private static JsonArray jsonArrayAddAll(JsonArray jsonArrayTo, JsonArray jsonArrayFrom) {
+ Streams.stream(jsonArrayFrom).forEach(jsonArrayTo::add);
+ return jsonArrayTo;
+ }
+}
diff --git a/protocol/src/main/java/mc/protocol/packets/server/StatusServerResponsePacket.java b/protocol/src/main/java/mc/protocol/packets/server/StatusServerResponsePacket.java
deleted file mode 100644
index fd6b4ef..0000000
--- a/protocol/src/main/java/mc/protocol/packets/server/StatusServerResponsePacket.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package mc.protocol.packets.server;
-
-import lombok.Data;
-import mc.protocol.io.NetByteBuf;
-import mc.protocol.packets.ServerSidePacket;
-
-/**
- * Status server packet, response.
- *
- *
- * | FIELD | TYPE | NOTES |
- * |---------------|--------|-----------------------------------------|
- * | JSON Response | String | Информация о сервере в JSON формате [1] |
- *
- * [1] - Server List Ping: Response
- *
Пример
- *
- * {
- * "version": {
- * "name": "1.8.7",
- * "protocol": 47
- * },
- * "players": {
- * "max": 100,
- * "online": 5,
- * "sample": [
- * {
- * "name": "thinkofdeath",
- * "id": "4566e69f-c907-48ee-8d71-d7ba5aa00d20"
- * }
- * ]
- * },
- * "description": {
- * "text": "Hello world"
- * },
- * "favicon": "data:image/png;base64,<data>"
- * }
- *
- */
- private String info;
-
- @Override
- public void writeSelf(NetByteBuf netByteBuf) {
- netByteBuf.writeString(info);
- }
-}
diff --git a/server/src/main/java/mc/server/Main.java b/server/src/main/java/mc/server/Main.java
index 156aceb..0592fa1 100644
--- a/server/src/main/java/mc/server/Main.java
+++ b/server/src/main/java/mc/server/Main.java
@@ -3,18 +3,20 @@ package mc.server;
import lombok.extern.slf4j.Slf4j;
import mc.protocol.NettyServer;
import mc.protocol.ProtocolConstant;
+import mc.protocol.model.ServerInfo;
import mc.protocol.packets.PingPacket;
import mc.protocol.packets.client.HandshakePacket;
import mc.protocol.packets.client.LoginStartPacket;
import mc.protocol.packets.client.StatusServerRequestPacket;
import mc.protocol.packets.server.DisconnectPacket;
-import mc.protocol.packets.server.StatusServerResponsePacket;
+import mc.protocol.packets.server.StatusServerResponse;
import mc.server.config.Config;
import mc.server.di.ConfigModule;
import mc.server.di.DaggerServerComponent;
import mc.server.di.ServerComponent;
import java.nio.file.Paths;
+import java.util.Collections;
@Slf4j
public class Main {
@@ -48,21 +50,16 @@ public class Main {
server.packetFlux(StatusServerRequestPacket.class)
.doOnNext(channel -> log.info("{}", channel.getPacket()))
.subscribe(channel -> {
- StatusServerResponsePacket response = new StatusServerResponsePacket();
- response.setInfo("{\n" +
- " \"version\": {\n" +
- " \"name\": \"" + ProtocolConstant.PROTOCOL_NAME + "\",\n" +
- " \"protocol\": " + ProtocolConstant.PROTOCOL_NUMBER + "\n" +
- " },\n" +
- " \"players\": {\n" +
- " \"max\": " + config.players().maxOnlile() + ",\n" +
- " \"online\": " + config.players().onlile() + ",\n" +
- " \"sample\": []\n" +
- " },\n" +
- " \"description\": {\n" +
- " \"text\": \"" + config.motd() + "\"\n" +
- " }\n" +
- "}");
+ ServerInfo serverInfo = new ServerInfo();
+ serverInfo.version().name(ProtocolConstant.PROTOCOL_NAME);
+ serverInfo.version().protocol(ProtocolConstant.PROTOCOL_NUMBER);
+ serverInfo.players().max(config.players().maxOnlile());
+ serverInfo.players().online(config.players().onlile());
+ serverInfo.players().sample(Collections.emptyList());
+ serverInfo.description(config.motd());
+
+ StatusServerResponse response = new StatusServerResponse();
+ response.setInfo(serverInfo);
channel.getCtx().writeAndFlush(response);
});
@@ -71,9 +68,7 @@ public class Main {
.doOnNext(channel -> log.info("{}", channel.getPacket()))
.subscribe(channel -> {
DisconnectPacket disconnectPacket = new DisconnectPacket();
- disconnectPacket.setReason("{\n" +
- " \"text\": \"Server is not available.\"\n" +
- "}");
+ disconnectPacket.setReason("Server is not available.");
channel.getCtx().writeAndFlush(disconnectPacket).channel().disconnect();
});