From a9b053765e0a9f9cd9d1504072e60629db63109e Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Sat, 24 Apr 2021 21:29:51 +0300 Subject: [PATCH 01/34] dummy server --- build.gradle | 5 ++ src/main/java/mc/server/Main.java | 7 ++ .../java/mc/server/di/NetworkComponent.java | 10 +++ src/main/java/mc/server/di/NetworkModule.java | 71 +++++++++++++++++++ src/main/java/mc/server/network/Server.java | 6 ++ .../mc/server/network/netty/NettyServer.java | 27 +++++++ 6 files changed, 126 insertions(+) create mode 100644 src/main/java/mc/server/di/NetworkComponent.java create mode 100644 src/main/java/mc/server/di/NetworkModule.java create mode 100644 src/main/java/mc/server/network/Server.java create mode 100644 src/main/java/mc/server/network/netty/NettyServer.java diff --git a/build.gradle b/build.gradle index 23c4b67..7e6b85d 100644 --- a/build.gradle +++ b/build.gradle @@ -38,6 +38,11 @@ dependencies { implementation libs.dagger2.implementation annotationProcessor libs.dagger2.annotationProcessor + + implementation platform('io.projectreactor:reactor-bom:2020.0.6') + implementation 'io.projectreactor:reactor-core' + + implementation 'io.netty:netty-all:4.1.22.Final' } application.mainClassName = 'mc.server.Main' \ No newline at end of file diff --git a/src/main/java/mc/server/Main.java b/src/main/java/mc/server/Main.java index bde95b3..bd5f9f7 100644 --- a/src/main/java/mc/server/Main.java +++ b/src/main/java/mc/server/Main.java @@ -1,11 +1,18 @@ package mc.server; import lombok.extern.slf4j.Slf4j; +import mc.server.di.DaggerNetworkComponent; +import mc.server.di.NetworkComponent; +import mc.server.network.Server; @Slf4j public class Main { public static void main(String[] args) { log.info("hello"); + + NetworkComponent networkComponent = DaggerNetworkComponent.create(); + Server server = networkComponent.getServer(); + server.start("127.0.0.1", 25565); } } diff --git a/src/main/java/mc/server/di/NetworkComponent.java b/src/main/java/mc/server/di/NetworkComponent.java new file mode 100644 index 0000000..ae73ed9 --- /dev/null +++ b/src/main/java/mc/server/di/NetworkComponent.java @@ -0,0 +1,10 @@ +package mc.server.di; + +import dagger.Component; +import mc.server.network.Server; + +@Component(modules = NetworkModule.class) +public interface NetworkComponent { + + Server getServer(); +} diff --git a/src/main/java/mc/server/di/NetworkModule.java b/src/main/java/mc/server/di/NetworkModule.java new file mode 100644 index 0000000..aae8cb4 --- /dev/null +++ b/src/main/java/mc/server/di/NetworkModule.java @@ -0,0 +1,71 @@ +package mc.server.di; + +import dagger.Module; +import dagger.Provides; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.logging.LoggingHandler; +import mc.server.network.Server; +import mc.server.network.netty.NettyServer; + +import javax.inject.Named; +import java.util.Collections; +import java.util.List; + +@Module +public class NetworkModule { + + @Provides + Server provideServer(ServerBootstrap serverBootstrap) { + return new NettyServer(serverBootstrap); + } + + @Provides + ServerBootstrap provideServerBootstrap( + @Named("boss-group") EventLoopGroup bossGroup, + @Named("worker-group") EventLoopGroup workerGroup, + ChannelInitializer channelChannelInitializer + ) { + ServerBootstrap bootstrap = new ServerBootstrap(); + + bootstrap.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .childHandler(channelChannelInitializer); + + return bootstrap; + } + + @Provides + @Named("boss-group") + EventLoopGroup provideBossGroup() { + return new NioEventLoopGroup(1); + } + + @Provides + @Named("worker-group") + EventLoopGroup provideWorkerGroup() { + return new NioEventLoopGroup(); + } + + @Provides + ChannelInitializer provideChannelChannelInitializer(List channelHandlerList) { + return new ChannelInitializer<>() { + @Override + protected void initChannel(SocketChannel socketChannel) { + final ChannelPipeline pipeline = socketChannel.pipeline(); + channelHandlerList.forEach(pipeline::addLast); + } + }; + } + + @Provides + List provideChannelHandlerList() { + return Collections.singletonList(new LoggingHandler()); + } +} diff --git a/src/main/java/mc/server/network/Server.java b/src/main/java/mc/server/network/Server.java new file mode 100644 index 0000000..f1464f8 --- /dev/null +++ b/src/main/java/mc/server/network/Server.java @@ -0,0 +1,6 @@ +package mc.server.network; + +public interface Server { + + void start(String host, int port); +} diff --git a/src/main/java/mc/server/network/netty/NettyServer.java b/src/main/java/mc/server/network/netty/NettyServer.java new file mode 100644 index 0000000..4c3d19e --- /dev/null +++ b/src/main/java/mc/server/network/netty/NettyServer.java @@ -0,0 +1,27 @@ +package mc.server.network.netty; + +import io.netty.bootstrap.ServerBootstrap; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import mc.server.network.Server; + +@Slf4j +@RequiredArgsConstructor +public class NettyServer implements Server { + + private final ServerBootstrap serverBootstrap; + + @Override + public void start(String host, int port) { + log.info("Network starting: {}:{}", host, port); + + try { + serverBootstrap.bind(host, port) + .sync().channel().closeFuture().sync(); + } catch (InterruptedException e) { + if (log.isTraceEnabled()) { + log.trace("{}: {}", e.getClass().getSimpleName(), e.getMessage(), e); + } + } + } +} From f10af6ae69297aaa4a176b80cc4a288f7f30fe95 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Sun, 25 Apr 2021 19:01:04 +0300 Subject: [PATCH 02/34] =?UTF-8?q?=D0=BE=D1=82=D0=BE=D0=B1=D1=80=D0=B0?= =?UTF-8?q?=D0=B6=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B8=D0=BD=D1=84=D0=BE=D1=80?= =?UTF-8?q?=D0=BC=D0=B0=D1=86=D0=B8=D0=B8=20=D0=BE=20=D1=81=D0=B5=D1=80?= =?UTF-8?q?=D0=B2=D0=B5=D1=80=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 15 +- .../gradle/extention/LibsExtention.java | 14 +- .../java/mc/protocol/NetworkAttributes.java | 10 + src/main/java/mc/protocol/State.java | 69 ++++ .../java/mc/protocol/io/DecoderException.java | 8 + src/main/java/mc/protocol/io/NetByteBuf.java | 183 +++++++++++ .../mc/protocol/io/codec/ProtocolDecoder.java | 59 ++++ .../mc/protocol/io/codec/ProtocolEncoder.java | 30 ++ .../protocol/io/codec/ProtocolSplitter.java | 40 +++ .../java/mc/protocol/packets/EmptyPacket.java | 16 + src/main/java/mc/protocol/packets/Packet.java | 24 ++ .../mc/protocol/packets/PacketDirection.java | 6 + .../mc/protocol/packets/UnknownPacket.java | 27 ++ .../packets/client/HandshakePacket.java | 57 ++++ .../packets/client/StatusServerRequest.java | 18 + .../packets/server/StatusServerResponse.java | 62 ++++ src/main/java/mc/server/Main.java | 2 +- src/main/java/mc/server/di/NetworkModule.java | 58 ++-- src/main/java/mc/server/network/Server.java | 2 +- .../network/netty/AbstractPacketHandler.java | 17 + .../network/netty/HandshakeHandler.java | 24 ++ .../mc/server/network/netty/NettyServer.java | 5 +- .../server/network/netty/StatusHandler.java | 33 ++ src/main/resources/logback.xml | 6 +- .../mc/protocol/io/NetByteBufReadTest.java | 307 ++++++++++++++++++ .../mc/protocol/io/NetByteBufWriteTest.java | 246 ++++++++++++++ 26 files changed, 1303 insertions(+), 35 deletions(-) create mode 100644 src/main/java/mc/protocol/NetworkAttributes.java create mode 100644 src/main/java/mc/protocol/State.java create mode 100644 src/main/java/mc/protocol/io/DecoderException.java create mode 100644 src/main/java/mc/protocol/io/NetByteBuf.java create mode 100644 src/main/java/mc/protocol/io/codec/ProtocolDecoder.java create mode 100644 src/main/java/mc/protocol/io/codec/ProtocolEncoder.java create mode 100644 src/main/java/mc/protocol/io/codec/ProtocolSplitter.java create mode 100644 src/main/java/mc/protocol/packets/EmptyPacket.java create mode 100644 src/main/java/mc/protocol/packets/Packet.java create mode 100644 src/main/java/mc/protocol/packets/PacketDirection.java create mode 100644 src/main/java/mc/protocol/packets/UnknownPacket.java create mode 100644 src/main/java/mc/protocol/packets/client/HandshakePacket.java create mode 100644 src/main/java/mc/protocol/packets/client/StatusServerRequest.java create mode 100644 src/main/java/mc/protocol/packets/server/StatusServerResponse.java create mode 100644 src/main/java/mc/server/network/netty/AbstractPacketHandler.java create mode 100644 src/main/java/mc/server/network/netty/HandshakeHandler.java create mode 100644 src/main/java/mc/server/network/netty/StatusHandler.java create mode 100644 src/test/java/mc/protocol/io/NetByteBufReadTest.java create mode 100644 src/test/java/mc/protocol/io/NetByteBufWriteTest.java diff --git a/build.gradle b/build.gradle index 7e6b85d..7de1955 100644 --- a/build.gradle +++ b/build.gradle @@ -43,6 +43,19 @@ dependencies { implementation 'io.projectreactor:reactor-core' implementation 'io.netty:netty-all:4.1.22.Final' + implementation libs.guava + + testImplementation libs.junit5.api + testImplementation libs.junit5.params + testRuntimeOnly libs.junit5.engine + + testImplementation libs.lang3 } -application.mainClassName = 'mc.server.Main' \ No newline at end of file +application { + mainClassName = 'mc.server.Main' +} + +test { + useJUnitPlatform() +} diff --git a/buildSrc/src/main/java/ru/dmitriymx/gradle/extention/LibsExtention.java b/buildSrc/src/main/java/ru/dmitriymx/gradle/extention/LibsExtention.java index 752fe92..05123ee 100644 --- a/buildSrc/src/main/java/ru/dmitriymx/gradle/extention/LibsExtention.java +++ b/buildSrc/src/main/java/ru/dmitriymx/gradle/extention/LibsExtention.java @@ -6,8 +6,12 @@ public class LibsExtention { public final String lombok = "org.projectlombok:lombok:1.18.12"; public final String annotations = "com.google.code.findbugs:jsr305:3.0.2"; + public final String guava = "com.google.guava:guava:30.1-jre"; + public final String lang3 = "org.apache.commons:commons-lang3:3.11"; + public final LoggerLibs logger = new LoggerLibs(); public final Dagger2Libs dagger2 = new Dagger2Libs(); + public final Junit5Libs junit5 = new Junit5Libs(); public static final class LoggerLibs { private final String slf4j_version = "1.7.30"; @@ -17,7 +21,6 @@ public class LibsExtention { "org.slf4j:slf4j-api:" + slf4j_version, "org.slf4j:jcl-over-slf4j:" + slf4j_version ); - public final String slf4j_simple = "org.slf4j:slf4j-simple:" + slf4j_version; public final List logback = List.of( "ch.qos.logback:logback-core:" + logback_version, @@ -31,4 +34,13 @@ public class LibsExtention { public final String implementation = "com.google.dagger:dagger:" + dagger2_version; public final String annotationProcessor = "com.google.dagger:dagger-compiler:" + dagger2_version; } + + public static final class Junit5Libs { + private final String junit_version = "5.5.2"; + + public final String api = "org.junit.jupiter:junit-jupiter-api:" + junit_version; + /** runtimeOnly */ + public final String engine = "org.junit.jupiter:junit-jupiter-engine:" + junit_version; + public final String params = "org.junit.jupiter:junit-jupiter-params:" + junit_version; + } } diff --git a/src/main/java/mc/protocol/NetworkAttributes.java b/src/main/java/mc/protocol/NetworkAttributes.java new file mode 100644 index 0000000..0be033c --- /dev/null +++ b/src/main/java/mc/protocol/NetworkAttributes.java @@ -0,0 +1,10 @@ +package mc.protocol; + +import io.netty.util.AttributeKey; +import lombok.experimental.UtilityClass; + +@UtilityClass +public class NetworkAttributes { + + public static final AttributeKey STATE = AttributeKey.newInstance("STATE"); +} diff --git a/src/main/java/mc/protocol/State.java b/src/main/java/mc/protocol/State.java new file mode 100644 index 0000000..da448e6 --- /dev/null +++ b/src/main/java/mc/protocol/State.java @@ -0,0 +1,69 @@ +package mc.protocol; + +import com.google.common.collect.BiMap; +import com.google.common.collect.ImmutableBiMap; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import mc.protocol.packets.Packet; +import mc.protocol.packets.PacketDirection; +import mc.protocol.packets.client.HandshakePacket; +import mc.protocol.packets.client.StatusServerRequest; +import mc.protocol.packets.server.StatusServerResponse; + +import javax.annotation.Nullable; + +@RequiredArgsConstructor +public enum State { + + HANDSHAKING(-1, + // server bound + ImmutableBiMap.of(0x00, HandshakePacket.class) + ), + STATUS(1, + // server bound + ImmutableBiMap.of(0x00, StatusServerRequest.class), + // client bound + ImmutableBiMap.of(0x00, StatusServerResponse.class) + ); + + @Nullable + public static State getById(int id) { + for (State state : State.values()) { + if (state.id == id) { + return state; + } + } + + return null; + } + + @Getter + private final int id; + + private final BiMap> serverBoundPackets; + private final BiMap> clientBoundPackets; + + State(int id, BiMap> serverBoundPackets) { + this.id = id; + this.serverBoundPackets = serverBoundPackets; + this.clientBoundPackets = ImmutableBiMap.of(); + } + + @Nullable + public Class getPacketById(PacketDirection direction, int id) { + if (PacketDirection.CLIENT_BOUND == direction) { + return clientBoundPackets == null ? null : clientBoundPackets.get(id); + } else { + return serverBoundPackets == null ? null : serverBoundPackets.get(id); + } + } + + @Nullable + public Integer getIdByPacket(PacketDirection direction, Class clazz) { + if (PacketDirection.CLIENT_BOUND == direction) { + return clientBoundPackets == null ? null : clientBoundPackets.inverse().get(clazz); + } else { + return serverBoundPackets == null ? null : serverBoundPackets.inverse().get(clazz); + } + } +} diff --git a/src/main/java/mc/protocol/io/DecoderException.java b/src/main/java/mc/protocol/io/DecoderException.java new file mode 100644 index 0000000..a30ee19 --- /dev/null +++ b/src/main/java/mc/protocol/io/DecoderException.java @@ -0,0 +1,8 @@ +package mc.protocol.io; + +public class DecoderException extends RuntimeException { + + public DecoderException(String message) { + super(message); + } +} diff --git a/src/main/java/mc/protocol/io/NetByteBuf.java b/src/main/java/mc/protocol/io/NetByteBuf.java new file mode 100644 index 0000000..d1c3638 --- /dev/null +++ b/src/main/java/mc/protocol/io/NetByteBuf.java @@ -0,0 +1,183 @@ +package mc.protocol.io; + +import io.netty.buffer.ByteBuf; +import lombok.EqualsAndHashCode; +import lombok.RequiredArgsConstructor; +import lombok.ToString; +import lombok.experimental.Delegate; +import lombok.extern.slf4j.Slf4j; + +import java.nio.charset.StandardCharsets; +import java.util.UUID; + +/** + * Компонент чтения и записи данных протокола. + * + *

Data types

+ *
+ * | TYPE           | SIZE (bytes)          | ENCODING                                            | NOTES                                                                    |
+ * |----------------|-----------------------|-----------------------------------------------------|--------------------------------------------------------------------------|
+ * | Boolean        | 1                     | True или False                                      | True = 0x01; False = 0x00                                                |
+ * | Byte           | 1                     | Число от -128 до 127                                | 8-bit число со знаком                                                    |
+ * | Unsigned Byte  | 1                     | Число от 0 до 255                                   | 8-bit без знаковое число                                                 |
+ * | Short          | 2                     | Число от -32768 до 32767                            | 16-bit число со знаком                                                   |
+ * | Unsigned Short | 2                     | Число от -32768 до 32767                            | 16-bit без знаковое число                                                |
+ * | Int            | 4                     | Число от -2147483648 и 2147483647                   | 32-bit число со знаком                                                   |
+ * | Long           | 8                     | Число от -9223372036854775808 и 9223372036854775807 | 64-bit число со знаком                                                   |
+ * | Float          | 4                     | 32-bit число одинарной точности (IEEE 754-2008)     | [1]                                                                      |
+ * | Double         | 8                     | 64-bit число одинарной точности (IEEE 754-2008)     | [2]                                                                      |
+ * | String (n)     | >= 1 ; <= (n * 4) + 3 | Последовательность Unicode scalar values            | В начале пишется длина строки в VarInt, после чего записываются символы. |
+ * |                |                       |                                                     | Каждый символ может состоять максимум из 4 байт. [3]                     |
+ * |                |                       |                                                     | Максимальная длина строки - 32767 (3 - это как раз размер VarInt для     |
+ * |                |                       |                                                     | этого числа).                                                            |
+ * | VarInt         | >= 1 ; <= 5           | Число от -2147483648 и 2147483647                   | 32-bit число с плавающей размерностью от 1 до 5 байт                     |
+ * | VarLong        | >= 1 ; <= 10          | Число от -9223372036854775808 и 9223372036854775807 | 64-bit число с плавающей размерностью от 1 до 10 байт                    |
+ *
+ * [1] - Single-precision floating-point format
+ * [2] - Double-precision floating-point format
+ * [3] - Unicode Scalar Value
+ * 
+ * + * @see Data types + */ +@Slf4j +@RequiredArgsConstructor +@EqualsAndHashCode(callSuper = false) +@ToString +public class NetByteBuf extends ByteBuf { + + @Delegate + private final ByteBuf byteBuf; + + //region String + public String readString() { + return readString(Short.MAX_VALUE); + } + + @SuppressWarnings("java:S131") + public String readString(int maxLength) { + int length = readVarInt(); + + if (length == 0) { + return ""; + } else if (length > maxLength) { + throw new DecoderException("String length exceeds maximum length: " + length + " > " + maxLength); + } else if (length < 0) { + throw new DecoderException("String length less zero!"); + } + + byte[] bytes = new byte[length * 4]; + int readbleBytes = 0; + for (int i = 0; i < length && readableBytes() > 0; i++) { + byte b = readByte(); + bytes[readbleBytes++] = b; + + switch ((b & 0xFF) >> 4) { + case 0b1100: + case 0b1101: + bytes[readbleBytes++] = readByte(); + break; + case 0b1110: + bytes[readbleBytes++] = readByte(); + bytes[readbleBytes++] = readByte(); + break; + case 0b1111: + bytes[readbleBytes++] = readByte(); + bytes[readbleBytes++] = readByte(); + bytes[readbleBytes++] = readByte(); + break; + } + } + + return new String(bytes, 0, readbleBytes, StandardCharsets.UTF_8); + } + + public void writeString(String string) { + byte[] buf; + int length = (int) string.codePoints().count(); + + if (length > Short.MAX_VALUE) { + log.warn("String is too long: {} > {}", length, Short.MAX_VALUE); + buf = string.substring(0, Short.MAX_VALUE).getBytes(StandardCharsets.UTF_8); + writeVarInt(Short.MAX_VALUE); + } else { + buf = string.getBytes(StandardCharsets.UTF_8); + writeVarInt(length); + } + + writeBytes(buf); + } + //endregion + + //region VarInt + public int readVarInt() { + int numRead = 0; + int result = 0; + byte read; + do { + if ((numRead + 1) > 5) { + log.warn("VarInt is too big"); + break; + } + read = readByte(); + int value = (read & 0b01111111); + result |= (value << (7 * numRead)); + + numRead++; + } while ((read & 0b10000000) != 0); + + return result; + } + + public void writeVarInt(int value) { + while ((value & -128) != 0) { + writeByte(value & 127 | 128); + value >>>= 7; + } + + writeByte(value); + } + //endregion + + //region VarLong + public long readVarLong() { + int numRead = 0; + long result = 0L; + byte read; + do { + if (numRead > 10) { + log.warn("VarLong is too big"); + break; + } + + read = readByte(); + long value = (read & 0b01111111); + result |= (value << (7 * numRead)); + + numRead++; + } while ((read & 0b10000000) != 0); + + return result; + } + + public void writeVarLong(long value) { + while ((value & -128L) != 0L) { + writeByte((int) (value & 127L) | 128); + value >>>= 7; + } + + writeByte((int) value); + } + //endregion + + //region UUID + public UUID readUUID() { + return new UUID(readLong(), readLong()); + } + + public void writeUUID(UUID uuid) { + writeLong(uuid.getMostSignificantBits()); + writeLong(uuid.getLeastSignificantBits()); + } + //endregion +} diff --git a/src/main/java/mc/protocol/io/codec/ProtocolDecoder.java b/src/main/java/mc/protocol/io/codec/ProtocolDecoder.java new file mode 100644 index 0000000..a59f5a0 --- /dev/null +++ b/src/main/java/mc/protocol/io/codec/ProtocolDecoder.java @@ -0,0 +1,59 @@ +package mc.protocol.io.codec; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import mc.protocol.NetworkAttributes; +import mc.protocol.State; +import mc.protocol.io.NetByteBuf; +import mc.protocol.packets.Packet; +import mc.protocol.packets.PacketDirection; +import mc.protocol.packets.UnknownPacket; + +import java.util.List; +import java.util.Objects; + +@Slf4j +@RequiredArgsConstructor +public class ProtocolDecoder extends ByteToMessageDecoder { + + private final boolean readUnknownPackets; + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + ctx.channel().attr(NetworkAttributes.STATE).set(State.HANDSHAKING); + super.channelActive(ctx); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + ctx.channel().attr(NetworkAttributes.STATE).set(null); + super.channelInactive(ctx); + } + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + State state = Objects.requireNonNull(ctx.channel().attr(NetworkAttributes.STATE).get()); + NetByteBuf netByteBuf = new NetByteBuf(in); + + int packetId = netByteBuf.readVarInt(); + Class packetClass = state.getPacketById(PacketDirection.SERVER_BOUND, packetId); + if (packetClass == null) { + log.warn("Unkown packet: State {} ; Id {}", state, packetId); + + if (readUnknownPackets) { + UnknownPacket unknownPacket = new UnknownPacket(state, packetId, netByteBuf.readableBytes()); + unknownPacket.readSelf(netByteBuf); + out.add(unknownPacket); + } else { + netByteBuf.skipBytes(netByteBuf.readableBytes()); + } + } else { + Packet packet = packetClass.getDeclaredConstructor().newInstance(); + packet.readSelf(netByteBuf); + out.add(packet); + } + } +} diff --git a/src/main/java/mc/protocol/io/codec/ProtocolEncoder.java b/src/main/java/mc/protocol/io/codec/ProtocolEncoder.java new file mode 100644 index 0000000..d26f26c --- /dev/null +++ b/src/main/java/mc/protocol/io/codec/ProtocolEncoder.java @@ -0,0 +1,30 @@ +package mc.protocol.io.codec; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToByteEncoder; +import mc.protocol.NetworkAttributes; +import mc.protocol.State; +import mc.protocol.io.NetByteBuf; +import mc.protocol.packets.Packet; +import mc.protocol.packets.PacketDirection; + +import java.util.Objects; + +public class ProtocolEncoder extends MessageToByteEncoder { + + @Override + protected void encode(ChannelHandlerContext ctx, Packet packet, ByteBuf out) { + State state = ctx.channel().attr(NetworkAttributes.STATE).get(); + int packetId = Objects.requireNonNull(state.getIdByPacket(PacketDirection.CLIENT_BOUND, packet.getClass())); + + NetByteBuf buffer = new NetByteBuf(Unpooled.buffer()); + buffer.writeVarInt(packetId); + packet.writeSelf(buffer); + + NetByteBuf netByteBuf = new NetByteBuf(out); + netByteBuf.writeVarInt(buffer.readableBytes()); + netByteBuf.writeBytes(buffer); + } +} diff --git a/src/main/java/mc/protocol/io/codec/ProtocolSplitter.java b/src/main/java/mc/protocol/io/codec/ProtocolSplitter.java new file mode 100644 index 0000000..452bb06 --- /dev/null +++ b/src/main/java/mc/protocol/io/codec/ProtocolSplitter.java @@ -0,0 +1,40 @@ +package mc.protocol.io.codec; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; +import mc.protocol.io.NetByteBuf; + +import java.util.List; + +public class ProtocolSplitter extends ByteToMessageDecoder { + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) { + NetByteBuf netByteBuf = new NetByteBuf(in); + netByteBuf.markReaderIndex(); + + do { + byte[] sizePacketRaw = new byte[3]; + for (int i = 0; i < 3; ++i) { + sizePacketRaw[i] = netByteBuf.readByte(); + + if (sizePacketRaw[i] >= 0) { + break; + } + } + + int sizePacket = new NetByteBuf(Unpooled.wrappedBuffer(sizePacketRaw)).readVarInt(); + + if (netByteBuf.readableBytes() >= sizePacket) { + byte[] bytes = new byte[sizePacket]; + netByteBuf.readBytes(bytes); + out.add(Unpooled.wrappedBuffer(bytes)); + } else { + netByteBuf.resetReaderIndex(); + break; + } + } while (netByteBuf.readableBytes() > 0); + } +} diff --git a/src/main/java/mc/protocol/packets/EmptyPacket.java b/src/main/java/mc/protocol/packets/EmptyPacket.java new file mode 100644 index 0000000..b6dd02f --- /dev/null +++ b/src/main/java/mc/protocol/packets/EmptyPacket.java @@ -0,0 +1,16 @@ +package mc.protocol.packets; + +import mc.protocol.io.NetByteBuf; + +public abstract class EmptyPacket implements Packet { + + @Override + public void readSelf(NetByteBuf netByteBuf) { + // empty + } + + @Override + public void writeSelf(NetByteBuf netByteBuf) { + // empty + } +} diff --git a/src/main/java/mc/protocol/packets/Packet.java b/src/main/java/mc/protocol/packets/Packet.java new file mode 100644 index 0000000..95e1385 --- /dev/null +++ b/src/main/java/mc/protocol/packets/Packet.java @@ -0,0 +1,24 @@ +package mc.protocol.packets; + +import mc.protocol.io.NetByteBuf; + +/** + * Пакет. + * + *

Структура пакета

+ *
+ * | FIELD       | TYPE   | NOTES                                     |
+ * |-------------|--------|-------------------------------------------|
+ * | SIZE        | VarInt | = sizeOf(PACKET ID) + sizeOf(PACKET DATA) |
+ * | PACKET ID   | VarInt |                                           |
+ * | PACKET DATA | bytes  |                                           |
+ * 
+ * + * @see Packet without compression + */ +public interface Packet { + + void readSelf(NetByteBuf netByteBuf); + + void writeSelf(NetByteBuf netByteBuf); +} diff --git a/src/main/java/mc/protocol/packets/PacketDirection.java b/src/main/java/mc/protocol/packets/PacketDirection.java new file mode 100644 index 0000000..2760689 --- /dev/null +++ b/src/main/java/mc/protocol/packets/PacketDirection.java @@ -0,0 +1,6 @@ +package mc.protocol.packets; + +public enum PacketDirection { + + SERVER_BOUND, CLIENT_BOUND +} diff --git a/src/main/java/mc/protocol/packets/UnknownPacket.java b/src/main/java/mc/protocol/packets/UnknownPacket.java new file mode 100644 index 0000000..04b4873 --- /dev/null +++ b/src/main/java/mc/protocol/packets/UnknownPacket.java @@ -0,0 +1,27 @@ +package mc.protocol.packets; + +import lombok.Data; +import lombok.ToString; +import mc.protocol.State; +import mc.protocol.io.NetByteBuf; + +@Data +@ToString(exclude = "rawData") +public class UnknownPacket implements Packet { + + private final State state; + private final int id; + private final int dataSize; + private byte[] rawData; + + @Override + public void readSelf(NetByteBuf netByteBuf) { + rawData = new byte[dataSize]; + netByteBuf.readBytes(rawData); + } + + @Override + public void writeSelf(NetByteBuf netByteBuf) { + netByteBuf.writeBytes(rawData); + } +} diff --git a/src/main/java/mc/protocol/packets/client/HandshakePacket.java b/src/main/java/mc/protocol/packets/client/HandshakePacket.java new file mode 100644 index 0000000..eb786bc --- /dev/null +++ b/src/main/java/mc/protocol/packets/client/HandshakePacket.java @@ -0,0 +1,57 @@ +package mc.protocol.packets.client; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import mc.protocol.State; +import mc.protocol.io.NetByteBuf; +import mc.protocol.packets.Packet; + +/** + * Handshake packet. + * + *

Данный пакет заставляет сервер переключить текущий {@link State}

+ * + *

Структура пакета

+ *
+ * | FIELD            | TYPE           | NOTES                                        |
+ * |------------------|----------------|----------------------------------------------|
+ * | Protocol version | VarInt         | Версия протокола [1]                         |
+ * | Server address   | Stirng         | Hostname или IP                              |
+ * | Server port      | Unsigned Short | Порт сервера                                 |
+ * | Next stage       | VarInt         | ID State на который необходимо переключиться |
+ *
+ * [1] - Protocol version numbers
+ * 
+ * + * @see Handshake + * @see State + */ +@NoArgsConstructor +@Getter +@EqualsAndHashCode +@ToString +public class HandshakePacket implements Packet { + + private int protocolVersion; + private String host; + private int port; + private State nextState; + + @Override + public void readSelf(NetByteBuf netByteBuf) { + protocolVersion = netByteBuf.readVarInt(); + host = netByteBuf.readString(255); + port = netByteBuf.readUnsignedShort(); + nextState = State.getById(netByteBuf.readVarInt()); + } + + @Override + public void writeSelf(NetByteBuf netByteBuf) { + netByteBuf.writeVarInt(protocolVersion); + netByteBuf.writeString(host); + netByteBuf.writeShort(port); + netByteBuf.writeVarInt(nextState.getId()); + } +} diff --git a/src/main/java/mc/protocol/packets/client/StatusServerRequest.java b/src/main/java/mc/protocol/packets/client/StatusServerRequest.java new file mode 100644 index 0000000..9cd1e61 --- /dev/null +++ b/src/main/java/mc/protocol/packets/client/StatusServerRequest.java @@ -0,0 +1,18 @@ +package mc.protocol.packets.client; + +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.ToString; +import mc.protocol.packets.EmptyPacket; + +/** + * Status server packet, request. + * + *

Клиент запрашивает получение информации о сервере

+ */ +@NoArgsConstructor +@EqualsAndHashCode(callSuper = false) +@ToString +public class StatusServerRequest extends EmptyPacket { + +} diff --git a/src/main/java/mc/protocol/packets/server/StatusServerResponse.java b/src/main/java/mc/protocol/packets/server/StatusServerResponse.java new file mode 100644 index 0000000..8cf99f4 --- /dev/null +++ b/src/main/java/mc/protocol/packets/server/StatusServerResponse.java @@ -0,0 +1,62 @@ +package mc.protocol.packets.server; + +import lombok.Data; +import mc.protocol.io.NetByteBuf; +import mc.protocol.packets.Packet; + +/** + * Status server packet, response. + * + *

Информация о сервере

+ * + *

Структура пакета + *

+ * | FIELD         | TYPE   | NOTES                                   |
+ * |---------------|--------|-----------------------------------------|
+ * | JSON Response | String | Информация о сервере в JSON формате [1] |
+ *
+ * [1] - Server List Ping: Response
+ * 

+ */ +@Data +public class StatusServerResponse implements Packet { + + /** + * Информация о серере в формате JSON + * + *

Пример

+ *
+	 * {
+	 *     "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 readSelf(NetByteBuf netByteBuf) { + info = netByteBuf.readString(); + } + + @Override + public void writeSelf(NetByteBuf netByteBuf) { + netByteBuf.writeString(info); + } +} diff --git a/src/main/java/mc/server/Main.java b/src/main/java/mc/server/Main.java index bd5f9f7..a435547 100644 --- a/src/main/java/mc/server/Main.java +++ b/src/main/java/mc/server/Main.java @@ -13,6 +13,6 @@ public class Main { NetworkComponent networkComponent = DaggerNetworkComponent.create(); Server server = networkComponent.getServer(); - server.start("127.0.0.1", 25565); + server.bind("127.0.0.1", 25565); } } diff --git a/src/main/java/mc/server/di/NetworkModule.java b/src/main/java/mc/server/di/NetworkModule.java index aae8cb4..c06bb2c 100644 --- a/src/main/java/mc/server/di/NetworkModule.java +++ b/src/main/java/mc/server/di/NetworkModule.java @@ -6,19 +6,26 @@ import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; -import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; +import lombok.extern.slf4j.Slf4j; +import mc.protocol.io.codec.ProtocolDecoder; +import mc.protocol.io.codec.ProtocolEncoder; +import mc.protocol.io.codec.ProtocolSplitter; import mc.server.network.Server; +import mc.server.network.netty.HandshakeHandler; import mc.server.network.netty.NettyServer; +import mc.server.network.netty.StatusHandler; -import javax.inject.Named; -import java.util.Collections; -import java.util.List; +import javax.inject.Provider; +import java.util.LinkedHashMap; +import java.util.Map; @Module +@Slf4j public class NetworkModule { @Provides @@ -27,14 +34,10 @@ public class NetworkModule { } @Provides - ServerBootstrap provideServerBootstrap( - @Named("boss-group") EventLoopGroup bossGroup, - @Named("worker-group") EventLoopGroup workerGroup, - ChannelInitializer channelChannelInitializer - ) { + ServerBootstrap provideServerBootstrap(ChannelInitializer channelChannelInitializer) { ServerBootstrap bootstrap = new ServerBootstrap(); - bootstrap.group(bossGroup, workerGroup) + bootstrap.group(new NioEventLoopGroup(1), new NioEventLoopGroup()) .channel(NioServerSocketChannel.class) .childHandler(channelChannelInitializer); @@ -42,30 +45,31 @@ public class NetworkModule { } @Provides - @Named("boss-group") - EventLoopGroup provideBossGroup() { - return new NioEventLoopGroup(1); - } - - @Provides - @Named("worker-group") - EventLoopGroup provideWorkerGroup() { - return new NioEventLoopGroup(); - } - - @Provides - ChannelInitializer provideChannelChannelInitializer(List channelHandlerList) { + ChannelInitializer provideChannelChannelInitializer(Provider> channelHandlerMapProvider) { return new ChannelInitializer<>() { @Override protected void initChannel(SocketChannel socketChannel) { - final ChannelPipeline pipeline = socketChannel.pipeline(); - channelHandlerList.forEach(pipeline::addLast); + ChannelPipeline pipeline = socketChannel.pipeline(); + channelHandlerMapProvider.get().forEach(pipeline::addLast); } }; } @Provides - List provideChannelHandlerList() { - return Collections.singletonList(new LoggingHandler()); + Map provideChannelHandlerMap(Provider statusHandlerProvider) { + Map map = new LinkedHashMap<>(); + + map.put("logger", new LoggingHandler(LogLevel.DEBUG)); + map.put("protocol_splitter", new ProtocolSplitter()); + map.put("protocol_decoder", new ProtocolDecoder(true)); + map.put("protocol_encoder", new ProtocolEncoder()); + map.put("handshake_handler", new HandshakeHandler(statusHandlerProvider)); + + return map; + } + + @Provides + StatusHandler provideStatusHandler() { + return new StatusHandler(); } } diff --git a/src/main/java/mc/server/network/Server.java b/src/main/java/mc/server/network/Server.java index f1464f8..b346a17 100644 --- a/src/main/java/mc/server/network/Server.java +++ b/src/main/java/mc/server/network/Server.java @@ -2,5 +2,5 @@ package mc.server.network; public interface Server { - void start(String host, int port); + void bind(String host, int port); } diff --git a/src/main/java/mc/server/network/netty/AbstractPacketHandler.java b/src/main/java/mc/server/network/netty/AbstractPacketHandler.java new file mode 100644 index 0000000..733e255 --- /dev/null +++ b/src/main/java/mc/server/network/netty/AbstractPacketHandler.java @@ -0,0 +1,17 @@ +package mc.server.network.netty; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import mc.protocol.packets.Packet; + +public abstract class AbstractPacketHandler

extends SimpleChannelInboundHandler { + + @SuppressWarnings("unchecked") + @Override + protected void channelRead0(ChannelHandlerContext ctx, Packet msg) throws Exception { + channelRead1(ctx, (P) msg); + } + + @SuppressWarnings("java:S112") + protected abstract void channelRead1(ChannelHandlerContext ctx, P packet) throws Exception; +} diff --git a/src/main/java/mc/server/network/netty/HandshakeHandler.java b/src/main/java/mc/server/network/netty/HandshakeHandler.java new file mode 100644 index 0000000..8ceb9a1 --- /dev/null +++ b/src/main/java/mc/server/network/netty/HandshakeHandler.java @@ -0,0 +1,24 @@ +package mc.server.network.netty; + +import io.netty.channel.ChannelHandlerContext; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import mc.protocol.NetworkAttributes; +import mc.protocol.packets.client.HandshakePacket; + +import javax.inject.Provider; + +@Slf4j +@RequiredArgsConstructor +public class HandshakeHandler extends AbstractPacketHandler { + + private final Provider statusHandlerProvider; + + @Override + protected void channelRead1(ChannelHandlerContext ctx, HandshakePacket packet) { + log.info("{}", packet); + + ctx.channel().attr(NetworkAttributes.STATE).set(packet.getNextState()); + ctx.pipeline().replace("handshake_handler", "status_handler", statusHandlerProvider.get()); + } +} diff --git a/src/main/java/mc/server/network/netty/NettyServer.java b/src/main/java/mc/server/network/netty/NettyServer.java index 4c3d19e..881914c 100644 --- a/src/main/java/mc/server/network/netty/NettyServer.java +++ b/src/main/java/mc/server/network/netty/NettyServer.java @@ -12,12 +12,11 @@ public class NettyServer implements Server { private final ServerBootstrap serverBootstrap; @Override - public void start(String host, int port) { + public void bind(String host, int port) { log.info("Network starting: {}:{}", host, port); try { - serverBootstrap.bind(host, port) - .sync().channel().closeFuture().sync(); + serverBootstrap.bind(host, port).sync().channel().closeFuture().sync(); } catch (InterruptedException e) { if (log.isTraceEnabled()) { log.trace("{}: {}", e.getClass().getSimpleName(), e.getMessage(), e); diff --git a/src/main/java/mc/server/network/netty/StatusHandler.java b/src/main/java/mc/server/network/netty/StatusHandler.java new file mode 100644 index 0000000..2d898ff --- /dev/null +++ b/src/main/java/mc/server/network/netty/StatusHandler.java @@ -0,0 +1,33 @@ +package mc.server.network.netty; + +import io.netty.channel.ChannelHandlerContext; +import lombok.extern.slf4j.Slf4j; +import mc.protocol.packets.client.StatusServerRequest; +import mc.protocol.packets.server.StatusServerResponse; + +@Slf4j +public class StatusHandler extends AbstractPacketHandler { + + @Override + protected void channelRead1(ChannelHandlerContext ctx, StatusServerRequest packet) { + log.info("{}", packet); + + StatusServerResponse response = new StatusServerResponse(); + response.setInfo("{\n" + + " \"version\": {\n" + + " \"name\": \"1.12.2\",\n" + + " \"protocol\": 340\n" + + " },\n" + + " \"players\": {\n" + + " \"max\": 0,\n" + + " \"online\": 0,\n" + + " \"sample\": []\n" + + " },\n" + + " \"description\": {\n" + + " \"text\": \"Hello world\"\n" + + " }\n" + + "}"); + + ctx.channel().writeAndFlush(response).channel().disconnect(); + } +} diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 9f1a1a5..192c634 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -4,11 +4,15 @@ - %d{HH:mm:ss.SSS} %-5level [%t] [%logger{36}] -- %msg%n + %d{HH:mm:ss.SSS} %-5level [%35.35logger{34}] -- %msg%n + + + + \ No newline at end of file diff --git a/src/test/java/mc/protocol/io/NetByteBufReadTest.java b/src/test/java/mc/protocol/io/NetByteBufReadTest.java new file mode 100644 index 0000000..c48b6b4 --- /dev/null +++ b/src/test/java/mc/protocol/io/NetByteBufReadTest.java @@ -0,0 +1,307 @@ +package mc.protocol.io; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Random; +import java.util.UUID; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +class NetByteBufReadTest { + + private static Random random; + private ByteArrayOutputStream baos; + + @BeforeEach + void setUp() { + random = new Random(System.currentTimeMillis()); + baos = new ByteArrayOutputStream(); + } + + @ParameterizedTest + @MethodSource("paramsReadBoolean") + void readBoolean(byte sourceByte, boolean expectedValue) { + baos.write(sourceByte); + + NetByteBuf netByteBuf = new NetByteBuf(Unpooled.wrappedBuffer(baos.toByteArray())); + + assertEquals(expectedValue, netByteBuf.readBoolean()); + } + + @Test + void readByte() { + byte[] bytes = new byte[1]; + random.nextBytes(bytes); + baos.write(bytes[0]); + + NetByteBuf netByteBuf = new NetByteBuf(Unpooled.wrappedBuffer(baos.toByteArray())); + + assertEquals(bytes[0], netByteBuf.readByte()); + } + + @ParameterizedTest + @MethodSource("paramsReadUnsignedByte") + void readUnsignedByte(byte sourceByte, int expectedValue) { + baos.write(sourceByte); + + NetByteBuf netByteBuf = new NetByteBuf(Unpooled.wrappedBuffer(baos.toByteArray())); + + assertEquals(expectedValue, netByteBuf.readUnsignedByte()); + } + + @Test + void readShort() throws IOException { + int value = Integer.valueOf(random.nextInt()).shortValue(); + new DataOutputStream(baos).writeShort(value); + + NetByteBuf netByteBuf = new NetByteBuf(Unpooled.wrappedBuffer(baos.toByteArray())); + + assertEquals(value, netByteBuf.readShort()); + } + + @Test + void readUnsignedShort() throws IOException { + int value = 32768; + new DataOutputStream(baos).writeShort(value); + + NetByteBuf netByteBuf = new NetByteBuf(Unpooled.wrappedBuffer(baos.toByteArray())); + + assertEquals(value, netByteBuf.readUnsignedShort()); + } + + @ParameterizedTest + @MethodSource("paramsReadString") + void readString(String string) throws IOException { + final byte[] strBytes = string.getBytes(StandardCharsets.UTF_8); + final byte[] bytes = new byte[strBytes.length + 1]; + bytes[0] = (byte) string.codePoints().count(); // допустим, что размер поместился в один байт + System.arraycopy(strBytes, 0, bytes, 1, strBytes.length); + + baos.write(bytes); + + NetByteBuf netByteBuf = new NetByteBuf(Unpooled.wrappedBuffer(baos.toByteArray())); + + assertEquals(string, netByteBuf.readString()); + } + + @Test + void readString_overSize() throws IOException { + String string = "123"; + final byte[] strBytes = string.getBytes(StandardCharsets.UTF_8); + final byte[] bytes = new byte[strBytes.length + 1]; + final int length = string.length(); + bytes[0] = (byte) (length + 1); // допустим, что размер поместился в один байт + System.arraycopy(strBytes, 0, bytes, 1, strBytes.length); + + baos.write(bytes); + + NetByteBuf netByteBuf = new NetByteBuf(Unpooled.wrappedBuffer(baos.toByteArray())); + + assertThrows(DecoderException.class, () -> netByteBuf.readString(length)); + } + + @Test + void readString_lessZero() throws IOException { + String string = "123"; + final byte[] strBytes = string.getBytes(StandardCharsets.UTF_8); + final byte[] bytes = new byte[strBytes.length + 5]; + bytes[0] = (byte) 0xFF; + bytes[1] = (byte) 0xFF; + bytes[2] = (byte) 0xFF; + bytes[3] = (byte) 0xFF; + bytes[4] = (byte) 0x0F; + System.arraycopy(strBytes, 0, bytes, 5, strBytes.length); + + baos.write(bytes); + + NetByteBuf netByteBuf = new NetByteBuf(Unpooled.wrappedBuffer(baos.toByteArray())); + + assertThrows(DecoderException.class, () -> netByteBuf.readString(-1)); + } + + @ParameterizedTest + @MethodSource("paramsReadVarInt") + void readVarInt(byte[] sourceBytes, int expectedValue) throws IOException { + baos.write(sourceBytes); + + NetByteBuf netByteBuf = new NetByteBuf(Unpooled.wrappedBuffer(baos.toByteArray())); + + assertEquals(expectedValue, netByteBuf.readVarInt()); + } + + @Test + void readVarInt_tooBig() throws IOException { + baos.write(new byte[]{ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x0F }); + + NetByteBuf netByteBuf = new NetByteBuf(Unpooled.wrappedBuffer(baos.toByteArray())); + + assertEquals(-1, netByteBuf.readVarInt()); + } + + @ParameterizedTest + @MethodSource({"paramsReadVarInt", "paramsReadVarLong"}) + void readVarLong(byte[] sourceBytes, long expectedValue) throws IOException { + baos.write(sourceBytes); + + NetByteBuf netByteBuf = new NetByteBuf(Unpooled.wrappedBuffer(baos.toByteArray())); + + assertEquals(expectedValue, netByteBuf.readVarLong()); + } + + @Test + void readVarLong_tooBig() throws IOException { + baos.write(new byte[]{ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0x0F }); + + NetByteBuf netByteBuf = new NetByteBuf(Unpooled.wrappedBuffer(baos.toByteArray())); + + assertEquals(-1, netByteBuf.readVarLong()); + } + + @Test + void readUUID() throws IOException { + final UUID uuid = UUID.randomUUID(); + final long mostSignificantBits = uuid.getMostSignificantBits(); + final long leastSignificantBits = uuid.getLeastSignificantBits(); + + baos.write(new byte[]{ + (byte) ((mostSignificantBits >>> 56) & 0xFF), + (byte) ((mostSignificantBits >>> 48) & 0xFF), + (byte) ((mostSignificantBits >>> 40) & 0xFF), + (byte) ((mostSignificantBits >>> 32) & 0xFF), + (byte) ((mostSignificantBits >>> 24) & 0xFF), + (byte) ((mostSignificantBits >>> 16) & 0xFF), + (byte) ((mostSignificantBits >>> 8) & 0xFF), + (byte) (mostSignificantBits & 0xFF) + }); + baos.write(new byte[]{ + (byte) ((leastSignificantBits >>> 56) & 0xFF), + (byte) ((leastSignificantBits >>> 48) & 0xFF), + (byte) ((leastSignificantBits >>> 40) & 0xFF), + (byte) ((leastSignificantBits >>> 32) & 0xFF), + (byte) ((leastSignificantBits >>> 24) & 0xFF), + (byte) ((leastSignificantBits >>> 16) & 0xFF), + (byte) ((leastSignificantBits >>> 8) & 0xFF), + (byte) (leastSignificantBits & 0xFF) + }); + + NetByteBuf netByteBuf = new NetByteBuf(Unpooled.wrappedBuffer(baos.toByteArray())); + + assertEquals(uuid, netByteBuf.readUUID()); + } + + @Test + void readBytes() throws IOException { + byte[] bytes = new byte[128]; + random.nextBytes(bytes); + baos.write(bytes); + + byte[] actualBytes = new byte[128]; + NetByteBuf netByteBuf = new NetByteBuf(Unpooled.wrappedBuffer(baos.toByteArray())); + + assertEquals(bytes.length, netByteBuf.readableBytes()); + + netByteBuf.readBytes(actualBytes); + + assertArrayEquals(bytes, actualBytes); + assertEquals(0, netByteBuf.readableBytes()); + } + + @Test + void read_offset() throws IOException { + byte[] bytes = new byte[128]; + random.nextBytes(bytes); + baos.write(bytes); + + byte[] buff = new byte[128]; + NetByteBuf netByteBuf = new NetByteBuf(Unpooled.wrappedBuffer(baos.toByteArray())); + netByteBuf.readBytes(buff, 3, 11); + + byte[] expectedBytes = new byte[11]; + System.arraycopy(bytes, 0, expectedBytes, 0, 11); + byte[] actualBytes = new byte[11]; + System.arraycopy(buff, 3, actualBytes, 0, 11); + + assertArrayEquals(expectedBytes, actualBytes); + } + + @SuppressWarnings("unused") + private static Stream paramsReadBoolean() { + return Stream.of( + Arguments.of((byte) 0x00, false), + Arguments.of((byte) 0x01, true) + ); + } + + @SuppressWarnings("unused") + private static Stream paramsReadUnsignedByte() { + return Stream.of( + Arguments.of((byte) 30, 30), + Arguments.of((byte) (0xFF & 130), 130) + ); + } + + @SuppressWarnings("unused") + private static Stream paramsReadString() { + return Stream.of( + Arguments.of(""), + Arguments.of("Latin"), + Arguments.of("Кириллица"), + Arguments.of("العربية"), + Arguments.of("ﬦﬣﬡ"), // Алфавитные формы представления + Arguments.of("\uD800\uDD07") // Эгейские цифры, [один] + ); + } + + @SuppressWarnings("unused") + private static Stream paramsReadVarInt() { + return Stream.of( + Arguments.of(new byte[]{ 0x78 }, 120), + Arguments.of(new byte[]{ (byte) 0xE0, 0x5D }, 12000), + Arguments.of(new byte[]{ (byte) 0xC0, (byte) 0xA9, 0x07 }, 120000), + Arguments.of(new byte[]{ (byte) 0x80, (byte) 0x9C, (byte) 0x9C, (byte) 0x39 }, 120_000_000), + Arguments.of(new byte[]{ (byte) 0x80, (byte) 0x98, (byte) 0x9A, (byte) 0xBC, 0x04 }, 1_200_000_000) + ); + } + + @SuppressWarnings("unused") + private static Stream paramsReadVarLong() { + return Stream.of( + Arguments.of( + new byte[]{ (byte) 0x80, (byte) 0xF0, (byte) 0x85, (byte) 0xDA, 0x2C }, + 12_000_000_000L), + Arguments.of( + new byte[]{ (byte) 0x80, (byte) 0xE0, (byte) 0xBA, (byte) 0x84, (byte) 0xBF, 0x03 }, + 120_000_000_000L), + Arguments.of( + new byte[]{ (byte) 0x80, (byte) 0x80, (byte) 0xF3, (byte) 0xBD, (byte) 0x9F, (byte) 0xDD, + 0x02 }, + 12_000_000_000_000L), + Arguments.of( + new byte[]{ (byte) 0x80, (byte) 0x80, (byte) 0xEC, (byte) 0xAD, (byte) 0xCC, (byte) 0xEC, + (byte) 0x90, 0x02}, + 1_200_000_000_000_000L), + Arguments.of( + new byte[]{ (byte) 0x80, (byte) 0x80, (byte) 0xB0, (byte) 0xE8, (byte) 0xD3, (byte) 0xEB, + (byte) 0x94, (byte) 0xD5, 0x01 }, + 120_000_000_000_000_000L), + Arguments.of( + new byte[]{ (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, + (byte) 0x80, (byte) 0x80, (byte) 0x80, 0x01 }, + Long.MIN_VALUE) + ); + } +} \ No newline at end of file diff --git a/src/test/java/mc/protocol/io/NetByteBufWriteTest.java b/src/test/java/mc/protocol/io/NetByteBufWriteTest.java new file mode 100644 index 0000000..74b6c5a --- /dev/null +++ b/src/test/java/mc/protocol/io/NetByteBufWriteTest.java @@ -0,0 +1,246 @@ +package mc.protocol.io; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.nio.charset.StandardCharsets; +import java.util.Random; +import java.util.UUID; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class NetByteBufWriteTest { + + private static Random random; + + @BeforeAll + static void setUp() { + random = new Random(System.currentTimeMillis()); + } + + @ParameterizedTest + @MethodSource("paramsWriteBoolean") + void writeBoolean(boolean sourceValue, byte expectedByte) { + ByteBuf byteBuf = Unpooled.buffer(); + NetByteBuf netByteBuf = new NetByteBuf(byteBuf); + + netByteBuf.writeBoolean(sourceValue); + + assertEquals(expectedByte, byteBuf.array()[0]); + } + + @ParameterizedTest + @MethodSource("paramsWriteByte") + void writeByte(byte sourceValue, byte expectedByte) { + ByteBuf byteBuf = Unpooled.buffer(); + NetByteBuf netByteBuf = new NetByteBuf(byteBuf); + + netByteBuf.writeByte(sourceValue); + + assertEquals(expectedByte, byteBuf.array()[0]); + } + + @ParameterizedTest + @MethodSource("paramsWriteString") + void writeString(String string) { + ByteBuf byteBuf = Unpooled.buffer(); + NetByteBuf netByteBuf = new NetByteBuf(byteBuf); + + netByteBuf.writeString(string); + + byte[] actualArray = netByteBuf.copy(0, netByteBuf.readableBytes()).array(); + int length = actualArray[0]; // допустим, что размер поместился в один байт + assertEquals(string.codePoints().count(), length); + + byte[] dataBytes = new byte[actualArray.length - 1]; + System.arraycopy(actualArray, 1, dataBytes, 0, dataBytes.length); + assertEquals(string, new String(dataBytes, StandardCharsets.UTF_8)); + } + + //возможно этот тест нужно перенести в NetByteBufReadTest + @Test + void writeString_overSize() { + String overSizeString = RandomStringUtils.randomAscii(Short.MAX_VALUE + Short.MAX_VALUE); + + ByteBuf byteBuf = Unpooled.buffer(); + NetByteBuf netByteBuf = new NetByteBuf(byteBuf); + + netByteBuf.writeString(overSizeString); + + NetByteBuf netByteBuf2 = new NetByteBuf(byteBuf.copy()); + String actualString = netByteBuf2.readString(); + + String expectedString = overSizeString.substring(0, Short.MAX_VALUE); + + assertEquals(expectedString, actualString); + } + + @ParameterizedTest + @MethodSource("paramsWriteVarInt") + void writeVarInt(int sourceValue, byte[] expectedBytes) { + ByteBuf byteBuf = Unpooled.buffer(); + NetByteBuf netByteBuf = new NetByteBuf(byteBuf); + + netByteBuf.writeVarInt(sourceValue); + byte[] actualArray = netByteBuf.copy(0, netByteBuf.readableBytes()).array(); + + assertArrayEquals(expectedBytes, actualArray); + } + + @ParameterizedTest + @MethodSource({ "paramsWriteVarInt", "paramsWriteVarLong" }) + void writeVarLong(long sourceValue, byte[] expectedBytes) { + ByteBuf byteBuf = Unpooled.buffer(); + NetByteBuf netByteBuf = new NetByteBuf(byteBuf); + + netByteBuf.writeVarLong(sourceValue); + byte[] actualArray = netByteBuf.copy(0, netByteBuf.readableBytes()).array(); + + assertArrayEquals(expectedBytes, actualArray); + } + + @Test + void writeUUID() { + final UUID uuid = UUID.randomUUID(); + + ByteBuf byteBuf = Unpooled.buffer(); + NetByteBuf netByteBuf = new NetByteBuf(byteBuf); + + netByteBuf.writeUUID(uuid); + + final long mostSignificantBits = uuid.getMostSignificantBits(); + final long leastSignificantBits = uuid.getLeastSignificantBits(); + + byte[] actualArray = netByteBuf.copy(0, netByteBuf.readableBytes()).array(); + + assertArrayEquals(new byte[]{ + (byte) ((mostSignificantBits >>> 56) & 0xFF), + (byte) ((mostSignificantBits >>> 48) & 0xFF), + (byte) ((mostSignificantBits >>> 40) & 0xFF), + (byte) ((mostSignificantBits >>> 32) & 0xFF), + (byte) ((mostSignificantBits >>> 24) & 0xFF), + (byte) ((mostSignificantBits >>> 16) & 0xFF), + (byte) ((mostSignificantBits >>> 8) & 0xFF), + (byte) (mostSignificantBits & 0xFF), + + (byte) ((leastSignificantBits >>> 56) & 0xFF), + (byte) ((leastSignificantBits >>> 48) & 0xFF), + (byte) ((leastSignificantBits >>> 40) & 0xFF), + (byte) ((leastSignificantBits >>> 32) & 0xFF), + (byte) ((leastSignificantBits >>> 24) & 0xFF), + (byte) ((leastSignificantBits >>> 16) & 0xFF), + (byte) ((leastSignificantBits >>> 8) & 0xFF), + (byte) (leastSignificantBits & 0xFF) }, + actualArray); + } + + @Test + void writeBytes() { + byte[] bytes = new byte[128]; + random.nextBytes(bytes); + + ByteBuf byteBuf = Unpooled.buffer(); + NetByteBuf netByteBuf = new NetByteBuf(byteBuf); + + netByteBuf.writeBytes(bytes); + byte[] actualArray = netByteBuf.copy(0, netByteBuf.readableBytes()).array(); + + assertArrayEquals(bytes, actualArray); + } + + @Test + void write_offset() { + byte[] bytes = new byte[128]; + random.nextBytes(bytes); + + ByteBuf byteBuf = Unpooled.buffer(); + NetByteBuf netByteBuf = new NetByteBuf(byteBuf); + + netByteBuf.writeBytes(bytes, 3, 11); + + byte[] actualBytes = new byte[11]; + System.arraycopy(byteBuf.array(), 0, actualBytes, 0, 11); + + byte[] expectedBytes = new byte[11]; + System.arraycopy(bytes, 3, expectedBytes, 0, 11); + + assertArrayEquals(expectedBytes, actualBytes); + } + + @SuppressWarnings("unused") + private static Stream paramsWriteBoolean() { + return Stream.of( + Arguments.of(false, (byte) 0x00), + Arguments.of(true, (byte) 0x01) + ); + } + + @SuppressWarnings("unused") + private static Stream paramsWriteByte() { + byte b = Integer.valueOf(random.nextInt()).byteValue(); + + return Stream.of( + Arguments.of(b, b), + Arguments.of((byte) 128, (byte) -128) + ); + } + + @SuppressWarnings("unused") + private static Stream paramsWriteString() { + return Stream.of( + Arguments.of(""), + Arguments.of("Latin"), + Arguments.of("Кириллица"), + Arguments.of("العربية"), + Arguments.of("ﬦﬣﬡ"), // Алфавитные формы представления + Arguments.of("\uD800\uDD07") // Эгейские цифры, [один] + ); + } + + @SuppressWarnings("unused") + private static Stream paramsWriteVarInt() { + return Stream.of( + Arguments.of(120, new byte[]{ 0x78 }), + Arguments.of(12000, new byte[]{ (byte) 0xE0, 0x5D }), + Arguments.of(120000, new byte[]{ (byte) 0xC0, (byte) 0xA9, 0x07 }), + Arguments.of(120000000, new byte[]{ (byte) 0x80, (byte) 0x9C, (byte) 0x9C, (byte) 0x39 }), + Arguments.of(1200000000, new byte[]{ (byte) 0x80, (byte) 0x98, (byte) 0x9A, (byte) 0xBC, 0x04 }) + ); + } + + @SuppressWarnings("unused") + private static Stream paramsWriteVarLong() { + return Stream.of( + Arguments.of( + 12_000_000_000L, + new byte[]{ (byte) 0x80, (byte) 0xF0, (byte) 0x85, (byte) 0xDA, 0x2C }), + Arguments.of( + 120_000_000_000L, + new byte[]{ (byte) 0x80, (byte) 0xE0, (byte) 0xBA, (byte) 0x84, (byte) 0xBF, 0x03 }), + Arguments.of( + 12_000_000_000_000L, + new byte[]{ (byte) 0x80, (byte) 0x80, (byte) 0xF3, (byte) 0xBD, (byte) 0x9F, (byte) 0xDD, + 0x02 }), + Arguments.of( + 1_200_000_000_000_000L, + new byte[]{ (byte) 0x80, (byte) 0x80, (byte) 0xEC, (byte) 0xAD, (byte) 0xCC, (byte) 0xEC, + (byte) 0x90, 0x02 }), + Arguments.of( + 120_000_000_000_000_000L, + new byte[]{ (byte) 0x80, (byte) 0x80, (byte) 0xB0, (byte) 0xE8, (byte) 0xD3, (byte) 0xEB, + (byte) 0x94, (byte) 0xD5, 0x01 }), + Arguments.of( + Long.MIN_VALUE, + new byte[]{ (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, + (byte) 0x80, (byte) 0x80, (byte) 0x80, 0x01 }) + ); + } +} From fdc975d268ecdbe373e9de0e82f122f6d340eb0a Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Mon, 26 Apr 2021 00:41:56 +0300 Subject: [PATCH 03/34] =?UTF-8?q?=D0=B7=D0=B0=D0=BF=D1=80=D0=B5=D1=82=20?= =?UTF-8?q?=D0=B2=D1=85=D0=BE=D0=B4=D0=B0=20=D0=BD=D0=B0=20=D1=81=D0=B5?= =?UTF-8?q?=D1=80=D0=B2=D0=B5=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/mc/protocol/State.java | 8 ++++ .../packets/client/LoginStartPacket.java | 43 +++++++++++++++++ .../packets/server/DisconnectPacket.java | 47 +++++++++++++++++++ src/main/java/mc/server/di/NetworkModule.java | 17 +++++-- .../{ => handler}/AbstractPacketHandler.java | 2 +- .../netty/{ => handler}/HandshakeHandler.java | 11 ++++- .../network/netty/handler/LoginHandler.java | 18 +++++++ .../netty/{ => handler}/StatusHandler.java | 2 +- 8 files changed, 140 insertions(+), 8 deletions(-) create mode 100644 src/main/java/mc/protocol/packets/client/LoginStartPacket.java create mode 100644 src/main/java/mc/protocol/packets/server/DisconnectPacket.java rename src/main/java/mc/server/network/netty/{ => handler}/AbstractPacketHandler.java (92%) rename src/main/java/mc/server/network/netty/{ => handler}/HandshakeHandler.java (58%) create mode 100644 src/main/java/mc/server/network/netty/handler/LoginHandler.java rename src/main/java/mc/server/network/netty/{ => handler}/StatusHandler.java (95%) diff --git a/src/main/java/mc/protocol/State.java b/src/main/java/mc/protocol/State.java index da448e6..3d38333 100644 --- a/src/main/java/mc/protocol/State.java +++ b/src/main/java/mc/protocol/State.java @@ -7,7 +7,9 @@ import lombok.RequiredArgsConstructor; import mc.protocol.packets.Packet; import mc.protocol.packets.PacketDirection; import mc.protocol.packets.client.HandshakePacket; +import mc.protocol.packets.client.LoginStartPacket; import mc.protocol.packets.client.StatusServerRequest; +import mc.protocol.packets.server.DisconnectPacket; import mc.protocol.packets.server.StatusServerResponse; import javax.annotation.Nullable; @@ -24,6 +26,12 @@ public enum State { ImmutableBiMap.of(0x00, StatusServerRequest.class), // client bound ImmutableBiMap.of(0x00, StatusServerResponse.class) + ), + LOGIN(2, + // server bound + ImmutableBiMap.of(0x00, LoginStartPacket.class), + // client bound + ImmutableBiMap.of(0x00, DisconnectPacket.class) ); @Nullable diff --git a/src/main/java/mc/protocol/packets/client/LoginStartPacket.java b/src/main/java/mc/protocol/packets/client/LoginStartPacket.java new file mode 100644 index 0000000..6fa953e --- /dev/null +++ b/src/main/java/mc/protocol/packets/client/LoginStartPacket.java @@ -0,0 +1,43 @@ +package mc.protocol.packets.client; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import mc.protocol.State; +import mc.protocol.io.NetByteBuf; +import mc.protocol.packets.Packet; + +/** + * Login start packet. + * + *

Начало авторизации.

+ * + *

Структура пакета

+ *
+ * | FIELD | TYPE   | NOTES            |
+ * |-------|--------|------------------|
+ * | Name  | String | Имя/Логин игрока |
+ * 
+ * + * @see Login start + * @see State + */ +@NoArgsConstructor +@Getter +@EqualsAndHashCode +@ToString +public class LoginStartPacket implements Packet { + + private String name; + + @Override + public void readSelf(NetByteBuf netByteBuf) { + this.name = netByteBuf.readString(); + } + + @Override + public void writeSelf(NetByteBuf netByteBuf) { + netByteBuf.writeString(name); + } +} diff --git a/src/main/java/mc/protocol/packets/server/DisconnectPacket.java b/src/main/java/mc/protocol/packets/server/DisconnectPacket.java new file mode 100644 index 0000000..2cfb3e2 --- /dev/null +++ b/src/main/java/mc/protocol/packets/server/DisconnectPacket.java @@ -0,0 +1,47 @@ +package mc.protocol.packets.server; + +import lombok.Data; +import mc.protocol.State; +import mc.protocol.io.NetByteBuf; +import mc.protocol.packets.Packet; + +/** + * Diconnect packet. + * + *

Отключение клиента сервером с указанием причины.

+ * + *

Структура пакета

+ *
+ * | FIELD  | TYPE | NOTES                            |
+ * |--------|------|----------------------------------|
+ * | Reason | Text | Причина отключения. Опционально. |
+ * 
+ * + * @see Disconnect + * @see State + */ +@Data +public class DisconnectPacket implements Packet { + + /** + * Причина отключения. + * + *

Пример:

+ *
+	 * {
+	 *     "text": "foo"
+	 * }
+	 * 
+ */ + private String reason; + + @Override + public void readSelf(NetByteBuf netByteBuf) { + this.reason = netByteBuf.readString(); + } + + @Override + public void writeSelf(NetByteBuf netByteBuf) { + netByteBuf.writeString(reason); + } +} diff --git a/src/main/java/mc/server/di/NetworkModule.java b/src/main/java/mc/server/di/NetworkModule.java index c06bb2c..c5ca566 100644 --- a/src/main/java/mc/server/di/NetworkModule.java +++ b/src/main/java/mc/server/di/NetworkModule.java @@ -16,9 +16,10 @@ import mc.protocol.io.codec.ProtocolDecoder; import mc.protocol.io.codec.ProtocolEncoder; import mc.protocol.io.codec.ProtocolSplitter; import mc.server.network.Server; -import mc.server.network.netty.HandshakeHandler; +import mc.server.network.netty.handler.HandshakeHandler; import mc.server.network.netty.NettyServer; -import mc.server.network.netty.StatusHandler; +import mc.server.network.netty.handler.LoginHandler; +import mc.server.network.netty.handler.StatusHandler; import javax.inject.Provider; import java.util.LinkedHashMap; @@ -56,14 +57,17 @@ public class NetworkModule { } @Provides - Map provideChannelHandlerMap(Provider statusHandlerProvider) { + Map provideChannelHandlerMap( + Provider statusHandlerProvider, + Provider loginHandlerProvider + ) { Map map = new LinkedHashMap<>(); map.put("logger", new LoggingHandler(LogLevel.DEBUG)); map.put("protocol_splitter", new ProtocolSplitter()); map.put("protocol_decoder", new ProtocolDecoder(true)); map.put("protocol_encoder", new ProtocolEncoder()); - map.put("handshake_handler", new HandshakeHandler(statusHandlerProvider)); + map.put("handshake_handler", new HandshakeHandler(statusHandlerProvider, loginHandlerProvider)); return map; } @@ -72,4 +76,9 @@ public class NetworkModule { StatusHandler provideStatusHandler() { return new StatusHandler(); } + + @Provides + LoginHandler provideLoginHandler() { + return new LoginHandler(); + } } diff --git a/src/main/java/mc/server/network/netty/AbstractPacketHandler.java b/src/main/java/mc/server/network/netty/handler/AbstractPacketHandler.java similarity index 92% rename from src/main/java/mc/server/network/netty/AbstractPacketHandler.java rename to src/main/java/mc/server/network/netty/handler/AbstractPacketHandler.java index 733e255..3d2d900 100644 --- a/src/main/java/mc/server/network/netty/AbstractPacketHandler.java +++ b/src/main/java/mc/server/network/netty/handler/AbstractPacketHandler.java @@ -1,4 +1,4 @@ -package mc.server.network.netty; +package mc.server.network.netty.handler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; diff --git a/src/main/java/mc/server/network/netty/HandshakeHandler.java b/src/main/java/mc/server/network/netty/handler/HandshakeHandler.java similarity index 58% rename from src/main/java/mc/server/network/netty/HandshakeHandler.java rename to src/main/java/mc/server/network/netty/handler/HandshakeHandler.java index 8ceb9a1..5f31d3e 100644 --- a/src/main/java/mc/server/network/netty/HandshakeHandler.java +++ b/src/main/java/mc/server/network/netty/handler/HandshakeHandler.java @@ -1,9 +1,10 @@ -package mc.server.network.netty; +package mc.server.network.netty.handler; import io.netty.channel.ChannelHandlerContext; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import mc.protocol.NetworkAttributes; +import mc.protocol.State; import mc.protocol.packets.client.HandshakePacket; import javax.inject.Provider; @@ -13,12 +14,18 @@ import javax.inject.Provider; public class HandshakeHandler extends AbstractPacketHandler { private final Provider statusHandlerProvider; + private final Provider loginHandlerProvider; @Override protected void channelRead1(ChannelHandlerContext ctx, HandshakePacket packet) { log.info("{}", packet); ctx.channel().attr(NetworkAttributes.STATE).set(packet.getNextState()); - ctx.pipeline().replace("handshake_handler", "status_handler", statusHandlerProvider.get()); + + if (State.STATUS == packet.getNextState()) { + ctx.pipeline().replace("handshake_handler", "status_handler", statusHandlerProvider.get()); + } else if (State.LOGIN == packet.getNextState()) { + ctx.channel().pipeline().replace("handshake_handler", "login_handler", loginHandlerProvider.get()); + } } } diff --git a/src/main/java/mc/server/network/netty/handler/LoginHandler.java b/src/main/java/mc/server/network/netty/handler/LoginHandler.java new file mode 100644 index 0000000..8a0d92c --- /dev/null +++ b/src/main/java/mc/server/network/netty/handler/LoginHandler.java @@ -0,0 +1,18 @@ +package mc.server.network.netty.handler; + +import io.netty.channel.ChannelHandlerContext; +import mc.protocol.packets.client.LoginStartPacket; +import mc.protocol.packets.server.DisconnectPacket; + +public class LoginHandler extends AbstractPacketHandler { + + @Override + protected void channelRead1(ChannelHandlerContext ctx, LoginStartPacket packet) { + DisconnectPacket disconnectPacket = new DisconnectPacket(); + disconnectPacket.setReason("{\n" + + " \"text\": \"Server is not available.\"\n" + + "}"); + + ctx.channel().writeAndFlush(disconnectPacket).channel().disconnect(); + } +} diff --git a/src/main/java/mc/server/network/netty/StatusHandler.java b/src/main/java/mc/server/network/netty/handler/StatusHandler.java similarity index 95% rename from src/main/java/mc/server/network/netty/StatusHandler.java rename to src/main/java/mc/server/network/netty/handler/StatusHandler.java index 2d898ff..0628875 100644 --- a/src/main/java/mc/server/network/netty/StatusHandler.java +++ b/src/main/java/mc/server/network/netty/handler/StatusHandler.java @@ -1,4 +1,4 @@ -package mc.server.network.netty; +package mc.server.network.netty.handler; import io.netty.channel.ChannelHandlerContext; import lombok.extern.slf4j.Slf4j; From 39b858696f37e5db31fc5c76297d3bc835f8e1ba Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Mon, 26 Apr 2021 14:00:19 +0300 Subject: [PATCH 04/34] =?UTF-8?q?=D1=83=D0=B1=D0=B8=D1=80=D0=B0=D0=B5?= =?UTF-8?q?=D0=BC=20LogicPlugin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 20 +++++++++++++++++-- .../gradle/extention/LogicExtention.java | 19 ------------------ .../dmitriymx/gradle/plugin/LogicPlugin.java | 13 ------------ 3 files changed, 18 insertions(+), 34 deletions(-) delete mode 100644 buildSrc/src/main/java/ru/dmitriymx/gradle/extention/LogicExtention.java delete mode 100644 buildSrc/src/main/java/ru/dmitriymx/gradle/plugin/LogicPlugin.java diff --git a/build.gradle b/build.gradle index 7de1955..9598373 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,22 @@ */ import ru.dmitriymx.gradle.plugin.LibsPlugin -import ru.dmitriymx.gradle.plugin.LogicPlugin + +class Logic { + private final Project project + + Logic(Project project) { + this.project = project + } + + String getProperty1(String propertyName1, String propertyName2) { + return (String) (project.hasProperty(propertyName1) ? project.property(propertyName1) : project.property(propertyName2)) + } + + String getProperty1(String propertyName) { + return (String) (project.hasProperty(propertyName) ? project.property(propertyName) : null) + } +} plugins { id 'java' @@ -12,7 +27,8 @@ plugins { } apply plugin: LibsPlugin -apply plugin: LogicPlugin + +def logic = new Logic(project) project.group = logic.getProperty1('project.group') project.version = logic.getProperty1('project.version') diff --git a/buildSrc/src/main/java/ru/dmitriymx/gradle/extention/LogicExtention.java b/buildSrc/src/main/java/ru/dmitriymx/gradle/extention/LogicExtention.java deleted file mode 100644 index c596a13..0000000 --- a/buildSrc/src/main/java/ru/dmitriymx/gradle/extention/LogicExtention.java +++ /dev/null @@ -1,19 +0,0 @@ -package ru.dmitriymx.gradle.extention; - -import org.gradle.api.Project; - -public class LogicExtention { - private final Project project; - - public LogicExtention(Project project) { - this.project = project; - } - - public String getProperty1(String propertyName1, String propertyName2) { - return (String) (project.hasProperty(propertyName1) ? project.property(propertyName1) : project.property(propertyName2)); - } - - public String getProperty1(String propertyName) { - return (String) (project.hasProperty(propertyName) ? project.property(propertyName) : null); - } -} diff --git a/buildSrc/src/main/java/ru/dmitriymx/gradle/plugin/LogicPlugin.java b/buildSrc/src/main/java/ru/dmitriymx/gradle/plugin/LogicPlugin.java deleted file mode 100644 index 4068cf4..0000000 --- a/buildSrc/src/main/java/ru/dmitriymx/gradle/plugin/LogicPlugin.java +++ /dev/null @@ -1,13 +0,0 @@ -package ru.dmitriymx.gradle.plugin; - -import org.gradle.api.Plugin; -import org.gradle.api.Project; -import ru.dmitriymx.gradle.extention.LogicExtention; - -public class LogicPlugin implements Plugin { - - @Override - public void apply(Project project) { - project.getExtensions().create("logic", LogicExtention.class, project); - } -} From 612eef236172a5d0addd54aaafefa7b6bf227b56 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Mon, 26 Apr 2021 14:34:58 +0300 Subject: [PATCH 05/34] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=BD=D0=BE?= =?UTF-8?q?=D1=81=20=D1=82=D0=B8=D0=BF=D0=B8=D1=87=D0=BD=D1=8B=D1=85=20?= =?UTF-8?q?=D0=BD=D0=B0=D1=81=D1=82=D1=80=D0=BE=D0=B5=D0=BA=20=D0=B2=20log?= =?UTF-8?q?ic.gradle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 33 +-------------------------------- logic.gradle | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 32 deletions(-) create mode 100644 logic.gradle diff --git a/build.gradle b/build.gradle index 9598373..bce7640 100644 --- a/build.gradle +++ b/build.gradle @@ -5,44 +5,13 @@ import ru.dmitriymx.gradle.plugin.LibsPlugin -class Logic { - private final Project project - - Logic(Project project) { - this.project = project - } - - String getProperty1(String propertyName1, String propertyName2) { - return (String) (project.hasProperty(propertyName1) ? project.property(propertyName1) : project.property(propertyName2)) - } - - String getProperty1(String propertyName) { - return (String) (project.hasProperty(propertyName) ? project.property(propertyName) : null) - } -} - plugins { id 'java' id 'application' } apply plugin: LibsPlugin - -def logic = new Logic(project) - -project.group = logic.getProperty1('project.group') -project.version = logic.getProperty1('project.version') -jar.archiveBaseName.set(logic.getProperty1('project.name')) - -compileJava { - sourceCompatibility = targetCompatibility = JavaVersion.VERSION_11 - options.encoding = 'UTF-8' -} - -repositories { - mavenLocal() - mavenCentral() -} +apply from: rootDir.toPath().resolve('logic.gradle').toFile() dependencies { annotationProcessor libs.lombok diff --git a/logic.gradle b/logic.gradle new file mode 100644 index 0000000..0e9a252 --- /dev/null +++ b/logic.gradle @@ -0,0 +1,17 @@ +String getProperty1(String propertyName1, String propertyName2) { + return (String) (project.hasProperty(propertyName1) ? project.property(propertyName1) : project.property(propertyName2)) +} + +project.group = getProperty1('module.group', 'project.group') +project.version = getProperty1('module.version', 'project.version') +project.jar.archiveBaseName.set(getProperty1('module.name', 'project.name')) + +compileJava { + sourceCompatibility = targetCompatibility = JavaVersion.VERSION_11 + options.encoding = 'UTF-8' +} + +repositories { + mavenLocal() + mavenCentral() +} \ No newline at end of file From a8f567ad2cff38e78ecc088c64999ecf84dc1ec9 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Mon, 26 Apr 2021 14:47:16 +0300 Subject: [PATCH 06/34] =?UTF-8?q?=D1=83=D0=B1=D0=B8=D1=80=D0=B0=D0=B5?= =?UTF-8?q?=D0=BC=20LibsPlugin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 36 +++++++++++++-- .../gradle/extention/LibsExtention.java | 46 ------------------- .../dmitriymx/gradle/plugin/LibsPlugin.java | 13 ------ 3 files changed, 33 insertions(+), 62 deletions(-) delete mode 100644 buildSrc/src/main/java/ru/dmitriymx/gradle/extention/LibsExtention.java delete mode 100644 buildSrc/src/main/java/ru/dmitriymx/gradle/plugin/LibsPlugin.java diff --git a/build.gradle b/build.gradle index bce7640..fd18383 100644 --- a/build.gradle +++ b/build.gradle @@ -3,16 +3,46 @@ gradle run */ -import ru.dmitriymx.gradle.plugin.LibsPlugin - plugins { id 'java' id 'application' } -apply plugin: LibsPlugin apply from: rootDir.toPath().resolve('logic.gradle').toFile() +ext { + slf4j_version = '1.7.30' + logback_version = '1.2.3' + dagger2_version = '2.33' + junit_version = '5.5.2' + + libs = [ + lombok : 'org.projectlombok:lombok:1.18.12', + annotations: 'com.google.code.findbugs:jsr305:3.0.2', + guava : 'com.google.guava:guava:30.1-jre', + lang3 : 'org.apache.commons:commons-lang3:3.11', + ] + + libs.logger = [ + slf4j : ["org.slf4j:slf4j-api:${slf4j_version}", + "org.slf4j:jcl-over-slf4j:${slf4j_version}"], + logback: ["ch.qos.logback:logback-core:${logback_version}", + "ch.qos.logback:logback-classic:${logback_version}"] + ] + + libs.dagger2 = [ + implementation: "com.google.dagger:dagger:${dagger2_version}", + annotationProcessor: "com.google.dagger:dagger-compiler:${dagger2_version}" + ] + + libs.junit5 = [ + api: "org.junit.jupiter:junit-jupiter-api:${junit_version}", + //runtime only + engine: "org.junit.jupiter:junit-jupiter-engine:${junit_version}", + params: "org.junit.jupiter:junit-jupiter-params:${junit_version}" + ] +} + dependencies { annotationProcessor libs.lombok compileOnly libs.lombok diff --git a/buildSrc/src/main/java/ru/dmitriymx/gradle/extention/LibsExtention.java b/buildSrc/src/main/java/ru/dmitriymx/gradle/extention/LibsExtention.java deleted file mode 100644 index 05123ee..0000000 --- a/buildSrc/src/main/java/ru/dmitriymx/gradle/extention/LibsExtention.java +++ /dev/null @@ -1,46 +0,0 @@ -package ru.dmitriymx.gradle.extention; - -import java.util.List; - -public class LibsExtention { - - public final String lombok = "org.projectlombok:lombok:1.18.12"; - public final String annotations = "com.google.code.findbugs:jsr305:3.0.2"; - public final String guava = "com.google.guava:guava:30.1-jre"; - public final String lang3 = "org.apache.commons:commons-lang3:3.11"; - - public final LoggerLibs logger = new LoggerLibs(); - public final Dagger2Libs dagger2 = new Dagger2Libs(); - public final Junit5Libs junit5 = new Junit5Libs(); - - public static final class LoggerLibs { - private final String slf4j_version = "1.7.30"; - private final String logback_version = "1.2.3"; - - public final List slf4j = List.of( - "org.slf4j:slf4j-api:" + slf4j_version, - "org.slf4j:jcl-over-slf4j:" + slf4j_version - ); - - public final List logback = List.of( - "ch.qos.logback:logback-core:" + logback_version, - "ch.qos.logback:logback-classic:" + logback_version - ); - } - - public static final class Dagger2Libs { - private final String dagger2_version = "2.33"; - - public final String implementation = "com.google.dagger:dagger:" + dagger2_version; - public final String annotationProcessor = "com.google.dagger:dagger-compiler:" + dagger2_version; - } - - public static final class Junit5Libs { - private final String junit_version = "5.5.2"; - - public final String api = "org.junit.jupiter:junit-jupiter-api:" + junit_version; - /** runtimeOnly */ - public final String engine = "org.junit.jupiter:junit-jupiter-engine:" + junit_version; - public final String params = "org.junit.jupiter:junit-jupiter-params:" + junit_version; - } -} diff --git a/buildSrc/src/main/java/ru/dmitriymx/gradle/plugin/LibsPlugin.java b/buildSrc/src/main/java/ru/dmitriymx/gradle/plugin/LibsPlugin.java deleted file mode 100644 index 243fa5d..0000000 --- a/buildSrc/src/main/java/ru/dmitriymx/gradle/plugin/LibsPlugin.java +++ /dev/null @@ -1,13 +0,0 @@ -package ru.dmitriymx.gradle.plugin; - -import org.gradle.api.Plugin; -import org.gradle.api.Project; -import ru.dmitriymx.gradle.extention.LibsExtention; - -public class LibsPlugin implements Plugin { - - @Override - public void apply(Project project) { - project.getExtensions().create("libs", LibsExtention.class); - } -} From 65a2f4ef817dead73e1cd14264eeeb023c2b8cc4 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Mon, 26 Apr 2021 14:51:21 +0300 Subject: [PATCH 07/34] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=BD=D0=BE?= =?UTF-8?q?=D1=81=20=D0=B1=D0=B8=D0=B1=D0=BB=D0=B8=D0=BE=D1=82=D0=B5=D0=BA?= =?UTF-8?q?=20=D0=B2=20libs.gradle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 34 +--------------------------------- libs.gradle | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 33 deletions(-) create mode 100644 libs.gradle diff --git a/build.gradle b/build.gradle index fd18383..3180acf 100644 --- a/build.gradle +++ b/build.gradle @@ -9,39 +9,7 @@ plugins { } apply from: rootDir.toPath().resolve('logic.gradle').toFile() - -ext { - slf4j_version = '1.7.30' - logback_version = '1.2.3' - dagger2_version = '2.33' - junit_version = '5.5.2' - - libs = [ - lombok : 'org.projectlombok:lombok:1.18.12', - annotations: 'com.google.code.findbugs:jsr305:3.0.2', - guava : 'com.google.guava:guava:30.1-jre', - lang3 : 'org.apache.commons:commons-lang3:3.11', - ] - - libs.logger = [ - slf4j : ["org.slf4j:slf4j-api:${slf4j_version}", - "org.slf4j:jcl-over-slf4j:${slf4j_version}"], - logback: ["ch.qos.logback:logback-core:${logback_version}", - "ch.qos.logback:logback-classic:${logback_version}"] - ] - - libs.dagger2 = [ - implementation: "com.google.dagger:dagger:${dagger2_version}", - annotationProcessor: "com.google.dagger:dagger-compiler:${dagger2_version}" - ] - - libs.junit5 = [ - api: "org.junit.jupiter:junit-jupiter-api:${junit_version}", - //runtime only - engine: "org.junit.jupiter:junit-jupiter-engine:${junit_version}", - params: "org.junit.jupiter:junit-jupiter-params:${junit_version}" - ] -} +apply from: rootDir.toPath().resolve('libs.gradle').toFile() dependencies { annotationProcessor libs.lombok diff --git a/libs.gradle b/libs.gradle new file mode 100644 index 0000000..600bd97 --- /dev/null +++ b/libs.gradle @@ -0,0 +1,35 @@ +//file:noinspection GroovyAssignabilityCheck +//file:noinspection GrUnresolvedAccess + +def slf4j_version = '1.7.30' +def logback_version = '1.2.3' +def dagger2_version = '2.33' +def junit_version = '5.5.2' + +ext { + libs = [ + lombok : 'org.projectlombok:lombok:1.18.12', + annotations: 'com.google.code.findbugs:jsr305:3.0.2', + guava : 'com.google.guava:guava:30.1-jre', + lang3 : 'org.apache.commons:commons-lang3:3.11', + ] + + libs.logger = [ + slf4j : ["org.slf4j:slf4j-api:${slf4j_version}", + "org.slf4j:jcl-over-slf4j:${slf4j_version}"], + logback: ["ch.qos.logback:logback-core:${logback_version}", + "ch.qos.logback:logback-classic:${logback_version}"] + ] + + libs.dagger2 = [ + implementation : "com.google.dagger:dagger:${dagger2_version}", + annotationProcessor: "com.google.dagger:dagger-compiler:${dagger2_version}" + ] + + libs.junit5 = [ + api : "org.junit.jupiter:junit-jupiter-api:${junit_version}", + //runtime only + engine: "org.junit.jupiter:junit-jupiter-engine:${junit_version}", + params: "org.junit.jupiter:junit-jupiter-params:${junit_version}" + ] +} \ No newline at end of file From 38091e8685320ec64549f8ec4c0d951bdc7c0560 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Mon, 26 Apr 2021 15:02:54 +0300 Subject: [PATCH 08/34] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=BD=D0=BE?= =?UTF-8?q?=D1=81=20=D0=BA=D0=BE=D0=B4=D0=B0=20=D0=B2=20=D0=BF=D0=BE=D0=B4?= =?UTF-8?q?=D0=BC=D0=BE=D0=B4=D1=83=D0=BB=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- logic.gradle | 2 ++ build.gradle => server/build.gradle | 7 ++----- server/gradle.properties | 3 +++ .../src}/main/java/mc/protocol/NetworkAttributes.java | 0 {src => server/src}/main/java/mc/protocol/State.java | 0 .../src}/main/java/mc/protocol/io/DecoderException.java | 0 .../src}/main/java/mc/protocol/io/NetByteBuf.java | 0 .../main/java/mc/protocol/io/codec/ProtocolDecoder.java | 0 .../main/java/mc/protocol/io/codec/ProtocolEncoder.java | 0 .../main/java/mc/protocol/io/codec/ProtocolSplitter.java | 0 .../src}/main/java/mc/protocol/packets/EmptyPacket.java | 0 .../src}/main/java/mc/protocol/packets/Packet.java | 0 .../main/java/mc/protocol/packets/PacketDirection.java | 0 .../src}/main/java/mc/protocol/packets/UnknownPacket.java | 0 .../java/mc/protocol/packets/client/HandshakePacket.java | 0 .../java/mc/protocol/packets/client/LoginStartPacket.java | 0 .../mc/protocol/packets/client/StatusServerRequest.java | 0 .../java/mc/protocol/packets/server/DisconnectPacket.java | 0 .../mc/protocol/packets/server/StatusServerResponse.java | 0 {src => server/src}/main/java/mc/server/Main.java | 0 .../src}/main/java/mc/server/di/NetworkComponent.java | 0 .../src}/main/java/mc/server/di/NetworkModule.java | 0 .../src}/main/java/mc/server/network/Server.java | 0 .../main/java/mc/server/network/netty/NettyServer.java | 0 .../network/netty/handler/AbstractPacketHandler.java | 0 .../mc/server/network/netty/handler/HandshakeHandler.java | 0 .../java/mc/server/network/netty/handler/LoginHandler.java | 0 .../mc/server/network/netty/handler/StatusHandler.java | 0 {src => server/src}/main/resources/logback.xml | 0 .../src}/test/java/mc/protocol/io/NetByteBufReadTest.java | 0 .../src}/test/java/mc/protocol/io/NetByteBufWriteTest.java | 0 31 files changed, 7 insertions(+), 5 deletions(-) rename build.gradle => server/build.gradle (95%) create mode 100644 server/gradle.properties rename {src => server/src}/main/java/mc/protocol/NetworkAttributes.java (100%) rename {src => server/src}/main/java/mc/protocol/State.java (100%) rename {src => server/src}/main/java/mc/protocol/io/DecoderException.java (100%) rename {src => server/src}/main/java/mc/protocol/io/NetByteBuf.java (100%) rename {src => server/src}/main/java/mc/protocol/io/codec/ProtocolDecoder.java (100%) rename {src => server/src}/main/java/mc/protocol/io/codec/ProtocolEncoder.java (100%) rename {src => server/src}/main/java/mc/protocol/io/codec/ProtocolSplitter.java (100%) rename {src => server/src}/main/java/mc/protocol/packets/EmptyPacket.java (100%) rename {src => server/src}/main/java/mc/protocol/packets/Packet.java (100%) rename {src => server/src}/main/java/mc/protocol/packets/PacketDirection.java (100%) rename {src => server/src}/main/java/mc/protocol/packets/UnknownPacket.java (100%) rename {src => server/src}/main/java/mc/protocol/packets/client/HandshakePacket.java (100%) rename {src => server/src}/main/java/mc/protocol/packets/client/LoginStartPacket.java (100%) rename {src => server/src}/main/java/mc/protocol/packets/client/StatusServerRequest.java (100%) rename {src => server/src}/main/java/mc/protocol/packets/server/DisconnectPacket.java (100%) rename {src => server/src}/main/java/mc/protocol/packets/server/StatusServerResponse.java (100%) rename {src => server/src}/main/java/mc/server/Main.java (100%) rename {src => server/src}/main/java/mc/server/di/NetworkComponent.java (100%) rename {src => server/src}/main/java/mc/server/di/NetworkModule.java (100%) rename {src => server/src}/main/java/mc/server/network/Server.java (100%) rename {src => server/src}/main/java/mc/server/network/netty/NettyServer.java (100%) rename {src => server/src}/main/java/mc/server/network/netty/handler/AbstractPacketHandler.java (100%) rename {src => server/src}/main/java/mc/server/network/netty/handler/HandshakeHandler.java (100%) rename {src => server/src}/main/java/mc/server/network/netty/handler/LoginHandler.java (100%) rename {src => server/src}/main/java/mc/server/network/netty/handler/StatusHandler.java (100%) rename {src => server/src}/main/resources/logback.xml (100%) rename {src => server/src}/test/java/mc/protocol/io/NetByteBufReadTest.java (100%) rename {src => server/src}/test/java/mc/protocol/io/NetByteBufWriteTest.java (100%) diff --git a/logic.gradle b/logic.gradle index 0e9a252..9254004 100644 --- a/logic.gradle +++ b/logic.gradle @@ -1,3 +1,5 @@ +apply plugin: 'java' + String getProperty1(String propertyName1, String propertyName2) { return (String) (project.hasProperty(propertyName1) ? project.property(propertyName1) : project.property(propertyName2)) } diff --git a/build.gradle b/server/build.gradle similarity index 95% rename from build.gradle rename to server/build.gradle index 3180acf..2155b25 100644 --- a/build.gradle +++ b/server/build.gradle @@ -3,14 +3,11 @@ gradle run */ -plugins { - id 'java' - id 'application' -} - apply from: rootDir.toPath().resolve('logic.gradle').toFile() apply from: rootDir.toPath().resolve('libs.gradle').toFile() +apply plugin: 'application' + dependencies { annotationProcessor libs.lombok compileOnly libs.lombok diff --git a/server/gradle.properties b/server/gradle.properties new file mode 100644 index 0000000..e2373fb --- /dev/null +++ b/server/gradle.properties @@ -0,0 +1,3 @@ +# suppress inspection "UnusedProperty" for whole file +module.name=server +module.version=1.0-SNAPSHOT \ No newline at end of file diff --git a/src/main/java/mc/protocol/NetworkAttributes.java b/server/src/main/java/mc/protocol/NetworkAttributes.java similarity index 100% rename from src/main/java/mc/protocol/NetworkAttributes.java rename to server/src/main/java/mc/protocol/NetworkAttributes.java diff --git a/src/main/java/mc/protocol/State.java b/server/src/main/java/mc/protocol/State.java similarity index 100% rename from src/main/java/mc/protocol/State.java rename to server/src/main/java/mc/protocol/State.java diff --git a/src/main/java/mc/protocol/io/DecoderException.java b/server/src/main/java/mc/protocol/io/DecoderException.java similarity index 100% rename from src/main/java/mc/protocol/io/DecoderException.java rename to server/src/main/java/mc/protocol/io/DecoderException.java diff --git a/src/main/java/mc/protocol/io/NetByteBuf.java b/server/src/main/java/mc/protocol/io/NetByteBuf.java similarity index 100% rename from src/main/java/mc/protocol/io/NetByteBuf.java rename to server/src/main/java/mc/protocol/io/NetByteBuf.java diff --git a/src/main/java/mc/protocol/io/codec/ProtocolDecoder.java b/server/src/main/java/mc/protocol/io/codec/ProtocolDecoder.java similarity index 100% rename from src/main/java/mc/protocol/io/codec/ProtocolDecoder.java rename to server/src/main/java/mc/protocol/io/codec/ProtocolDecoder.java diff --git a/src/main/java/mc/protocol/io/codec/ProtocolEncoder.java b/server/src/main/java/mc/protocol/io/codec/ProtocolEncoder.java similarity index 100% rename from src/main/java/mc/protocol/io/codec/ProtocolEncoder.java rename to server/src/main/java/mc/protocol/io/codec/ProtocolEncoder.java diff --git a/src/main/java/mc/protocol/io/codec/ProtocolSplitter.java b/server/src/main/java/mc/protocol/io/codec/ProtocolSplitter.java similarity index 100% rename from src/main/java/mc/protocol/io/codec/ProtocolSplitter.java rename to server/src/main/java/mc/protocol/io/codec/ProtocolSplitter.java diff --git a/src/main/java/mc/protocol/packets/EmptyPacket.java b/server/src/main/java/mc/protocol/packets/EmptyPacket.java similarity index 100% rename from src/main/java/mc/protocol/packets/EmptyPacket.java rename to server/src/main/java/mc/protocol/packets/EmptyPacket.java diff --git a/src/main/java/mc/protocol/packets/Packet.java b/server/src/main/java/mc/protocol/packets/Packet.java similarity index 100% rename from src/main/java/mc/protocol/packets/Packet.java rename to server/src/main/java/mc/protocol/packets/Packet.java diff --git a/src/main/java/mc/protocol/packets/PacketDirection.java b/server/src/main/java/mc/protocol/packets/PacketDirection.java similarity index 100% rename from src/main/java/mc/protocol/packets/PacketDirection.java rename to server/src/main/java/mc/protocol/packets/PacketDirection.java diff --git a/src/main/java/mc/protocol/packets/UnknownPacket.java b/server/src/main/java/mc/protocol/packets/UnknownPacket.java similarity index 100% rename from src/main/java/mc/protocol/packets/UnknownPacket.java rename to server/src/main/java/mc/protocol/packets/UnknownPacket.java diff --git a/src/main/java/mc/protocol/packets/client/HandshakePacket.java b/server/src/main/java/mc/protocol/packets/client/HandshakePacket.java similarity index 100% rename from src/main/java/mc/protocol/packets/client/HandshakePacket.java rename to server/src/main/java/mc/protocol/packets/client/HandshakePacket.java diff --git a/src/main/java/mc/protocol/packets/client/LoginStartPacket.java b/server/src/main/java/mc/protocol/packets/client/LoginStartPacket.java similarity index 100% rename from src/main/java/mc/protocol/packets/client/LoginStartPacket.java rename to server/src/main/java/mc/protocol/packets/client/LoginStartPacket.java diff --git a/src/main/java/mc/protocol/packets/client/StatusServerRequest.java b/server/src/main/java/mc/protocol/packets/client/StatusServerRequest.java similarity index 100% rename from src/main/java/mc/protocol/packets/client/StatusServerRequest.java rename to server/src/main/java/mc/protocol/packets/client/StatusServerRequest.java diff --git a/src/main/java/mc/protocol/packets/server/DisconnectPacket.java b/server/src/main/java/mc/protocol/packets/server/DisconnectPacket.java similarity index 100% rename from src/main/java/mc/protocol/packets/server/DisconnectPacket.java rename to server/src/main/java/mc/protocol/packets/server/DisconnectPacket.java diff --git a/src/main/java/mc/protocol/packets/server/StatusServerResponse.java b/server/src/main/java/mc/protocol/packets/server/StatusServerResponse.java similarity index 100% rename from src/main/java/mc/protocol/packets/server/StatusServerResponse.java rename to server/src/main/java/mc/protocol/packets/server/StatusServerResponse.java diff --git a/src/main/java/mc/server/Main.java b/server/src/main/java/mc/server/Main.java similarity index 100% rename from src/main/java/mc/server/Main.java rename to server/src/main/java/mc/server/Main.java diff --git a/src/main/java/mc/server/di/NetworkComponent.java b/server/src/main/java/mc/server/di/NetworkComponent.java similarity index 100% rename from src/main/java/mc/server/di/NetworkComponent.java rename to server/src/main/java/mc/server/di/NetworkComponent.java diff --git a/src/main/java/mc/server/di/NetworkModule.java b/server/src/main/java/mc/server/di/NetworkModule.java similarity index 100% rename from src/main/java/mc/server/di/NetworkModule.java rename to server/src/main/java/mc/server/di/NetworkModule.java diff --git a/src/main/java/mc/server/network/Server.java b/server/src/main/java/mc/server/network/Server.java similarity index 100% rename from src/main/java/mc/server/network/Server.java rename to server/src/main/java/mc/server/network/Server.java diff --git a/src/main/java/mc/server/network/netty/NettyServer.java b/server/src/main/java/mc/server/network/netty/NettyServer.java similarity index 100% rename from src/main/java/mc/server/network/netty/NettyServer.java rename to server/src/main/java/mc/server/network/netty/NettyServer.java diff --git a/src/main/java/mc/server/network/netty/handler/AbstractPacketHandler.java b/server/src/main/java/mc/server/network/netty/handler/AbstractPacketHandler.java similarity index 100% rename from src/main/java/mc/server/network/netty/handler/AbstractPacketHandler.java rename to server/src/main/java/mc/server/network/netty/handler/AbstractPacketHandler.java diff --git a/src/main/java/mc/server/network/netty/handler/HandshakeHandler.java b/server/src/main/java/mc/server/network/netty/handler/HandshakeHandler.java similarity index 100% rename from src/main/java/mc/server/network/netty/handler/HandshakeHandler.java rename to server/src/main/java/mc/server/network/netty/handler/HandshakeHandler.java diff --git a/src/main/java/mc/server/network/netty/handler/LoginHandler.java b/server/src/main/java/mc/server/network/netty/handler/LoginHandler.java similarity index 100% rename from src/main/java/mc/server/network/netty/handler/LoginHandler.java rename to server/src/main/java/mc/server/network/netty/handler/LoginHandler.java diff --git a/src/main/java/mc/server/network/netty/handler/StatusHandler.java b/server/src/main/java/mc/server/network/netty/handler/StatusHandler.java similarity index 100% rename from src/main/java/mc/server/network/netty/handler/StatusHandler.java rename to server/src/main/java/mc/server/network/netty/handler/StatusHandler.java diff --git a/src/main/resources/logback.xml b/server/src/main/resources/logback.xml similarity index 100% rename from src/main/resources/logback.xml rename to server/src/main/resources/logback.xml diff --git a/src/test/java/mc/protocol/io/NetByteBufReadTest.java b/server/src/test/java/mc/protocol/io/NetByteBufReadTest.java similarity index 100% rename from src/test/java/mc/protocol/io/NetByteBufReadTest.java rename to server/src/test/java/mc/protocol/io/NetByteBufReadTest.java diff --git a/src/test/java/mc/protocol/io/NetByteBufWriteTest.java b/server/src/test/java/mc/protocol/io/NetByteBufWriteTest.java similarity index 100% rename from src/test/java/mc/protocol/io/NetByteBufWriteTest.java rename to server/src/test/java/mc/protocol/io/NetByteBufWriteTest.java From fcfcb16e6daeebbf13425b8adfc206807534ec2e Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Mon, 26 Apr 2021 15:27:59 +0300 Subject: [PATCH 09/34] =?UTF-8?q?=D1=80=D0=B0=D0=B7=D0=B4=D0=B5=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20mc.protocol=20=D0=B8=20mc.server=20?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=BF=D0=BE=D0=B4=D0=BC=D0=BE=D0=B4=D1=83=D0=BB?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.MD | 10 ++++++- libs.gradle | 7 ++++- logic.gradle | 27 +++++++++++++++-- protocol/build.gradle | 8 +++++ protocol/gradle.properties | 3 ++ .../java/mc/protocol/NetworkAttributes.java | 0 .../src/main/java/mc/protocol/State.java | 0 .../java/mc/protocol/io/DecoderException.java | 0 .../main/java/mc/protocol/io/NetByteBuf.java | 0 .../mc/protocol/io/codec/ProtocolDecoder.java | 0 .../mc/protocol/io/codec/ProtocolEncoder.java | 0 .../protocol/io/codec/ProtocolSplitter.java | 0 .../java/mc/protocol/packets/EmptyPacket.java | 0 .../main/java/mc/protocol/packets/Packet.java | 0 .../mc/protocol/packets/PacketDirection.java | 0 .../mc/protocol/packets/UnknownPacket.java | 0 .../packets/client/HandshakePacket.java | 0 .../packets/client/LoginStartPacket.java | 0 .../packets/client/StatusServerRequest.java | 0 .../packets/server/DisconnectPacket.java | 0 .../packets/server/StatusServerResponse.java | 0 .../mc/protocol/io/NetByteBufReadTest.java | 1 - .../mc/protocol/io/NetByteBufWriteTest.java | 0 server/build.gradle | 30 ++++--------------- settings.gradle | 1 + 25 files changed, 58 insertions(+), 29 deletions(-) create mode 100644 protocol/build.gradle create mode 100644 protocol/gradle.properties rename {server => protocol}/src/main/java/mc/protocol/NetworkAttributes.java (100%) rename {server => protocol}/src/main/java/mc/protocol/State.java (100%) rename {server => protocol}/src/main/java/mc/protocol/io/DecoderException.java (100%) rename {server => protocol}/src/main/java/mc/protocol/io/NetByteBuf.java (100%) rename {server => protocol}/src/main/java/mc/protocol/io/codec/ProtocolDecoder.java (100%) rename {server => protocol}/src/main/java/mc/protocol/io/codec/ProtocolEncoder.java (100%) rename {server => protocol}/src/main/java/mc/protocol/io/codec/ProtocolSplitter.java (100%) rename {server => protocol}/src/main/java/mc/protocol/packets/EmptyPacket.java (100%) rename {server => protocol}/src/main/java/mc/protocol/packets/Packet.java (100%) rename {server => protocol}/src/main/java/mc/protocol/packets/PacketDirection.java (100%) rename {server => protocol}/src/main/java/mc/protocol/packets/UnknownPacket.java (100%) rename {server => protocol}/src/main/java/mc/protocol/packets/client/HandshakePacket.java (100%) rename {server => protocol}/src/main/java/mc/protocol/packets/client/LoginStartPacket.java (100%) rename {server => protocol}/src/main/java/mc/protocol/packets/client/StatusServerRequest.java (100%) rename {server => protocol}/src/main/java/mc/protocol/packets/server/DisconnectPacket.java (100%) rename {server => protocol}/src/main/java/mc/protocol/packets/server/StatusServerResponse.java (100%) rename {server => protocol}/src/test/java/mc/protocol/io/NetByteBufReadTest.java (99%) rename {server => protocol}/src/test/java/mc/protocol/io/NetByteBufWriteTest.java (100%) diff --git a/README.MD b/README.MD index 3d7113f..f0e5040 100644 --- a/README.MD +++ b/README.MD @@ -6,4 +6,12 @@ --- -* Java 11 \ No newline at end of file +* Java 11 + +--- + +## Запуск + +```shell +gradle :server:run +``` \ No newline at end of file diff --git a/libs.gradle b/libs.gradle index 600bd97..365ee1a 100644 --- a/libs.gradle +++ b/libs.gradle @@ -1,5 +1,6 @@ //file:noinspection GroovyAssignabilityCheck //file:noinspection GrUnresolvedAccess +//file:noinspection GroovyConstructorNamedArguments def slf4j_version = '1.7.30' def logback_version = '1.2.3' @@ -26,7 +27,11 @@ ext { annotationProcessor: "com.google.dagger:dagger-compiler:${dagger2_version}" ] - libs.junit5 = [ + libs.test = [ + logger: "org.slf4j:slf4j-simple:${slf4j_version}" + ] + + libs.test.junit5 = [ api : "org.junit.jupiter:junit-jupiter-api:${junit_version}", //runtime only engine: "org.junit.jupiter:junit-jupiter-engine:${junit_version}", diff --git a/logic.gradle b/logic.gradle index 9254004..eb5630f 100644 --- a/logic.gradle +++ b/logic.gradle @@ -1,4 +1,6 @@ +//file:noinspection GrUnresolvedAccess apply plugin: 'java' +apply from: rootDir.toPath().resolve('libs.gradle').toFile() String getProperty1(String propertyName1, String propertyName2) { return (String) (project.hasProperty(propertyName1) ? project.property(propertyName1) : project.property(propertyName2)) @@ -6,7 +8,7 @@ String getProperty1(String propertyName1, String propertyName2) { project.group = getProperty1('module.group', 'project.group') project.version = getProperty1('module.version', 'project.version') -project.jar.archiveBaseName.set(getProperty1('module.name', 'project.name')) +jar.archiveBaseName.set(getProperty1('module.name', 'project.name')) compileJava { sourceCompatibility = targetCompatibility = JavaVersion.VERSION_11 @@ -16,4 +18,25 @@ compileJava { repositories { mavenLocal() mavenCentral() -} \ No newline at end of file +} + +dependencies { + annotationProcessor libs.lombok + compileOnly libs.lombok + compileOnly libs.annotations + + implementation libs.logger.slf4j + + implementation libs.dagger2.implementation + annotationProcessor libs.dagger2.annotationProcessor + + testImplementation libs.test.junit5.api + testImplementation libs.test.junit5.params + testRuntimeOnly libs.test.junit5.engine + + testRuntimeOnly libs.test.logger +} + +test { + useJUnitPlatform() +} diff --git a/protocol/build.gradle b/protocol/build.gradle new file mode 100644 index 0000000..4e4b0da --- /dev/null +++ b/protocol/build.gradle @@ -0,0 +1,8 @@ +apply from: rootDir.toPath().resolve('logic.gradle').toFile() + +dependencies { + implementation 'io.netty:netty-all:4.1.22.Final' + implementation libs.guava + + testImplementation libs.lang3 +} diff --git a/protocol/gradle.properties b/protocol/gradle.properties new file mode 100644 index 0000000..572e805 --- /dev/null +++ b/protocol/gradle.properties @@ -0,0 +1,3 @@ +# suppress inspection "UnusedProperty" for whole file +module.name=protocol +module.version=1.0-SNAPSHOT \ No newline at end of file diff --git a/server/src/main/java/mc/protocol/NetworkAttributes.java b/protocol/src/main/java/mc/protocol/NetworkAttributes.java similarity index 100% rename from server/src/main/java/mc/protocol/NetworkAttributes.java rename to protocol/src/main/java/mc/protocol/NetworkAttributes.java diff --git a/server/src/main/java/mc/protocol/State.java b/protocol/src/main/java/mc/protocol/State.java similarity index 100% rename from server/src/main/java/mc/protocol/State.java rename to protocol/src/main/java/mc/protocol/State.java diff --git a/server/src/main/java/mc/protocol/io/DecoderException.java b/protocol/src/main/java/mc/protocol/io/DecoderException.java similarity index 100% rename from server/src/main/java/mc/protocol/io/DecoderException.java rename to protocol/src/main/java/mc/protocol/io/DecoderException.java diff --git a/server/src/main/java/mc/protocol/io/NetByteBuf.java b/protocol/src/main/java/mc/protocol/io/NetByteBuf.java similarity index 100% rename from server/src/main/java/mc/protocol/io/NetByteBuf.java rename to protocol/src/main/java/mc/protocol/io/NetByteBuf.java diff --git a/server/src/main/java/mc/protocol/io/codec/ProtocolDecoder.java b/protocol/src/main/java/mc/protocol/io/codec/ProtocolDecoder.java similarity index 100% rename from server/src/main/java/mc/protocol/io/codec/ProtocolDecoder.java rename to protocol/src/main/java/mc/protocol/io/codec/ProtocolDecoder.java diff --git a/server/src/main/java/mc/protocol/io/codec/ProtocolEncoder.java b/protocol/src/main/java/mc/protocol/io/codec/ProtocolEncoder.java similarity index 100% rename from server/src/main/java/mc/protocol/io/codec/ProtocolEncoder.java rename to protocol/src/main/java/mc/protocol/io/codec/ProtocolEncoder.java diff --git a/server/src/main/java/mc/protocol/io/codec/ProtocolSplitter.java b/protocol/src/main/java/mc/protocol/io/codec/ProtocolSplitter.java similarity index 100% rename from server/src/main/java/mc/protocol/io/codec/ProtocolSplitter.java rename to protocol/src/main/java/mc/protocol/io/codec/ProtocolSplitter.java diff --git a/server/src/main/java/mc/protocol/packets/EmptyPacket.java b/protocol/src/main/java/mc/protocol/packets/EmptyPacket.java similarity index 100% rename from server/src/main/java/mc/protocol/packets/EmptyPacket.java rename to protocol/src/main/java/mc/protocol/packets/EmptyPacket.java diff --git a/server/src/main/java/mc/protocol/packets/Packet.java b/protocol/src/main/java/mc/protocol/packets/Packet.java similarity index 100% rename from server/src/main/java/mc/protocol/packets/Packet.java rename to protocol/src/main/java/mc/protocol/packets/Packet.java diff --git a/server/src/main/java/mc/protocol/packets/PacketDirection.java b/protocol/src/main/java/mc/protocol/packets/PacketDirection.java similarity index 100% rename from server/src/main/java/mc/protocol/packets/PacketDirection.java rename to protocol/src/main/java/mc/protocol/packets/PacketDirection.java diff --git a/server/src/main/java/mc/protocol/packets/UnknownPacket.java b/protocol/src/main/java/mc/protocol/packets/UnknownPacket.java similarity index 100% rename from server/src/main/java/mc/protocol/packets/UnknownPacket.java rename to protocol/src/main/java/mc/protocol/packets/UnknownPacket.java diff --git a/server/src/main/java/mc/protocol/packets/client/HandshakePacket.java b/protocol/src/main/java/mc/protocol/packets/client/HandshakePacket.java similarity index 100% rename from server/src/main/java/mc/protocol/packets/client/HandshakePacket.java rename to protocol/src/main/java/mc/protocol/packets/client/HandshakePacket.java diff --git a/server/src/main/java/mc/protocol/packets/client/LoginStartPacket.java b/protocol/src/main/java/mc/protocol/packets/client/LoginStartPacket.java similarity index 100% rename from server/src/main/java/mc/protocol/packets/client/LoginStartPacket.java rename to protocol/src/main/java/mc/protocol/packets/client/LoginStartPacket.java diff --git a/server/src/main/java/mc/protocol/packets/client/StatusServerRequest.java b/protocol/src/main/java/mc/protocol/packets/client/StatusServerRequest.java similarity index 100% rename from server/src/main/java/mc/protocol/packets/client/StatusServerRequest.java rename to protocol/src/main/java/mc/protocol/packets/client/StatusServerRequest.java diff --git a/server/src/main/java/mc/protocol/packets/server/DisconnectPacket.java b/protocol/src/main/java/mc/protocol/packets/server/DisconnectPacket.java similarity index 100% rename from server/src/main/java/mc/protocol/packets/server/DisconnectPacket.java rename to protocol/src/main/java/mc/protocol/packets/server/DisconnectPacket.java diff --git a/server/src/main/java/mc/protocol/packets/server/StatusServerResponse.java b/protocol/src/main/java/mc/protocol/packets/server/StatusServerResponse.java similarity index 100% rename from server/src/main/java/mc/protocol/packets/server/StatusServerResponse.java rename to protocol/src/main/java/mc/protocol/packets/server/StatusServerResponse.java diff --git a/server/src/test/java/mc/protocol/io/NetByteBufReadTest.java b/protocol/src/test/java/mc/protocol/io/NetByteBufReadTest.java similarity index 99% rename from server/src/test/java/mc/protocol/io/NetByteBufReadTest.java rename to protocol/src/test/java/mc/protocol/io/NetByteBufReadTest.java index c48b6b4..6337ec5 100644 --- a/server/src/test/java/mc/protocol/io/NetByteBufReadTest.java +++ b/protocol/src/test/java/mc/protocol/io/NetByteBufReadTest.java @@ -1,6 +1,5 @@ package mc.protocol.io; -import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/server/src/test/java/mc/protocol/io/NetByteBufWriteTest.java b/protocol/src/test/java/mc/protocol/io/NetByteBufWriteTest.java similarity index 100% rename from server/src/test/java/mc/protocol/io/NetByteBufWriteTest.java rename to protocol/src/test/java/mc/protocol/io/NetByteBufWriteTest.java diff --git a/server/build.gradle b/server/build.gradle index 2155b25..68acb11 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -1,41 +1,23 @@ /* Запуск - gradle run + gradle :server:run */ apply from: rootDir.toPath().resolve('logic.gradle').toFile() -apply from: rootDir.toPath().resolve('libs.gradle').toFile() - apply plugin: 'application' +application { + mainClassName = 'mc.server.Main' +} + dependencies { - annotationProcessor libs.lombok - compileOnly libs.lombok - compileOnly libs.annotations + implementation project(':protocol') - implementation libs.logger.slf4j implementation libs.logger.logback - implementation libs.dagger2.implementation - annotationProcessor libs.dagger2.annotationProcessor - implementation platform('io.projectreactor:reactor-bom:2020.0.6') implementation 'io.projectreactor:reactor-core' implementation 'io.netty:netty-all:4.1.22.Final' implementation libs.guava - - testImplementation libs.junit5.api - testImplementation libs.junit5.params - testRuntimeOnly libs.junit5.engine - - testImplementation libs.lang3 -} - -application { - mainClassName = 'mc.server.Main' -} - -test { - useJUnitPlatform() } diff --git a/settings.gradle b/settings.gradle index 925cad0..03dd498 100644 --- a/settings.gradle +++ b/settings.gradle @@ -10,4 +10,5 @@ rootProject.projectDir.toPath().resolve('gradle.properties').readLines().forEach rootProject.name = map.get('project.name') +include('protocol') include('server') \ No newline at end of file From eff6dcf1484368f4435ffc1cebd0f35d6fde2f05 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Mon, 26 Apr 2021 18:29:50 +0300 Subject: [PATCH 10/34] =?UTF-8?q?(BROKEN)=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=20PingPacket?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- protocol/src/main/java/mc/protocol/State.java | 11 ++++- .../java/mc/protocol/packets/PingPacket.java | 41 +++++++++++++++++++ .../packets/client/LoginStartPacket.java | 2 - .../main/java/mc/server/di/NetworkModule.java | 12 +++++- .../netty/handler/HandshakeHandler.java | 2 + .../netty/handler/KeepAliveHandler.java | 16 ++++++++ .../network/netty/handler/StatusHandler.java | 2 +- 7 files changed, 79 insertions(+), 7 deletions(-) create mode 100644 protocol/src/main/java/mc/protocol/packets/PingPacket.java create mode 100644 server/src/main/java/mc/server/network/netty/handler/KeepAliveHandler.java diff --git a/protocol/src/main/java/mc/protocol/State.java b/protocol/src/main/java/mc/protocol/State.java index 3d38333..b9b9d53 100644 --- a/protocol/src/main/java/mc/protocol/State.java +++ b/protocol/src/main/java/mc/protocol/State.java @@ -6,6 +6,7 @@ import lombok.Getter; import lombok.RequiredArgsConstructor; import mc.protocol.packets.Packet; import mc.protocol.packets.PacketDirection; +import mc.protocol.packets.PingPacket; import mc.protocol.packets.client.HandshakePacket; import mc.protocol.packets.client.LoginStartPacket; import mc.protocol.packets.client.StatusServerRequest; @@ -23,9 +24,15 @@ public enum State { ), STATUS(1, // server bound - ImmutableBiMap.of(0x00, StatusServerRequest.class), + ImmutableBiMap.of( + 0x00, StatusServerRequest.class, + 0x01, PingPacket.class + ), // client bound - ImmutableBiMap.of(0x00, StatusServerResponse.class) + ImmutableBiMap.of( + 0x00, StatusServerResponse.class, + 0x01, PingPacket.class + ) ), LOGIN(2, // server bound diff --git a/protocol/src/main/java/mc/protocol/packets/PingPacket.java b/protocol/src/main/java/mc/protocol/packets/PingPacket.java new file mode 100644 index 0000000..81e0b88 --- /dev/null +++ b/protocol/src/main/java/mc/protocol/packets/PingPacket.java @@ -0,0 +1,41 @@ +package mc.protocol.packets; + +import lombok.Data; +import mc.protocol.io.NetByteBuf; + +/** + * Пинг-пакет. + * + *

Эхо-пакет, которым проверяется качество соединения между Клиентом и Сервером.

+ * + *

По спецификации:

+ * + *
  • если Сервер не ответил Клиенту в течении 20 секунд, Клиент отключается + * и выдаёт ошибку "Timed out".
  • + *
  • если Клиент не отвечает Серверу в течении 30 секунд, Сервер отключает Клиента.
  • + *
    + * + *

    Структура пакета

    + *
    + * | FIELD   | TYPE | NOTES                  |
    + * |---------|------|------------------------|
    + * | Payload | Long | Любое уникальное число |
    + * 
    + * + * @see Keep Alive + */ +@Data +public class PingPacket implements Packet { + + private Long payload; + + @Override + public void readSelf(NetByteBuf netByteBuf) { + payload = netByteBuf.readLong(); + } + + @Override + public void writeSelf(NetByteBuf netByteBuf) { + netByteBuf.writeLong(payload); + } +} diff --git a/protocol/src/main/java/mc/protocol/packets/client/LoginStartPacket.java b/protocol/src/main/java/mc/protocol/packets/client/LoginStartPacket.java index 6fa953e..75ebe04 100644 --- a/protocol/src/main/java/mc/protocol/packets/client/LoginStartPacket.java +++ b/protocol/src/main/java/mc/protocol/packets/client/LoginStartPacket.java @@ -4,7 +4,6 @@ import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.ToString; -import mc.protocol.State; import mc.protocol.io.NetByteBuf; import mc.protocol.packets.Packet; @@ -21,7 +20,6 @@ import mc.protocol.packets.Packet; * * * @see Login start - * @see State */ @NoArgsConstructor @Getter diff --git a/server/src/main/java/mc/server/di/NetworkModule.java b/server/src/main/java/mc/server/di/NetworkModule.java index c5ca566..851566e 100644 --- a/server/src/main/java/mc/server/di/NetworkModule.java +++ b/server/src/main/java/mc/server/di/NetworkModule.java @@ -18,6 +18,7 @@ import mc.protocol.io.codec.ProtocolSplitter; import mc.server.network.Server; import mc.server.network.netty.handler.HandshakeHandler; import mc.server.network.netty.NettyServer; +import mc.server.network.netty.handler.KeepAliveHandler; import mc.server.network.netty.handler.LoginHandler; import mc.server.network.netty.handler.StatusHandler; @@ -59,7 +60,8 @@ public class NetworkModule { @Provides Map provideChannelHandlerMap( Provider statusHandlerProvider, - Provider loginHandlerProvider + Provider loginHandlerProvider, + Provider keepAliveHandlerProvider ) { Map map = new LinkedHashMap<>(); @@ -67,7 +69,8 @@ public class NetworkModule { map.put("protocol_splitter", new ProtocolSplitter()); map.put("protocol_decoder", new ProtocolDecoder(true)); map.put("protocol_encoder", new ProtocolEncoder()); - map.put("handshake_handler", new HandshakeHandler(statusHandlerProvider, loginHandlerProvider)); + map.put("handshake_handler", new HandshakeHandler( + statusHandlerProvider, loginHandlerProvider, keepAliveHandlerProvider)); return map; } @@ -81,4 +84,9 @@ public class NetworkModule { LoginHandler provideLoginHandler() { return new LoginHandler(); } + + @Provides + KeepAliveHandler provideKeepAliveHandler() { + return new KeepAliveHandler(); + } } diff --git a/server/src/main/java/mc/server/network/netty/handler/HandshakeHandler.java b/server/src/main/java/mc/server/network/netty/handler/HandshakeHandler.java index 5f31d3e..02b19e0 100644 --- a/server/src/main/java/mc/server/network/netty/handler/HandshakeHandler.java +++ b/server/src/main/java/mc/server/network/netty/handler/HandshakeHandler.java @@ -15,6 +15,7 @@ public class HandshakeHandler extends AbstractPacketHandler { private final Provider statusHandlerProvider; private final Provider loginHandlerProvider; + private final Provider keepAliveHandlerProvider; @Override protected void channelRead1(ChannelHandlerContext ctx, HandshakePacket packet) { @@ -24,6 +25,7 @@ public class HandshakeHandler extends AbstractPacketHandler { if (State.STATUS == packet.getNextState()) { ctx.pipeline().replace("handshake_handler", "status_handler", statusHandlerProvider.get()); + ctx.pipeline().addAfter("status_handler", "keepalive_handler", keepAliveHandlerProvider.get()); } else if (State.LOGIN == packet.getNextState()) { ctx.channel().pipeline().replace("handshake_handler", "login_handler", loginHandlerProvider.get()); } diff --git a/server/src/main/java/mc/server/network/netty/handler/KeepAliveHandler.java b/server/src/main/java/mc/server/network/netty/handler/KeepAliveHandler.java new file mode 100644 index 0000000..ea69c2c --- /dev/null +++ b/server/src/main/java/mc/server/network/netty/handler/KeepAliveHandler.java @@ -0,0 +1,16 @@ +package mc.server.network.netty.handler; + +import io.netty.channel.ChannelHandlerContext; +import lombok.extern.slf4j.Slf4j; +import mc.protocol.packets.PingPacket; + +@Slf4j +public class KeepAliveHandler extends AbstractPacketHandler { + + @Override + protected void channelRead1(ChannelHandlerContext ctx, PingPacket packet) { + log.info("{}", packet); + + ctx.writeAndFlush(packet).channel().disconnect(); + } +} diff --git a/server/src/main/java/mc/server/network/netty/handler/StatusHandler.java b/server/src/main/java/mc/server/network/netty/handler/StatusHandler.java index 0628875..2fbcfe5 100644 --- a/server/src/main/java/mc/server/network/netty/handler/StatusHandler.java +++ b/server/src/main/java/mc/server/network/netty/handler/StatusHandler.java @@ -28,6 +28,6 @@ public class StatusHandler extends AbstractPacketHandler { " }\n" + "}"); - ctx.channel().writeAndFlush(response).channel().disconnect(); + ctx.channel().writeAndFlush(response); } } From 2a1992b6dd8a276571360bba1ad6b17a52623dcc Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Tue, 27 Apr 2021 00:10:55 +0300 Subject: [PATCH 11/34] =?UTF-8?q?=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=B0=D0=B1=D1=81=D1=82=D1=80=D0=B0=D0=BA=D1=86=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=BD=D0=B0=D0=B4=20NettyServer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs.gradle | 2 + protocol/build.gradle | 3 +- .../main/java/mc/protocol/ChannelContext.java | 20 ++++++ .../main/java/mc/protocol/NettyServer.java | 43 +++++++++++++ .../mc/protocol/PacketInboundHandler.java | 21 ++++++ protocol/src/main/java/mc/protocol/State.java | 1 + .../mc/protocol/di/ProtocolComponent.java | 11 ++++ .../java/mc/protocol/di/ProtocolModule.java | 64 +++++++++---------- .../main/java/mc/protocol/di/ServerScope.java | 10 +++ server/build.gradle | 6 +- server/src/main/java/mc/server/Main.java | 55 ++++++++++++++-- .../java/mc/server/di/NetworkComponent.java | 10 --- .../main/java/mc/server/network/Server.java | 6 -- .../mc/server/network/netty/NettyServer.java | 26 -------- .../netty/handler/AbstractPacketHandler.java | 17 ----- .../netty/handler/HandshakeHandler.java | 33 ---------- .../netty/handler/KeepAliveHandler.java | 16 ----- .../network/netty/handler/LoginHandler.java | 18 ------ .../network/netty/handler/StatusHandler.java | 33 ---------- 19 files changed, 194 insertions(+), 201 deletions(-) create mode 100644 protocol/src/main/java/mc/protocol/ChannelContext.java create mode 100644 protocol/src/main/java/mc/protocol/NettyServer.java create mode 100644 protocol/src/main/java/mc/protocol/PacketInboundHandler.java create mode 100644 protocol/src/main/java/mc/protocol/di/ProtocolComponent.java rename server/src/main/java/mc/server/di/NetworkModule.java => protocol/src/main/java/mc/protocol/di/ProtocolModule.java (52%) create mode 100644 protocol/src/main/java/mc/protocol/di/ServerScope.java delete mode 100644 server/src/main/java/mc/server/di/NetworkComponent.java delete mode 100644 server/src/main/java/mc/server/network/Server.java delete mode 100644 server/src/main/java/mc/server/network/netty/NettyServer.java delete mode 100644 server/src/main/java/mc/server/network/netty/handler/AbstractPacketHandler.java delete mode 100644 server/src/main/java/mc/server/network/netty/handler/HandshakeHandler.java delete mode 100644 server/src/main/java/mc/server/network/netty/handler/KeepAliveHandler.java delete mode 100644 server/src/main/java/mc/server/network/netty/handler/LoginHandler.java delete mode 100644 server/src/main/java/mc/server/network/netty/handler/StatusHandler.java diff --git a/libs.gradle b/libs.gradle index 365ee1a..d6958eb 100644 --- a/libs.gradle +++ b/libs.gradle @@ -13,6 +13,8 @@ ext { annotations: 'com.google.code.findbugs:jsr305:3.0.2', guava : 'com.google.guava:guava:30.1-jre', 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' ] libs.logger = [ diff --git a/protocol/build.gradle b/protocol/build.gradle index 4e4b0da..4677d8a 100644 --- a/protocol/build.gradle +++ b/protocol/build.gradle @@ -1,7 +1,8 @@ apply from: rootDir.toPath().resolve('logic.gradle').toFile() dependencies { - implementation 'io.netty:netty-all:4.1.22.Final' + implementation libs.netty + implementation libs.reactor implementation libs.guava testImplementation libs.lang3 diff --git a/protocol/src/main/java/mc/protocol/ChannelContext.java b/protocol/src/main/java/mc/protocol/ChannelContext.java new file mode 100644 index 0000000..ba85b49 --- /dev/null +++ b/protocol/src/main/java/mc/protocol/ChannelContext.java @@ -0,0 +1,20 @@ +package mc.protocol; + +import io.netty.channel.ChannelHandlerContext; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import mc.protocol.packets.Packet; + +@RequiredArgsConstructor +public class ChannelContext

    { + + @Getter + private final ChannelHandlerContext ctx; + + @Getter + private final P packet; + + public void setState(State state) { + ctx.channel().attr(NetworkAttributes.STATE).set(state); + } +} diff --git a/protocol/src/main/java/mc/protocol/NettyServer.java b/protocol/src/main/java/mc/protocol/NettyServer.java new file mode 100644 index 0000000..b2f20fc --- /dev/null +++ b/protocol/src/main/java/mc/protocol/NettyServer.java @@ -0,0 +1,43 @@ +package mc.protocol; + +import io.netty.bootstrap.ServerBootstrap; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import mc.protocol.di.DaggerProtocolComponent; +import mc.protocol.di.ProtocolComponent; +import mc.protocol.packets.Packet; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Sinks; + +import java.util.Map; + +@SuppressWarnings("rawtypes") +@Slf4j +@RequiredArgsConstructor +public class NettyServer { + + private final ServerBootstrap serverBootstrap; + private final Map, Sinks.Many> observedMap; + + public void bind(String host, int port) { + log.info("Network starting: {}:{}", host, port); + + try { + serverBootstrap.bind(host, port).sync().channel().closeFuture().sync(); + } catch (InterruptedException e) { + if (log.isTraceEnabled()) { + log.trace("{}: {}", e.getClass().getSimpleName(), e.getMessage(), e); + } + } + } + + @SuppressWarnings("unchecked") + public

    Flux> packetFlux(Class

    packetClass) { + return observedMap.get(packetClass).asFlux().map(ChannelContext.class::cast); + } + + public static NettyServer createServer() { + ProtocolComponent component = DaggerProtocolComponent.create(); + return component.getNettyServer(); + } +} diff --git a/protocol/src/main/java/mc/protocol/PacketInboundHandler.java b/protocol/src/main/java/mc/protocol/PacketInboundHandler.java new file mode 100644 index 0000000..451f3b7 --- /dev/null +++ b/protocol/src/main/java/mc/protocol/PacketInboundHandler.java @@ -0,0 +1,21 @@ +package mc.protocol; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import lombok.RequiredArgsConstructor; +import mc.protocol.packets.Packet; +import reactor.core.publisher.Sinks; + +import java.util.Map; + +@SuppressWarnings("rawtypes") +@RequiredArgsConstructor +public class PacketInboundHandler extends SimpleChannelInboundHandler { + + private final Map, Sinks.Many> observedMap; + + @Override + protected void channelRead0(ChannelHandlerContext ctx, Packet packet) { + observedMap.get(packet.getClass()).tryEmitNext(new ChannelContext<>(ctx, packet)); + } +} diff --git a/protocol/src/main/java/mc/protocol/State.java b/protocol/src/main/java/mc/protocol/State.java index b9b9d53..01c2971 100644 --- a/protocol/src/main/java/mc/protocol/State.java +++ b/protocol/src/main/java/mc/protocol/State.java @@ -55,6 +55,7 @@ public enum State { @Getter private final int id; + @Getter private final BiMap> serverBoundPackets; private final BiMap> clientBoundPackets; diff --git a/protocol/src/main/java/mc/protocol/di/ProtocolComponent.java b/protocol/src/main/java/mc/protocol/di/ProtocolComponent.java new file mode 100644 index 0000000..a433211 --- /dev/null +++ b/protocol/src/main/java/mc/protocol/di/ProtocolComponent.java @@ -0,0 +1,11 @@ +package mc.protocol.di; + +import dagger.Component; +import mc.protocol.NettyServer; + +@Component(modules = ProtocolModule.class) +@ServerScope +public interface ProtocolComponent { + + NettyServer getNettyServer(); +} diff --git a/server/src/main/java/mc/server/di/NetworkModule.java b/protocol/src/main/java/mc/protocol/di/ProtocolModule.java similarity index 52% rename from server/src/main/java/mc/server/di/NetworkModule.java rename to protocol/src/main/java/mc/protocol/di/ProtocolModule.java index 851566e..3ee3ba3 100644 --- a/server/src/main/java/mc/server/di/NetworkModule.java +++ b/protocol/src/main/java/mc/protocol/di/ProtocolModule.java @@ -1,5 +1,6 @@ -package mc.server.di; +package mc.protocol.di; +import com.google.common.collect.ImmutableMap; import dagger.Module; import dagger.Provides; import io.netty.bootstrap.ServerBootstrap; @@ -11,28 +12,29 @@ import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; -import lombok.extern.slf4j.Slf4j; +import mc.protocol.ChannelContext; +import mc.protocol.NettyServer; +import mc.protocol.PacketInboundHandler; +import mc.protocol.State; import mc.protocol.io.codec.ProtocolDecoder; import mc.protocol.io.codec.ProtocolEncoder; import mc.protocol.io.codec.ProtocolSplitter; -import mc.server.network.Server; -import mc.server.network.netty.handler.HandshakeHandler; -import mc.server.network.netty.NettyServer; -import mc.server.network.netty.handler.KeepAliveHandler; -import mc.server.network.netty.handler.LoginHandler; -import mc.server.network.netty.handler.StatusHandler; +import mc.protocol.packets.Packet; +import reactor.core.publisher.Sinks; import javax.inject.Provider; import java.util.LinkedHashMap; import java.util.Map; +import java.util.stream.Stream; @Module -@Slf4j -public class NetworkModule { +public class ProtocolModule { + @SuppressWarnings("rawtypes") @Provides - Server provideServer(ServerBootstrap serverBootstrap) { - return new NettyServer(serverBootstrap); + NettyServer provideServer(ServerBootstrap serverBootstrap, + Map, Sinks.Many> observedMap) { + return new NettyServer(serverBootstrap, observedMap); } @Provides @@ -47,7 +49,9 @@ public class NetworkModule { } @Provides - ChannelInitializer provideChannelChannelInitializer(Provider> channelHandlerMapProvider) { + ChannelInitializer provideChannelChannelInitializer( + Provider> channelHandlerMapProvider) { + return new ChannelInitializer<>() { @Override protected void initChannel(SocketChannel socketChannel) { @@ -57,36 +61,32 @@ public class NetworkModule { }; } + @SuppressWarnings("rawtypes") @Provides Map provideChannelHandlerMap( - Provider statusHandlerProvider, - Provider loginHandlerProvider, - Provider keepAliveHandlerProvider - ) { + Map, Sinks.Many> observedMap) { + Map map = new LinkedHashMap<>(); + map.put("packet_splitter", new ProtocolSplitter()); map.put("logger", new LoggingHandler(LogLevel.DEBUG)); - map.put("protocol_splitter", new ProtocolSplitter()); - map.put("protocol_decoder", new ProtocolDecoder(true)); - map.put("protocol_encoder", new ProtocolEncoder()); - map.put("handshake_handler", new HandshakeHandler( - statusHandlerProvider, loginHandlerProvider, keepAliveHandlerProvider)); + map.put("packet_decoder", new ProtocolDecoder(true)); + map.put("packet_encoder", new ProtocolEncoder()); + map.put("packet_handler", new PacketInboundHandler(observedMap)); return map; } + @SuppressWarnings("rawtypes") @Provides - StatusHandler provideStatusHandler() { - return new StatusHandler(); - } + @ServerScope + Map, Sinks.Many> provideObservedMap() { + ImmutableMap.Builder, Sinks.Many> builder = ImmutableMap.builder(); - @Provides - LoginHandler provideLoginHandler() { - return new LoginHandler(); - } + Stream.of(State.values()) + .flatMap(state -> state.getServerBoundPackets().values().stream()) + .forEach(packetClass -> builder.put(packetClass, Sinks.many().multicast().directBestEffort())); - @Provides - KeepAliveHandler provideKeepAliveHandler() { - return new KeepAliveHandler(); + return builder.build(); } } diff --git a/protocol/src/main/java/mc/protocol/di/ServerScope.java b/protocol/src/main/java/mc/protocol/di/ServerScope.java new file mode 100644 index 0000000..b90e94e --- /dev/null +++ b/protocol/src/main/java/mc/protocol/di/ServerScope.java @@ -0,0 +1,10 @@ +package mc.protocol.di; + +import javax.inject.Scope; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Scope +@Retention(RetentionPolicy.RUNTIME) +public @interface ServerScope { +} diff --git a/server/build.gradle b/server/build.gradle index 68acb11..491cc7b 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -15,9 +15,7 @@ dependencies { implementation libs.logger.logback - implementation platform('io.projectreactor:reactor-bom:2020.0.6') - implementation 'io.projectreactor:reactor-core' - - implementation 'io.netty:netty-all:4.1.22.Final' + implementation libs.netty + implementation libs.reactor implementation libs.guava } diff --git a/server/src/main/java/mc/server/Main.java b/server/src/main/java/mc/server/Main.java index a435547..d0a445b 100644 --- a/server/src/main/java/mc/server/Main.java +++ b/server/src/main/java/mc/server/Main.java @@ -1,9 +1,13 @@ package mc.server; import lombok.extern.slf4j.Slf4j; -import mc.server.di.DaggerNetworkComponent; -import mc.server.di.NetworkComponent; -import mc.server.network.Server; +import mc.protocol.NettyServer; +import mc.protocol.packets.PingPacket; +import mc.protocol.packets.client.HandshakePacket; +import mc.protocol.packets.client.LoginStartPacket; +import mc.protocol.packets.client.StatusServerRequest; +import mc.protocol.packets.server.DisconnectPacket; +import mc.protocol.packets.server.StatusServerResponse; @Slf4j public class Main { @@ -11,8 +15,49 @@ public class Main { public static void main(String[] args) { log.info("hello"); - NetworkComponent networkComponent = DaggerNetworkComponent.create(); - Server server = networkComponent.getServer(); + NettyServer server = NettyServer.createServer(); + + server.packetFlux(HandshakePacket.class) + .doOnNext(channel -> log.info("{}", channel.getPacket())) + .subscribe(channel -> channel.setState(channel.getPacket().getNextState())); + + server.packetFlux(PingPacket.class) + .doOnNext(channel -> log.info("{}", channel.getPacket())) + .subscribe(channel -> channel.getCtx().writeAndFlush(channel.getPacket()).channel().disconnect()); + + server.packetFlux(StatusServerRequest.class) + .doOnNext(channel -> log.info("{}", channel.getPacket())) + .subscribe(channel -> { + StatusServerResponse response = new StatusServerResponse(); + response.setInfo("{\n" + + " \"version\": {\n" + + " \"name\": \"1.12.2\",\n" + + " \"protocol\": 340\n" + + " },\n" + + " \"players\": {\n" + + " \"max\": 0,\n" + + " \"online\": 0,\n" + + " \"sample\": []\n" + + " },\n" + + " \"description\": {\n" + + " \"text\": \"Hello world\"\n" + + " }\n" + + "}"); + + channel.getCtx().writeAndFlush(response); + }); + + server.packetFlux(LoginStartPacket.class) + .doOnNext(channel -> log.info("{}", channel.getPacket())) + .subscribe(channel -> { + DisconnectPacket disconnectPacket = new DisconnectPacket(); + disconnectPacket.setReason("{\n" + + " \"text\": \"Server is not available.\"\n" + + "}"); + + channel.getCtx().writeAndFlush(disconnectPacket).channel().disconnect(); + }); + server.bind("127.0.0.1", 25565); } } diff --git a/server/src/main/java/mc/server/di/NetworkComponent.java b/server/src/main/java/mc/server/di/NetworkComponent.java deleted file mode 100644 index ae73ed9..0000000 --- a/server/src/main/java/mc/server/di/NetworkComponent.java +++ /dev/null @@ -1,10 +0,0 @@ -package mc.server.di; - -import dagger.Component; -import mc.server.network.Server; - -@Component(modules = NetworkModule.class) -public interface NetworkComponent { - - Server getServer(); -} diff --git a/server/src/main/java/mc/server/network/Server.java b/server/src/main/java/mc/server/network/Server.java deleted file mode 100644 index b346a17..0000000 --- a/server/src/main/java/mc/server/network/Server.java +++ /dev/null @@ -1,6 +0,0 @@ -package mc.server.network; - -public interface Server { - - void bind(String host, int port); -} diff --git a/server/src/main/java/mc/server/network/netty/NettyServer.java b/server/src/main/java/mc/server/network/netty/NettyServer.java deleted file mode 100644 index 881914c..0000000 --- a/server/src/main/java/mc/server/network/netty/NettyServer.java +++ /dev/null @@ -1,26 +0,0 @@ -package mc.server.network.netty; - -import io.netty.bootstrap.ServerBootstrap; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import mc.server.network.Server; - -@Slf4j -@RequiredArgsConstructor -public class NettyServer implements Server { - - private final ServerBootstrap serverBootstrap; - - @Override - public void bind(String host, int port) { - log.info("Network starting: {}:{}", host, port); - - try { - serverBootstrap.bind(host, port).sync().channel().closeFuture().sync(); - } catch (InterruptedException e) { - if (log.isTraceEnabled()) { - log.trace("{}: {}", e.getClass().getSimpleName(), e.getMessage(), e); - } - } - } -} diff --git a/server/src/main/java/mc/server/network/netty/handler/AbstractPacketHandler.java b/server/src/main/java/mc/server/network/netty/handler/AbstractPacketHandler.java deleted file mode 100644 index 3d2d900..0000000 --- a/server/src/main/java/mc/server/network/netty/handler/AbstractPacketHandler.java +++ /dev/null @@ -1,17 +0,0 @@ -package mc.server.network.netty.handler; - -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.SimpleChannelInboundHandler; -import mc.protocol.packets.Packet; - -public abstract class AbstractPacketHandler

    extends SimpleChannelInboundHandler { - - @SuppressWarnings("unchecked") - @Override - protected void channelRead0(ChannelHandlerContext ctx, Packet msg) throws Exception { - channelRead1(ctx, (P) msg); - } - - @SuppressWarnings("java:S112") - protected abstract void channelRead1(ChannelHandlerContext ctx, P packet) throws Exception; -} diff --git a/server/src/main/java/mc/server/network/netty/handler/HandshakeHandler.java b/server/src/main/java/mc/server/network/netty/handler/HandshakeHandler.java deleted file mode 100644 index 02b19e0..0000000 --- a/server/src/main/java/mc/server/network/netty/handler/HandshakeHandler.java +++ /dev/null @@ -1,33 +0,0 @@ -package mc.server.network.netty.handler; - -import io.netty.channel.ChannelHandlerContext; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import mc.protocol.NetworkAttributes; -import mc.protocol.State; -import mc.protocol.packets.client.HandshakePacket; - -import javax.inject.Provider; - -@Slf4j -@RequiredArgsConstructor -public class HandshakeHandler extends AbstractPacketHandler { - - private final Provider statusHandlerProvider; - private final Provider loginHandlerProvider; - private final Provider keepAliveHandlerProvider; - - @Override - protected void channelRead1(ChannelHandlerContext ctx, HandshakePacket packet) { - log.info("{}", packet); - - ctx.channel().attr(NetworkAttributes.STATE).set(packet.getNextState()); - - if (State.STATUS == packet.getNextState()) { - ctx.pipeline().replace("handshake_handler", "status_handler", statusHandlerProvider.get()); - ctx.pipeline().addAfter("status_handler", "keepalive_handler", keepAliveHandlerProvider.get()); - } else if (State.LOGIN == packet.getNextState()) { - ctx.channel().pipeline().replace("handshake_handler", "login_handler", loginHandlerProvider.get()); - } - } -} diff --git a/server/src/main/java/mc/server/network/netty/handler/KeepAliveHandler.java b/server/src/main/java/mc/server/network/netty/handler/KeepAliveHandler.java deleted file mode 100644 index ea69c2c..0000000 --- a/server/src/main/java/mc/server/network/netty/handler/KeepAliveHandler.java +++ /dev/null @@ -1,16 +0,0 @@ -package mc.server.network.netty.handler; - -import io.netty.channel.ChannelHandlerContext; -import lombok.extern.slf4j.Slf4j; -import mc.protocol.packets.PingPacket; - -@Slf4j -public class KeepAliveHandler extends AbstractPacketHandler { - - @Override - protected void channelRead1(ChannelHandlerContext ctx, PingPacket packet) { - log.info("{}", packet); - - ctx.writeAndFlush(packet).channel().disconnect(); - } -} diff --git a/server/src/main/java/mc/server/network/netty/handler/LoginHandler.java b/server/src/main/java/mc/server/network/netty/handler/LoginHandler.java deleted file mode 100644 index 8a0d92c..0000000 --- a/server/src/main/java/mc/server/network/netty/handler/LoginHandler.java +++ /dev/null @@ -1,18 +0,0 @@ -package mc.server.network.netty.handler; - -import io.netty.channel.ChannelHandlerContext; -import mc.protocol.packets.client.LoginStartPacket; -import mc.protocol.packets.server.DisconnectPacket; - -public class LoginHandler extends AbstractPacketHandler { - - @Override - protected void channelRead1(ChannelHandlerContext ctx, LoginStartPacket packet) { - DisconnectPacket disconnectPacket = new DisconnectPacket(); - disconnectPacket.setReason("{\n" + - " \"text\": \"Server is not available.\"\n" + - "}"); - - ctx.channel().writeAndFlush(disconnectPacket).channel().disconnect(); - } -} diff --git a/server/src/main/java/mc/server/network/netty/handler/StatusHandler.java b/server/src/main/java/mc/server/network/netty/handler/StatusHandler.java deleted file mode 100644 index 2fbcfe5..0000000 --- a/server/src/main/java/mc/server/network/netty/handler/StatusHandler.java +++ /dev/null @@ -1,33 +0,0 @@ -package mc.server.network.netty.handler; - -import io.netty.channel.ChannelHandlerContext; -import lombok.extern.slf4j.Slf4j; -import mc.protocol.packets.client.StatusServerRequest; -import mc.protocol.packets.server.StatusServerResponse; - -@Slf4j -public class StatusHandler extends AbstractPacketHandler { - - @Override - protected void channelRead1(ChannelHandlerContext ctx, StatusServerRequest packet) { - log.info("{}", packet); - - StatusServerResponse response = new StatusServerResponse(); - response.setInfo("{\n" + - " \"version\": {\n" + - " \"name\": \"1.12.2\",\n" + - " \"protocol\": 340\n" + - " },\n" + - " \"players\": {\n" + - " \"max\": 0,\n" + - " \"online\": 0,\n" + - " \"sample\": []\n" + - " },\n" + - " \"description\": {\n" + - " \"text\": \"Hello world\"\n" + - " }\n" + - "}"); - - ctx.channel().writeAndFlush(response); - } -} From 801e68ea551e2fccf98b78299bf95630e4c89f06 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Tue, 27 Apr 2021 21:32:16 +0300 Subject: [PATCH 12/34] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20config?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs.gradle | 3 +- .../java/mc/protocol/ProtocolConstant.java | 10 +++ server/build.gradle | 2 + server/src/main/java/mc/server/Main.java | 34 ++++++++-- .../main/java/mc/server/config/Config.java | 35 ++++++++++ .../main/java/mc/server/config/lombok.config | 1 + .../main/java/mc/server/di/ConfigModule.java | 66 +++++++++++++++++++ .../java/mc/server/di/ServerComponent.java | 10 +++ server/src/main/resources/config.yml | 13 ++++ 9 files changed, 166 insertions(+), 8 deletions(-) create mode 100644 protocol/src/main/java/mc/protocol/ProtocolConstant.java create mode 100644 server/src/main/java/mc/server/config/Config.java create mode 100644 server/src/main/java/mc/server/config/lombok.config create mode 100644 server/src/main/java/mc/server/di/ConfigModule.java create mode 100644 server/src/main/java/mc/server/di/ServerComponent.java create mode 100644 server/src/main/resources/config.yml diff --git a/libs.gradle b/libs.gradle index d6958eb..33ed495 100644 --- a/libs.gradle +++ b/libs.gradle @@ -14,7 +14,8 @@ ext { guava : 'com.google.guava:guava:30.1-jre', 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' + reactor : 'io.projectreactor:reactor-core:3.4.5', + yaml : 'org.yaml:snakeyaml:1.28' ] libs.logger = [ diff --git a/protocol/src/main/java/mc/protocol/ProtocolConstant.java b/protocol/src/main/java/mc/protocol/ProtocolConstant.java new file mode 100644 index 0000000..4fbbada --- /dev/null +++ b/protocol/src/main/java/mc/protocol/ProtocolConstant.java @@ -0,0 +1,10 @@ +package mc.protocol; + +import lombok.experimental.UtilityClass; + +@UtilityClass +public class ProtocolConstant { + + public static final String PROTOCOL_NAME = "1.12.2"; + public static final int PROTOCOL_NUMBER = 340; +} diff --git a/server/build.gradle b/server/build.gradle index 491cc7b..46c8b98 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -3,6 +3,7 @@ gradle :server:run */ +//file:noinspection GrUnresolvedAccess apply from: rootDir.toPath().resolve('logic.gradle').toFile() apply plugin: 'application' @@ -18,4 +19,5 @@ dependencies { implementation libs.netty implementation libs.reactor implementation libs.guava + implementation libs.yaml } diff --git a/server/src/main/java/mc/server/Main.java b/server/src/main/java/mc/server/Main.java index d0a445b..7736a56 100644 --- a/server/src/main/java/mc/server/Main.java +++ b/server/src/main/java/mc/server/Main.java @@ -2,18 +2,38 @@ package mc.server; import lombok.extern.slf4j.Slf4j; import mc.protocol.NettyServer; +import mc.protocol.ProtocolConstant; import mc.protocol.packets.PingPacket; import mc.protocol.packets.client.HandshakePacket; import mc.protocol.packets.client.LoginStartPacket; import mc.protocol.packets.client.StatusServerRequest; import mc.protocol.packets.server.DisconnectPacket; 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; @Slf4j public class Main { public static void main(String[] args) { - log.info("hello"); + log.info("mc-project launch"); + + ConfigModule configModule; + if (args.length > 0) { + configModule = new ConfigModule(Paths.get(args[0])); + } else { + configModule = new ConfigModule(Paths.get("config.yml")); + } + + ServerComponent serverComponent = DaggerServerComponent.builder() + .configModule(configModule) + .build(); + + Config config = serverComponent.getConfig(); NettyServer server = NettyServer.createServer(); @@ -31,16 +51,16 @@ public class Main { StatusServerResponse response = new StatusServerResponse(); response.setInfo("{\n" + " \"version\": {\n" + - " \"name\": \"1.12.2\",\n" + - " \"protocol\": 340\n" + + " \"name\": \"" + ProtocolConstant.PROTOCOL_NAME + "\",\n" + + " \"protocol\": " + ProtocolConstant.PROTOCOL_NUMBER + "\n" + " },\n" + " \"players\": {\n" + - " \"max\": 0,\n" + - " \"online\": 0,\n" + + " \"max\": " + config.players().maxOnlile() + ",\n" + + " \"online\": " + config.players().onlile() + ",\n" + " \"sample\": []\n" + " },\n" + " \"description\": {\n" + - " \"text\": \"Hello world\"\n" + + " \"text\": \"" + config.motd() + "\"\n" + " }\n" + "}"); @@ -58,6 +78,6 @@ public class Main { channel.getCtx().writeAndFlush(disconnectPacket).channel().disconnect(); }); - server.bind("127.0.0.1", 25565); + server.bind(config.server().host(), config.server().port()); } } diff --git a/server/src/main/java/mc/server/config/Config.java b/server/src/main/java/mc/server/config/Config.java new file mode 100644 index 0000000..f8f5f14 --- /dev/null +++ b/server/src/main/java/mc/server/config/Config.java @@ -0,0 +1,35 @@ +package mc.server.config; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +import java.nio.file.Path; + +@Getter +@Setter +@ToString +public class Config { + + private final Server server = new Server(); + private final Players players = new Players(); + + private String motd; + private Path iconPath; + + @Getter + @Setter + @ToString + public static class Server { + private String host; + private int port; + } + + @Getter + @Setter + @ToString + public static class Players { + private int maxOnlile; + private int onlile; + } +} diff --git a/server/src/main/java/mc/server/config/lombok.config b/server/src/main/java/mc/server/config/lombok.config new file mode 100644 index 0000000..f4387a7 --- /dev/null +++ b/server/src/main/java/mc/server/config/lombok.config @@ -0,0 +1 @@ +lombok.accessors.fluent=true \ No newline at end of file diff --git a/server/src/main/java/mc/server/di/ConfigModule.java b/server/src/main/java/mc/server/di/ConfigModule.java new file mode 100644 index 0000000..510b077 --- /dev/null +++ b/server/src/main/java/mc/server/di/ConfigModule.java @@ -0,0 +1,66 @@ +package mc.server.di; + +import dagger.Module; +import dagger.Provides; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import mc.server.config.Config; +import org.yaml.snakeyaml.Yaml; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Map; + +@Slf4j +@Module +@RequiredArgsConstructor +public class ConfigModule { + + private final Path configPath; + + @Provides + Config provideConfig() { + Config config = new Config(); + Map map = new Yaml().load(readConfigAsString()); + + config.server().host(fromYamlPath("server/host", map, "127.0.0.1")); + config.server().port(fromYamlPath("server/port", map, 25565)); + config.motd(fromYamlPath("motd", map, "")); + config.players().maxOnlile(fromYamlPath("players/max-online", map, 0)); + config.players().onlile(fromYamlPath("players/online", map, 0)); + + if (Boolean.TRUE.equals(fromYamlPath("icon/enable", map, false))) { + config.iconPath(Paths.get(fromYamlPath("icon/path", map, "favicon.png"))); + } + + map.clear(); + return config; + } + + private String readConfigAsString() { + try { + return Files.readString(configPath); + } catch (IOException e) { + log.error("Can't load config from '{}'", configPath.toAbsolutePath(), e); + return ""; + } + } + + @SuppressWarnings("unchecked") + private static T fromYamlPath(String mapPath, Map map, T defaultValue) { + String[] keys = mapPath.split("/", 2); + + if (map.containsKey(keys[0])) { + Object object = map.get(keys[0]); + if (keys.length > 1) { + return fromYamlPath(keys[1], (Map) object, defaultValue); + } else { + return (T) object; + } + } else { + return defaultValue; + } + } +} diff --git a/server/src/main/java/mc/server/di/ServerComponent.java b/server/src/main/java/mc/server/di/ServerComponent.java new file mode 100644 index 0000000..4147205 --- /dev/null +++ b/server/src/main/java/mc/server/di/ServerComponent.java @@ -0,0 +1,10 @@ +package mc.server.di; + +import dagger.Component; +import mc.server.config.Config; + +@Component(modules = ConfigModule.class) +public interface ServerComponent { + + Config getConfig(); +} diff --git a/server/src/main/resources/config.yml b/server/src/main/resources/config.yml new file mode 100644 index 0000000..af6b6aa --- /dev/null +++ b/server/src/main/resources/config.yml @@ -0,0 +1,13 @@ +server: + host: 127.0.0.1 + port: 25565 + +motd: 'mc-project::ZERO' + +players: + max-online: 0 + online: 0 + +icon: + enable: false + path: favicon.png \ No newline at end of file From f4f796c3a424ef3e8a41203524702af1984ad9ca Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Wed, 28 Apr 2021 18:34:19 +0300 Subject: [PATCH 13/34] =?UTF-8?q?=D1=80=D0=B0=D0=B7=D0=B4=D0=B5=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BD=D0=B0=20=D1=81=D0=B5=D1=80?= =?UTF-8?q?=D0=B2=D0=B5=D1=80=D0=BD=D1=8B=D0=B5=20=D0=B8=20=D0=BA=D0=BB?= =?UTF-8?q?=D0=B8=D0=B5=D0=BD=D1=82=D1=81=D0=BA=D0=B8=D0=B5=20=D0=BF=D0=B0?= =?UTF-8?q?=D0=BA=D0=B5=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- protocol/src/main/java/mc/protocol/State.java | 59 ++++++++----------- .../java/mc/protocol/di/ProtocolModule.java | 2 +- .../mc/protocol/io/codec/ProtocolDecoder.java | 7 +-- .../mc/protocol/io/codec/ProtocolEncoder.java | 9 ++- .../mc/protocol/packets/ClientSidePacket.java | 11 ++++ .../java/mc/protocol/packets/EmptyPacket.java | 2 +- .../main/java/mc/protocol/packets/Packet.java | 5 -- .../mc/protocol/packets/PacketDirection.java | 6 -- .../java/mc/protocol/packets/PingPacket.java | 2 +- .../mc/protocol/packets/ServerSidePacket.java | 11 ++++ .../mc/protocol/packets/UnknownPacket.java | 7 +-- .../packets/client/HandshakePacket.java | 11 +--- .../packets/client/LoginStartPacket.java | 8 +-- ...st.java => StatusServerRequestPacket.java} | 2 +- .../packets/server/DisconnectPacket.java | 9 +-- ...e.java => StatusServerResponsePacket.java} | 9 +-- server/src/main/java/mc/server/Main.java | 8 +-- 17 files changed, 72 insertions(+), 96 deletions(-) create mode 100644 protocol/src/main/java/mc/protocol/packets/ClientSidePacket.java delete mode 100644 protocol/src/main/java/mc/protocol/packets/PacketDirection.java create mode 100644 protocol/src/main/java/mc/protocol/packets/ServerSidePacket.java rename protocol/src/main/java/mc/protocol/packets/client/{StatusServerRequest.java => StatusServerRequestPacket.java} (86%) rename protocol/src/main/java/mc/protocol/packets/server/{StatusServerResponse.java => StatusServerResponsePacket.java} (88%) diff --git a/protocol/src/main/java/mc/protocol/State.java b/protocol/src/main/java/mc/protocol/State.java index 01c2971..0190377 100644 --- a/protocol/src/main/java/mc/protocol/State.java +++ b/protocol/src/main/java/mc/protocol/State.java @@ -1,44 +1,45 @@ package mc.protocol; -import com.google.common.collect.BiMap; -import com.google.common.collect.ImmutableBiMap; import lombok.Getter; import lombok.RequiredArgsConstructor; +import mc.protocol.packets.ClientSidePacket; import mc.protocol.packets.Packet; -import mc.protocol.packets.PacketDirection; import mc.protocol.packets.PingPacket; +import mc.protocol.packets.ServerSidePacket; import mc.protocol.packets.client.HandshakePacket; import mc.protocol.packets.client.LoginStartPacket; -import mc.protocol.packets.client.StatusServerRequest; +import mc.protocol.packets.client.StatusServerRequestPacket; import mc.protocol.packets.server.DisconnectPacket; -import mc.protocol.packets.server.StatusServerResponse; +import mc.protocol.packets.server.StatusServerResponsePacket; import javax.annotation.Nullable; +import java.util.Collections; +import java.util.Map; @RequiredArgsConstructor public enum State { HANDSHAKING(-1, - // server bound - ImmutableBiMap.of(0x00, HandshakePacket.class) + // client side + Map.of(0x00, HandshakePacket.class) ), STATUS(1, - // server bound - ImmutableBiMap.of( - 0x00, StatusServerRequest.class, + // client side + Map.of( + 0x00, StatusServerRequestPacket.class, 0x01, PingPacket.class ), - // client bound - ImmutableBiMap.of( - 0x00, StatusServerResponse.class, - 0x01, PingPacket.class + // server side + Map.of( + StatusServerResponsePacket.class, 0x00, + PingPacket.class, 0x01 ) ), LOGIN(2, // server bound - ImmutableBiMap.of(0x00, LoginStartPacket.class), + Map.of(0x00, LoginStartPacket.class), // client bound - ImmutableBiMap.of(0x00, DisconnectPacket.class) + Map.of(DisconnectPacket.class, 0x00) ); @Nullable @@ -56,30 +57,22 @@ public enum State { private final int id; @Getter - private final BiMap> serverBoundPackets; - private final BiMap> clientBoundPackets; + private final Map> clientSidePackets; + private final Map, Integer> serverSidePackets; - State(int id, BiMap> serverBoundPackets) { + State(int id, Map> clientSidePackets) { this.id = id; - this.serverBoundPackets = serverBoundPackets; - this.clientBoundPackets = ImmutableBiMap.of(); + this.clientSidePackets = clientSidePackets; + this.serverSidePackets = Collections.emptyMap(); } @Nullable - public Class getPacketById(PacketDirection direction, int id) { - if (PacketDirection.CLIENT_BOUND == direction) { - return clientBoundPackets == null ? null : clientBoundPackets.get(id); - } else { - return serverBoundPackets == null ? null : serverBoundPackets.get(id); - } + public Class getClientSidePacketById(int id) { + return clientSidePackets == null ? null : clientSidePackets.get(id); } @Nullable - public Integer getIdByPacket(PacketDirection direction, Class clazz) { - if (PacketDirection.CLIENT_BOUND == direction) { - return clientBoundPackets == null ? null : clientBoundPackets.inverse().get(clazz); - } else { - return serverBoundPackets == null ? null : serverBoundPackets.inverse().get(clazz); - } + public Integer getServerSidePacketId(Class clazz) { + return serverSidePackets == null ? null : serverSidePackets.get(clazz); } } diff --git a/protocol/src/main/java/mc/protocol/di/ProtocolModule.java b/protocol/src/main/java/mc/protocol/di/ProtocolModule.java index 3ee3ba3..479e6c9 100644 --- a/protocol/src/main/java/mc/protocol/di/ProtocolModule.java +++ b/protocol/src/main/java/mc/protocol/di/ProtocolModule.java @@ -84,7 +84,7 @@ public class ProtocolModule { ImmutableMap.Builder, Sinks.Many> builder = ImmutableMap.builder(); Stream.of(State.values()) - .flatMap(state -> state.getServerBoundPackets().values().stream()) + .flatMap(state -> state.getClientSidePackets().values().stream()) .forEach(packetClass -> builder.put(packetClass, Sinks.many().multicast().directBestEffort())); return builder.build(); diff --git a/protocol/src/main/java/mc/protocol/io/codec/ProtocolDecoder.java b/protocol/src/main/java/mc/protocol/io/codec/ProtocolDecoder.java index a59f5a0..58d22d7 100644 --- a/protocol/src/main/java/mc/protocol/io/codec/ProtocolDecoder.java +++ b/protocol/src/main/java/mc/protocol/io/codec/ProtocolDecoder.java @@ -8,8 +8,7 @@ import lombok.extern.slf4j.Slf4j; import mc.protocol.NetworkAttributes; import mc.protocol.State; import mc.protocol.io.NetByteBuf; -import mc.protocol.packets.Packet; -import mc.protocol.packets.PacketDirection; +import mc.protocol.packets.ClientSidePacket; import mc.protocol.packets.UnknownPacket; import java.util.List; @@ -39,7 +38,7 @@ public class ProtocolDecoder extends ByteToMessageDecoder { NetByteBuf netByteBuf = new NetByteBuf(in); int packetId = netByteBuf.readVarInt(); - Class packetClass = state.getPacketById(PacketDirection.SERVER_BOUND, packetId); + Class packetClass = state.getClientSidePacketById(packetId); if (packetClass == null) { log.warn("Unkown packet: State {} ; Id {}", state, packetId); @@ -51,7 +50,7 @@ public class ProtocolDecoder extends ByteToMessageDecoder { netByteBuf.skipBytes(netByteBuf.readableBytes()); } } else { - Packet packet = packetClass.getDeclaredConstructor().newInstance(); + ClientSidePacket packet = packetClass.getDeclaredConstructor().newInstance(); packet.readSelf(netByteBuf); out.add(packet); } diff --git a/protocol/src/main/java/mc/protocol/io/codec/ProtocolEncoder.java b/protocol/src/main/java/mc/protocol/io/codec/ProtocolEncoder.java index d26f26c..418d3ff 100644 --- a/protocol/src/main/java/mc/protocol/io/codec/ProtocolEncoder.java +++ b/protocol/src/main/java/mc/protocol/io/codec/ProtocolEncoder.java @@ -7,17 +7,16 @@ import io.netty.handler.codec.MessageToByteEncoder; import mc.protocol.NetworkAttributes; import mc.protocol.State; import mc.protocol.io.NetByteBuf; -import mc.protocol.packets.Packet; -import mc.protocol.packets.PacketDirection; +import mc.protocol.packets.ServerSidePacket; import java.util.Objects; -public class ProtocolEncoder extends MessageToByteEncoder { +public class ProtocolEncoder extends MessageToByteEncoder { @Override - protected void encode(ChannelHandlerContext ctx, Packet packet, ByteBuf out) { + protected void encode(ChannelHandlerContext ctx, ServerSidePacket packet, ByteBuf out) { State state = ctx.channel().attr(NetworkAttributes.STATE).get(); - int packetId = Objects.requireNonNull(state.getIdByPacket(PacketDirection.CLIENT_BOUND, packet.getClass())); + int packetId = Objects.requireNonNull(state.getServerSidePacketId(packet.getClass())); NetByteBuf buffer = new NetByteBuf(Unpooled.buffer()); buffer.writeVarInt(packetId); diff --git a/protocol/src/main/java/mc/protocol/packets/ClientSidePacket.java b/protocol/src/main/java/mc/protocol/packets/ClientSidePacket.java new file mode 100644 index 0000000..6629750 --- /dev/null +++ b/protocol/src/main/java/mc/protocol/packets/ClientSidePacket.java @@ -0,0 +1,11 @@ +package mc.protocol.packets; + +import mc.protocol.io.NetByteBuf; + +/** + * Пакеты отправляемые клиентом. + */ +public interface ClientSidePacket extends Packet { + + void readSelf(NetByteBuf netByteBuf); +} diff --git a/protocol/src/main/java/mc/protocol/packets/EmptyPacket.java b/protocol/src/main/java/mc/protocol/packets/EmptyPacket.java index b6dd02f..60c800f 100644 --- a/protocol/src/main/java/mc/protocol/packets/EmptyPacket.java +++ b/protocol/src/main/java/mc/protocol/packets/EmptyPacket.java @@ -2,7 +2,7 @@ package mc.protocol.packets; import mc.protocol.io.NetByteBuf; -public abstract class EmptyPacket implements Packet { +public abstract class EmptyPacket implements ClientSidePacket, ServerSidePacket { @Override public void readSelf(NetByteBuf netByteBuf) { diff --git a/protocol/src/main/java/mc/protocol/packets/Packet.java b/protocol/src/main/java/mc/protocol/packets/Packet.java index 95e1385..02ce207 100644 --- a/protocol/src/main/java/mc/protocol/packets/Packet.java +++ b/protocol/src/main/java/mc/protocol/packets/Packet.java @@ -1,7 +1,5 @@ package mc.protocol.packets; -import mc.protocol.io.NetByteBuf; - /** * Пакет. * @@ -18,7 +16,4 @@ import mc.protocol.io.NetByteBuf; */ public interface Packet { - void readSelf(NetByteBuf netByteBuf); - - void writeSelf(NetByteBuf netByteBuf); } diff --git a/protocol/src/main/java/mc/protocol/packets/PacketDirection.java b/protocol/src/main/java/mc/protocol/packets/PacketDirection.java deleted file mode 100644 index 2760689..0000000 --- a/protocol/src/main/java/mc/protocol/packets/PacketDirection.java +++ /dev/null @@ -1,6 +0,0 @@ -package mc.protocol.packets; - -public enum PacketDirection { - - SERVER_BOUND, CLIENT_BOUND -} diff --git a/protocol/src/main/java/mc/protocol/packets/PingPacket.java b/protocol/src/main/java/mc/protocol/packets/PingPacket.java index 81e0b88..f40b121 100644 --- a/protocol/src/main/java/mc/protocol/packets/PingPacket.java +++ b/protocol/src/main/java/mc/protocol/packets/PingPacket.java @@ -25,7 +25,7 @@ import mc.protocol.io.NetByteBuf; * @see Keep Alive */ @Data -public class PingPacket implements Packet { +public class PingPacket implements ClientSidePacket, ServerSidePacket { private Long payload; diff --git a/protocol/src/main/java/mc/protocol/packets/ServerSidePacket.java b/protocol/src/main/java/mc/protocol/packets/ServerSidePacket.java new file mode 100644 index 0000000..086deb6 --- /dev/null +++ b/protocol/src/main/java/mc/protocol/packets/ServerSidePacket.java @@ -0,0 +1,11 @@ +package mc.protocol.packets; + +import mc.protocol.io.NetByteBuf; + +/** + * Пакеты отправляемые сервером. + */ +public interface ServerSidePacket extends Packet { + + void writeSelf(NetByteBuf netByteBuf); +} diff --git a/protocol/src/main/java/mc/protocol/packets/UnknownPacket.java b/protocol/src/main/java/mc/protocol/packets/UnknownPacket.java index 04b4873..aef7b74 100644 --- a/protocol/src/main/java/mc/protocol/packets/UnknownPacket.java +++ b/protocol/src/main/java/mc/protocol/packets/UnknownPacket.java @@ -7,7 +7,7 @@ import mc.protocol.io.NetByteBuf; @Data @ToString(exclude = "rawData") -public class UnknownPacket implements Packet { +public class UnknownPacket implements ClientSidePacket { private final State state; private final int id; @@ -19,9 +19,4 @@ public class UnknownPacket implements Packet { rawData = new byte[dataSize]; netByteBuf.readBytes(rawData); } - - @Override - public void writeSelf(NetByteBuf netByteBuf) { - netByteBuf.writeBytes(rawData); - } } diff --git a/protocol/src/main/java/mc/protocol/packets/client/HandshakePacket.java b/protocol/src/main/java/mc/protocol/packets/client/HandshakePacket.java index eb786bc..ccb86b5 100644 --- a/protocol/src/main/java/mc/protocol/packets/client/HandshakePacket.java +++ b/protocol/src/main/java/mc/protocol/packets/client/HandshakePacket.java @@ -6,7 +6,7 @@ import lombok.NoArgsConstructor; import lombok.ToString; import mc.protocol.State; import mc.protocol.io.NetByteBuf; -import mc.protocol.packets.Packet; +import mc.protocol.packets.ClientSidePacket; /** * Handshake packet. @@ -32,7 +32,7 @@ import mc.protocol.packets.Packet; @Getter @EqualsAndHashCode @ToString -public class HandshakePacket implements Packet { +public class HandshakePacket implements ClientSidePacket { private int protocolVersion; private String host; @@ -47,11 +47,4 @@ public class HandshakePacket implements Packet { nextState = State.getById(netByteBuf.readVarInt()); } - @Override - public void writeSelf(NetByteBuf netByteBuf) { - netByteBuf.writeVarInt(protocolVersion); - netByteBuf.writeString(host); - netByteBuf.writeShort(port); - netByteBuf.writeVarInt(nextState.getId()); - } } diff --git a/protocol/src/main/java/mc/protocol/packets/client/LoginStartPacket.java b/protocol/src/main/java/mc/protocol/packets/client/LoginStartPacket.java index 75ebe04..77775b6 100644 --- a/protocol/src/main/java/mc/protocol/packets/client/LoginStartPacket.java +++ b/protocol/src/main/java/mc/protocol/packets/client/LoginStartPacket.java @@ -5,7 +5,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.ToString; import mc.protocol.io.NetByteBuf; -import mc.protocol.packets.Packet; +import mc.protocol.packets.ClientSidePacket; /** * Login start packet. @@ -25,7 +25,7 @@ import mc.protocol.packets.Packet; @Getter @EqualsAndHashCode @ToString -public class LoginStartPacket implements Packet { +public class LoginStartPacket implements ClientSidePacket { private String name; @@ -34,8 +34,4 @@ public class LoginStartPacket implements Packet { this.name = netByteBuf.readString(); } - @Override - public void writeSelf(NetByteBuf netByteBuf) { - netByteBuf.writeString(name); - } } diff --git a/protocol/src/main/java/mc/protocol/packets/client/StatusServerRequest.java b/protocol/src/main/java/mc/protocol/packets/client/StatusServerRequestPacket.java similarity index 86% rename from protocol/src/main/java/mc/protocol/packets/client/StatusServerRequest.java rename to protocol/src/main/java/mc/protocol/packets/client/StatusServerRequestPacket.java index 9cd1e61..5f4e84c 100644 --- a/protocol/src/main/java/mc/protocol/packets/client/StatusServerRequest.java +++ b/protocol/src/main/java/mc/protocol/packets/client/StatusServerRequestPacket.java @@ -13,6 +13,6 @@ import mc.protocol.packets.EmptyPacket; @NoArgsConstructor @EqualsAndHashCode(callSuper = false) @ToString -public class StatusServerRequest extends EmptyPacket { +public class StatusServerRequestPacket extends EmptyPacket { } diff --git a/protocol/src/main/java/mc/protocol/packets/server/DisconnectPacket.java b/protocol/src/main/java/mc/protocol/packets/server/DisconnectPacket.java index 2cfb3e2..dca7fef 100644 --- a/protocol/src/main/java/mc/protocol/packets/server/DisconnectPacket.java +++ b/protocol/src/main/java/mc/protocol/packets/server/DisconnectPacket.java @@ -3,7 +3,7 @@ package mc.protocol.packets.server; import lombok.Data; import mc.protocol.State; import mc.protocol.io.NetByteBuf; -import mc.protocol.packets.Packet; +import mc.protocol.packets.ServerSidePacket; /** * Diconnect packet. @@ -21,7 +21,7 @@ import mc.protocol.packets.Packet; * @see State */ @Data -public class DisconnectPacket implements Packet { +public class DisconnectPacket implements ServerSidePacket { /** * Причина отключения. @@ -35,11 +35,6 @@ public class DisconnectPacket implements Packet { */ private String reason; - @Override - public void readSelf(NetByteBuf netByteBuf) { - this.reason = netByteBuf.readString(); - } - @Override public void writeSelf(NetByteBuf netByteBuf) { netByteBuf.writeString(reason); diff --git a/protocol/src/main/java/mc/protocol/packets/server/StatusServerResponse.java b/protocol/src/main/java/mc/protocol/packets/server/StatusServerResponsePacket.java similarity index 88% rename from protocol/src/main/java/mc/protocol/packets/server/StatusServerResponse.java rename to protocol/src/main/java/mc/protocol/packets/server/StatusServerResponsePacket.java index 8cf99f4..fd6b4ef 100644 --- a/protocol/src/main/java/mc/protocol/packets/server/StatusServerResponse.java +++ b/protocol/src/main/java/mc/protocol/packets/server/StatusServerResponsePacket.java @@ -2,7 +2,7 @@ package mc.protocol.packets.server; import lombok.Data; import mc.protocol.io.NetByteBuf; -import mc.protocol.packets.Packet; +import mc.protocol.packets.ServerSidePacket; /** * Status server packet, response. @@ -19,7 +19,7 @@ import mc.protocol.packets.Packet; *

    */ @Data -public class StatusServerResponse implements Packet { +public class StatusServerResponsePacket implements ServerSidePacket { /** * Информация о серере в формате JSON @@ -50,11 +50,6 @@ public class StatusServerResponse implements Packet { */ private String info; - @Override - public void readSelf(NetByteBuf netByteBuf) { - info = netByteBuf.readString(); - } - @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 7736a56..156aceb 100644 --- a/server/src/main/java/mc/server/Main.java +++ b/server/src/main/java/mc/server/Main.java @@ -6,9 +6,9 @@ import mc.protocol.ProtocolConstant; import mc.protocol.packets.PingPacket; import mc.protocol.packets.client.HandshakePacket; import mc.protocol.packets.client.LoginStartPacket; -import mc.protocol.packets.client.StatusServerRequest; +import mc.protocol.packets.client.StatusServerRequestPacket; import mc.protocol.packets.server.DisconnectPacket; -import mc.protocol.packets.server.StatusServerResponse; +import mc.protocol.packets.server.StatusServerResponsePacket; import mc.server.config.Config; import mc.server.di.ConfigModule; import mc.server.di.DaggerServerComponent; @@ -45,10 +45,10 @@ public class Main { .doOnNext(channel -> log.info("{}", channel.getPacket())) .subscribe(channel -> channel.getCtx().writeAndFlush(channel.getPacket()).channel().disconnect()); - server.packetFlux(StatusServerRequest.class) + server.packetFlux(StatusServerRequestPacket.class) .doOnNext(channel -> log.info("{}", channel.getPacket())) .subscribe(channel -> { - StatusServerResponse response = new StatusServerResponse(); + StatusServerResponsePacket response = new StatusServerResponsePacket(); response.setInfo("{\n" + " \"version\": {\n" + " \"name\": \"" + ProtocolConstant.PROTOCOL_NAME + "\",\n" + From 09a3d16b772fdd4ac8641651ea5749a62779e8f2 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Wed, 28 Apr 2021 18:47:31 +0300 Subject: [PATCH 14/34] =?UTF-8?q?JSON=20=D0=B2=D0=BC=D0=B5=D1=81=D1=82?= =?UTF-8?q?=D0=BE=20String?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs.gradle | 3 +- protocol/build.gradle | 1 + protocol/src/main/java/mc/protocol/State.java | 4 +- .../java/mc/protocol/model/ServerInfo.java | 47 ++++++++++ .../main/java/mc/protocol/model/lombok.config | 1 + .../packets/server/DisconnectPacket.java | 23 ++--- .../packets/server/StatusServerResponse.java | 92 +++++++++++++++++++ .../server/StatusServerResponsePacket.java | 57 ------------ server/src/main/java/mc/server/Main.java | 33 +++---- 9 files changed, 171 insertions(+), 90 deletions(-) create mode 100644 protocol/src/main/java/mc/protocol/model/ServerInfo.java create mode 100644 protocol/src/main/java/mc/protocol/model/lombok.config create mode 100644 protocol/src/main/java/mc/protocol/packets/server/StatusServerResponse.java delete mode 100644 protocol/src/main/java/mc/protocol/packets/server/StatusServerResponsePacket.java 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 sample; + } + + @RequiredArgsConstructor + @Getter + @EqualsAndHashCode + @ToString + public static class SamplePlayer { + private final String id; + private final String name; + } +} diff --git a/protocol/src/main/java/mc/protocol/model/lombok.config b/protocol/src/main/java/mc/protocol/model/lombok.config new file mode 100644 index 0000000..f4387a7 --- /dev/null +++ b/protocol/src/main/java/mc/protocol/model/lombok.config @@ -0,0 +1 @@ +lombok.accessors.fluent=true \ No newline at end of file diff --git a/protocol/src/main/java/mc/protocol/packets/server/DisconnectPacket.java b/protocol/src/main/java/mc/protocol/packets/server/DisconnectPacket.java index dca7fef..c45891c 100644 --- a/protocol/src/main/java/mc/protocol/packets/server/DisconnectPacket.java +++ b/protocol/src/main/java/mc/protocol/packets/server/DisconnectPacket.java @@ -1,5 +1,6 @@ package mc.protocol.packets.server; +import com.eclipsesource.json.Json; import lombok.Data; import mc.protocol.State; import mc.protocol.io.NetByteBuf; @@ -12,9 +13,16 @@ import mc.protocol.packets.ServerSidePacket; * *

    Структура пакета

    *
    - * | FIELD  | TYPE | NOTES                            |
    - * |--------|------|----------------------------------|
    - * | Reason | Text | Причина отключения. Опционально. |
    + * | FIELD       | TYPE   | NOTES                            |
    + * |-------------|--------|----------------------------------|
    + * | JSON Reason | String | Причина отключения. Опционально. |
    + * 
    + * + *

    Пример JSON Reason

    + *
    + * {
    + *     "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
    + * 
    + * + *

    Пример JSON 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
    - * 

    - */ -@Data -public class StatusServerResponsePacket implements ServerSidePacket { - - /** - * Информация о серере в формате JSON - * - *

    Пример

    - *
    -	 * {
    -	 *     "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(); }); From ef984b28f0339b879222cf3bb005297f79e0c46b Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Wed, 28 Apr 2021 19:31:39 +0300 Subject: [PATCH 15/34] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=B7=D0=BD=D0=B0=D1=87=D0=BE=D0=BA=20=D1=81?= =?UTF-8?q?=D0=B5=D1=80=D0=B2=D0=B5=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs.gradle | 3 ++- .../packets/server/StatusServerResponse.java | 13 +++++++++--- server/build.gradle | 1 + server/src/main/java/mc/server/Main.java | 20 ++++++++++++++++++ server/src/main/resources/config.yml | 4 ++-- server/src/main/resources/favicon.png | Bin 0 -> 1675 bytes 6 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 server/src/main/resources/favicon.png diff --git a/libs.gradle b/libs.gradle index fc2589b..a4eb76f 100644 --- a/libs.gradle +++ b/libs.gradle @@ -16,7 +16,8 @@ ext { netty : 'io.netty:netty-all:4.1.22.Final', reactor : 'io.projectreactor:reactor-core:3.4.5', yaml : 'org.yaml:snakeyaml:1.28', - json : 'com.eclipsesource.minimal-json:minimal-json:0.9.5' + json : 'com.eclipsesource.minimal-json:minimal-json:0.9.5', + ioutils : 'commons-io:commons-io:2.6' ] libs.logger = [ diff --git a/protocol/src/main/java/mc/protocol/packets/server/StatusServerResponse.java b/protocol/src/main/java/mc/protocol/packets/server/StatusServerResponse.java index a238d20..32b26c7 100644 --- a/protocol/src/main/java/mc/protocol/packets/server/StatusServerResponse.java +++ b/protocol/src/main/java/mc/protocol/packets/server/StatusServerResponse.java @@ -48,6 +48,8 @@ import java.util.stream.Collector; * "favicon": "data:image/png;base64,<data>" * } * + * + *

    `$.favicon` должен быть формата PNG и размеры 64x64 px

    */ @Data public class StatusServerResponse implements ServerSidePacket { @@ -59,11 +61,16 @@ public class StatusServerResponse implements ServerSidePacket { @Override public void writeSelf(NetByteBuf netByteBuf) { - netByteBuf.writeString(Json.object() + JsonObject jsonObject = Json.object() .add("version", createVersionObj()) .add("players", createPlayersObj()) - .add("description", Json.object().add("text", info.description())) - .toString()); + .add("description", Json.object().add("text", info.description())); + + if (info.favicon() != null && !info.favicon().isEmpty()) { + jsonObject.add("favicon", info.favicon()); + } + + netByteBuf.writeString(jsonObject.toString()); } private JsonObject createVersionObj() { diff --git a/server/build.gradle b/server/build.gradle index 46c8b98..3854cf5 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -20,4 +20,5 @@ dependencies { implementation libs.reactor implementation libs.guava implementation libs.yaml + implementation libs.ioutils } diff --git a/server/src/main/java/mc/server/Main.java b/server/src/main/java/mc/server/Main.java index 0592fa1..c07e3c1 100644 --- a/server/src/main/java/mc/server/Main.java +++ b/server/src/main/java/mc/server/Main.java @@ -14,8 +14,13 @@ import mc.server.config.Config; import mc.server.di.ConfigModule; import mc.server.di.DaggerServerComponent; import mc.server.di.ServerComponent; +import org.apache.commons.io.IOUtils; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Base64; import java.util.Collections; @Slf4j @@ -58,6 +63,10 @@ public class Main { serverInfo.players().sample(Collections.emptyList()); serverInfo.description(config.motd()); + if (config.iconPath() != null) { + serverInfo.favicon(faviconToBase64(config.iconPath())); + } + StatusServerResponse response = new StatusServerResponse(); response.setInfo(serverInfo); @@ -75,4 +84,15 @@ public class Main { server.bind(config.server().host(), config.server().port()); } + + private static String faviconToBase64(Path iconPath) { + try { + return "data:image/png;base64," + + Base64.getEncoder().encodeToString( + IOUtils.toByteArray(Files.newInputStream(iconPath))); + } catch (IOException e) { + log.error("Can't read icon '{}'", iconPath.toAbsolutePath(), e); + return ""; + } + } } diff --git a/server/src/main/resources/config.yml b/server/src/main/resources/config.yml index af6b6aa..81df62d 100644 --- a/server/src/main/resources/config.yml +++ b/server/src/main/resources/config.yml @@ -9,5 +9,5 @@ players: online: 0 icon: - enable: false - path: favicon.png \ No newline at end of file + enable: true + path: src/main/resources/favicon.png \ No newline at end of file diff --git a/server/src/main/resources/favicon.png b/server/src/main/resources/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..d512fc5472e1d4b4573ba22b5e3e71587dbd4c9f GIT binary patch literal 1675 zcmV;626Xv}P)09zrl&^1WzcGf>6{pC7KKEp~p(7 zm8$R+BqT&YDrzr1B0?|WNG@&Q)Kgp3N=;EK4kUb5;xDLFQ7H?^5{eKeBm_fnt9);4 z_pn}j*IwH*J2STPlPs-g-^_dS+u4~n@6BpcQ&VUHf&eZ8_=ZvbTL2dT7&48Zlvb7b zWGbk@IDkU&w+{BsqbR#>t3NK?x*}u~Fo3erLlWB^vb8%Pv0Z5doP}xJElKUw!>yvO zvoabJC13)kF_$IS!i&pA-4h~>1O)0youCA81SSzd02{oOy^Me#(LSBG!vOFzZzbLl zunv>ycEuMkC(ICQ1s(zlywz-H;Z9ZWW}5U?3LZ=s>>jR;tiWJoJf zw-5CQ_z4`7NgE>svoEgDYHWu5;9OG&Pkzm3mLSdy4dU>?XFOGcl+vm`)fxfZ4n-@F z$z)&{%r1$mpxZKd-HS2Xdx)26p7GAxI{*OLY!-<`0>NNo_e9tA>y*+#dzl*nM@0Kttz#*yDvK`y0*UpH(X>rVM`=}ojZD5?-?68 zq@O*oAGpUcqZTpe|NcS26u0jodJ?uL0i9_bW z_df{fuSbHe>%US;Pg?}Y3}8Ai{Ui;auiD@8`Fxm}eSv&FkFG=6uy3{yxxs?>ov>&iFj2AYnKF#@HDT^oJ?v4^y(6l?EFLn)FF< z&!Nv9|DWEx>pGj;p?VT@gGGXL0-oNyTUFMI4zfaJc6d`jsUOhyZg1&2^>`W|b_B3J z}SADsBhDam=pu7tF21QY! zHr^DC17%nElnM=gpO5)x_XJfV6bgY-dKysd2jm)r!diuRyu3TL6L1uQXYSnKkAz*z zbE|8JMz;b0mX}xHM*(49<594blX76Clq0kgpu}Cvt*)Ub*hj@Jf9O$#f;+9AFM2|wG0Lza89UDD8SgLuKs%Ajn^iH5Dtfd8VR6U1mpl*0q`ZO zlA{L?a2qCqcs#}|8;ixRpvD8Obxh8}8aU1hGM>^mZY^%KS8vW6cX}DiT;b5AY>MG;n+=(kc=NAqF@e7;k1M1aoy@HHNc! z?+Ay(AcXt^&I8_FQe$6%<4{F2NFanD7K;S|oZ+qOH8;2cbC@xmD^^7UAq0ew>qT2U zIc}oK(PKsB=NbvhBq5nhf)H}9sQZ{mTe7mlmth)nu%3_z387HPdg6yPGkzxJV@=uV z@!K$o&;VR@6W}4Cv$NCc^woGgZnZ1*^IVlN!6B3*%|V!lvCacbBzy;81Wour^M8T$ Vqx`lI%8LL1002ovPDHLkV1m=#{XPHy literal 0 HcmV?d00001 From 30bb894b7ce2a426bdfe9fa93456255053d02187 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Wed, 28 Apr 2021 21:18:28 +0300 Subject: [PATCH 16/34] =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D1=8B=D0=B9=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BC=D0=BF=D0=BE=D0=BD=D0=B5=D0=BD=D1=82:=20Text?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/mc/protocol/model/ServerInfo.java | 2 + .../main/java/mc/protocol/model/lombok.config | 1 - .../java/mc/protocol/model/text/Text.java | 46 +++++++++++++++++++ .../java/mc/protocol/model/text/TextTest.java | 30 ++++++++++++ 4 files changed, 78 insertions(+), 1 deletion(-) delete mode 100644 protocol/src/main/java/mc/protocol/model/lombok.config create mode 100644 protocol/src/main/java/mc/protocol/model/text/Text.java create mode 100644 protocol/src/test/java/mc/protocol/model/text/TextTest.java diff --git a/protocol/src/main/java/mc/protocol/model/ServerInfo.java b/protocol/src/main/java/mc/protocol/model/ServerInfo.java index 002d52b..6924d14 100644 --- a/protocol/src/main/java/mc/protocol/model/ServerInfo.java +++ b/protocol/src/main/java/mc/protocol/model/ServerInfo.java @@ -5,9 +5,11 @@ import lombok.Setter; import lombok.ToString; import lombok.RequiredArgsConstructor; import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; import java.util.List; +@Accessors(fluent = true) @Getter @Setter @ToString diff --git a/protocol/src/main/java/mc/protocol/model/lombok.config b/protocol/src/main/java/mc/protocol/model/lombok.config deleted file mode 100644 index f4387a7..0000000 --- a/protocol/src/main/java/mc/protocol/model/lombok.config +++ /dev/null @@ -1 +0,0 @@ -lombok.accessors.fluent=true \ No newline at end of file diff --git a/protocol/src/main/java/mc/protocol/model/text/Text.java b/protocol/src/main/java/mc/protocol/model/text/Text.java new file mode 100644 index 0000000..94607a2 --- /dev/null +++ b/protocol/src/main/java/mc/protocol/model/text/Text.java @@ -0,0 +1,46 @@ +package mc.protocol.model.text; + +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@EqualsAndHashCode +@ToString +public class Text { + + public static final Text EMPTY = of(""); + + private String content; + + Text(String content) { + this.content = content; + } + + public static Text of(String content) { + return new Text(content); + } + + public static Text.Builder builder() { + return new Text.Builder(); + } + + public static class Builder { + private String content; + + public Builder append(String content) { + if (this.content == null) { + this.content = content; + } else { + this.content += content; + } + return this; + } + + public Text build() { + if (content == null) { + return EMPTY; + } else { + return new Text(content); + } + } + } +} diff --git a/protocol/src/test/java/mc/protocol/model/text/TextTest.java b/protocol/src/test/java/mc/protocol/model/text/TextTest.java new file mode 100644 index 0000000..ed3d423 --- /dev/null +++ b/protocol/src/test/java/mc/protocol/model/text/TextTest.java @@ -0,0 +1,30 @@ +package mc.protocol.model.text; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class TextTest { + + @Test + void emptyTest() { + Text actual = Text.builder().build(); + Text expected = Text.EMPTY; + + assertEquals(expected, actual); + } + + @Test + void contentTest() { + Text actual; + Text expected; + + actual = Text.builder().append("123").build(); + expected = new Text("123"); + assertEquals(expected, actual); + + actual = Text.builder().append("123").append("456").build(); + expected = new Text("123456"); + assertEquals(expected, actual); + } +} \ No newline at end of file From df4c1b7c71528b105a824798d4cb68ba99f1ee37 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Wed, 28 Apr 2021 21:27:38 +0300 Subject: [PATCH 17/34] =?UTF-8?q?Text:=20=D0=B4=D0=BE=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=20children?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/mc/protocol/model/text/Text.java | 26 ++++++++++++++++--- .../java/mc/protocol/model/text/TextTest.java | 24 +++++++++++++++-- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/protocol/src/main/java/mc/protocol/model/text/Text.java b/protocol/src/main/java/mc/protocol/model/text/Text.java index 94607a2..27041ec 100644 --- a/protocol/src/main/java/mc/protocol/model/text/Text.java +++ b/protocol/src/main/java/mc/protocol/model/text/Text.java @@ -1,5 +1,6 @@ package mc.protocol.model.text; +import com.google.common.collect.ImmutableList; import lombok.EqualsAndHashCode; import lombok.ToString; @@ -10,13 +11,15 @@ public class Text { public static final Text EMPTY = of(""); private String content; + private ImmutableList children; - Text(String content) { + Text(String content, ImmutableList children) { this.content = content; + this.children = children; } public static Text of(String content) { - return new Text(content); + return new Text(content, null); } public static Text.Builder builder() { @@ -25,6 +28,7 @@ public class Text { public static class Builder { private String content; + private ImmutableList.Builder childrenBuilder; public Builder append(String content) { if (this.content == null) { @@ -35,11 +39,25 @@ public class Text { return this; } + public Builder append(Text text) { + if (text == null || EMPTY.equals(text)) { + return this; + } + + if (this.childrenBuilder == null) { + this.childrenBuilder = ImmutableList.builder(); + } + + this.childrenBuilder.add(text); + return this; + } + public Text build() { - if (content == null) { + if (content == null && childrenBuilder == null) { return EMPTY; } else { - return new Text(content); + return new Text(content, + childrenBuilder == null ? null : childrenBuilder.build()); } } } diff --git a/protocol/src/test/java/mc/protocol/model/text/TextTest.java b/protocol/src/test/java/mc/protocol/model/text/TextTest.java index ed3d423..9513bef 100644 --- a/protocol/src/test/java/mc/protocol/model/text/TextTest.java +++ b/protocol/src/test/java/mc/protocol/model/text/TextTest.java @@ -1,5 +1,6 @@ package mc.protocol.model.text; +import com.google.common.collect.ImmutableList; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -20,11 +21,30 @@ class TextTest { Text expected; actual = Text.builder().append("123").build(); - expected = new Text("123"); + expected = new Text("123", null); assertEquals(expected, actual); actual = Text.builder().append("123").append("456").build(); - expected = new Text("123456"); + expected = new Text("123456", null); + assertEquals(expected, actual); + } + + @Test + void childrenTest() { + Text actual; + Text expected; + + actual = Text.builder().append("123").append((Text) null).build(); + expected = new Text("123", null); + assertEquals(expected, actual); + + actual = Text.builder().append("123").append(Text.EMPTY).build(); + expected = new Text("123", null); + assertEquals(expected, actual); + + Text child = Text.of("456"); + actual = Text.builder().append("123").append(child).build(); + expected = new Text("123", ImmutableList.of(child)); assertEquals(expected, actual); } } \ No newline at end of file From b255980c05f016107adf11ceee7bb5e875ac235f Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Wed, 28 Apr 2021 21:42:35 +0300 Subject: [PATCH 18/34] =?UTF-8?q?Text:=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D1=91=D0=BD=20builder?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/mc/protocol/model/text/Text.java | 45 ++++++++++++------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/protocol/src/main/java/mc/protocol/model/text/Text.java b/protocol/src/main/java/mc/protocol/model/text/Text.java index 27041ec..cb4545b 100644 --- a/protocol/src/main/java/mc/protocol/model/text/Text.java +++ b/protocol/src/main/java/mc/protocol/model/text/Text.java @@ -4,6 +4,8 @@ import com.google.common.collect.ImmutableList; import lombok.EqualsAndHashCode; import lombok.ToString; +import java.util.LinkedList; + @EqualsAndHashCode @ToString public class Text { @@ -27,15 +29,10 @@ public class Text { } public static class Builder { - private String content; - private ImmutableList.Builder childrenBuilder; + private final LinkedList chain = new LinkedList<>(); public Builder append(String content) { - if (this.content == null) { - this.content = content; - } else { - this.content += content; - } + chain.add(content); return this; } @@ -44,21 +41,37 @@ public class Text { return this; } - if (this.childrenBuilder == null) { - this.childrenBuilder = ImmutableList.builder(); - } - - this.childrenBuilder.add(text); + chain.add(text); return this; } public Text build() { - if (content == null && childrenBuilder == null) { + if (chain.isEmpty()) { return EMPTY; - } else { - return new Text(content, - childrenBuilder == null ? null : childrenBuilder.build()); } + + StringBuilder contentBuilder = null; + ImmutableList.Builder childrenBuilder = null; + + for (Object element : chain) { + if (element instanceof String) { + if (contentBuilder == null) { + contentBuilder = new StringBuilder((String) element); + } else { + contentBuilder.append((String) element); + } + } else if (element instanceof Text) { + if (childrenBuilder == null) { + childrenBuilder = ImmutableList.builder(); + } + + childrenBuilder.add((Text) element); + } + } + + return new Text( + contentBuilder == null ? null : contentBuilder.toString(), + childrenBuilder == null ? null : childrenBuilder.build()); } } } From c722da2b0562afd3027c371825c7b5d38a60f453 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Wed, 28 Apr 2021 22:12:21 +0300 Subject: [PATCH 19/34] =?UTF-8?q?Text:=20=D1=83=D0=BF=D1=80=D0=BE=D1=89?= =?UTF-8?q?=D0=B5=D0=BD=20builder?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/mc/protocol/model/text/Text.java | 56 +++++++++---------- .../mc/protocol/model/text/TextColor.java | 31 ++++++++++ .../mc/protocol/model/text/TextStyle.java | 38 +++++++++++++ .../java/mc/protocol/model/text/TextTest.java | 32 +++-------- 4 files changed, 103 insertions(+), 54 deletions(-) create mode 100644 protocol/src/main/java/mc/protocol/model/text/TextColor.java create mode 100644 protocol/src/main/java/mc/protocol/model/text/TextStyle.java diff --git a/protocol/src/main/java/mc/protocol/model/text/Text.java b/protocol/src/main/java/mc/protocol/model/text/Text.java index cb4545b..0b5a8c3 100644 --- a/protocol/src/main/java/mc/protocol/model/text/Text.java +++ b/protocol/src/main/java/mc/protocol/model/text/Text.java @@ -1,10 +1,11 @@ package mc.protocol.model.text; -import com.google.common.collect.ImmutableList; import lombok.EqualsAndHashCode; import lombok.ToString; +import java.util.ArrayList; import java.util.LinkedList; +import java.util.List; @EqualsAndHashCode @ToString @@ -12,16 +13,32 @@ public class Text { public static final Text EMPTY = of(""); + private TextColor color; + private TextStyle style; private String content; - private ImmutableList children; + private List children; - Text(String content, ImmutableList children) { + Text(TextColor color, TextStyle style, String content, List children) { + this.color = color; + this.style = style; this.content = content; this.children = children; } public static Text of(String content) { - return new Text(content, null); + return new Text(null, null, content, null); + } + + public static Text of(TextColor color, String content) { + return new Text(color, null, content, null); + } + + public static Text of(TextStyle style, String content) { + return new Text(null, style, content, null); + } + + public static Text of(TextColor color, TextStyle style, String content) { + return new Text(color, style, content, null); } public static Text.Builder builder() { @@ -29,12 +46,7 @@ public class Text { } public static class Builder { - private final LinkedList chain = new LinkedList<>(); - - public Builder append(String content) { - chain.add(content); - return this; - } + private final LinkedList chain = new LinkedList<>(); public Builder append(Text text) { if (text == null || EMPTY.equals(text)) { @@ -50,28 +62,14 @@ public class Text { return EMPTY; } - StringBuilder contentBuilder = null; - ImmutableList.Builder childrenBuilder = null; + Text rootText = chain.pollFirst(); - for (Object element : chain) { - if (element instanceof String) { - if (contentBuilder == null) { - contentBuilder = new StringBuilder((String) element); - } else { - contentBuilder.append((String) element); - } - } else if (element instanceof Text) { - if (childrenBuilder == null) { - childrenBuilder = ImmutableList.builder(); - } - - childrenBuilder.add((Text) element); - } + if (!chain.isEmpty()) { + rootText.children = new ArrayList<>(); + rootText.children.addAll(chain); } - return new Text( - contentBuilder == null ? null : contentBuilder.toString(), - childrenBuilder == null ? null : childrenBuilder.build()); + return rootText; } } } diff --git a/protocol/src/main/java/mc/protocol/model/text/TextColor.java b/protocol/src/main/java/mc/protocol/model/text/TextColor.java new file mode 100644 index 0000000..ba0b1c2 --- /dev/null +++ b/protocol/src/main/java/mc/protocol/model/text/TextColor.java @@ -0,0 +1,31 @@ +package mc.protocol.model.text; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Getter +public enum TextColor { + //@formatter:off + BLACK ("black", '0'), + DARK_BLUE ("dark_blue", '1'), + DARK_GREEN ("dark_green", '2'), + DARK_AQUA ("dark_aqua", '3'), + DARK_RED ("dark_red", '4'), + DARK_PUEPLE("dark_purple", '5'), + GOLD ("gold", '6'), + GRAY ("gray", '7'), + DARK_GRAY ("dark_gray", '8'), + BLUE ("blue", '9'), + GREEN ("green", 'a'), + AQUA ("aqua", 'b'), + RED ("red", 'c'), + PUEPLE ("light_purple",'d'), + YELLOW ("yellow", 'e'), + WHITE ("white", 'f'), + RESET ("reset", 'r'); + //@formatter:on + + private final String name; + private final char code; +} diff --git a/protocol/src/main/java/mc/protocol/model/text/TextStyle.java b/protocol/src/main/java/mc/protocol/model/text/TextStyle.java new file mode 100644 index 0000000..e4856e3 --- /dev/null +++ b/protocol/src/main/java/mc/protocol/model/text/TextStyle.java @@ -0,0 +1,38 @@ +package mc.protocol.model.text; + +import lombok.*; +import lombok.experimental.Accessors; + +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Builder(builderClassName = "Builder") +@Accessors(fluent = true) +@Getter +@Setter(AccessLevel.PACKAGE) +@EqualsAndHashCode +@ToString +@SuppressWarnings("java:S1845") +public class TextStyle { + + public static final TextStyle BOLD = new TextStyle(true, null, null, null, null); + public static final TextStyle ITALIC = new TextStyle(null, true, null, null, null); + public static final TextStyle UNDERLINE = new TextStyle(null, null, true, null, null); + public static final TextStyle STRIKETHOUGH = new TextStyle(null, null, null, true, null); + public static final TextStyle OBFUSCATED = new TextStyle(null, null, null, null, true); + + public static final TextStyle RESET = new TextStyle(false, false, false, false, false); + public static final TextStyle NONE = new TextStyle(null, null, null, null, null); + + private Boolean bold; + private Boolean italic; + private Boolean underline; + private Boolean strikethrough; + private Boolean obfuscated; + + void merge(TextStyle style) { + if (style.bold != null) this.bold = style.bold; + if (style.italic != null) this.italic = style.italic; + if (style.underline != null) this.underline = style.underline; + if (style.strikethrough != null) this.strikethrough = style.strikethrough; + if (style.obfuscated != null) this.obfuscated = style.obfuscated; + } +} diff --git a/protocol/src/test/java/mc/protocol/model/text/TextTest.java b/protocol/src/test/java/mc/protocol/model/text/TextTest.java index 9513bef..cbed53f 100644 --- a/protocol/src/test/java/mc/protocol/model/text/TextTest.java +++ b/protocol/src/test/java/mc/protocol/model/text/TextTest.java @@ -1,9 +1,10 @@ package mc.protocol.model.text; -import com.google.common.collect.ImmutableList; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; class TextTest { @@ -20,31 +21,12 @@ class TextTest { Text actual; Text expected; - actual = Text.builder().append("123").build(); - expected = new Text("123", null); + actual = Text.builder().append(Text.of("123")).build(); + expected = new Text(null, null, "123", null); assertEquals(expected, actual); - actual = Text.builder().append("123").append("456").build(); - expected = new Text("123456", null); - assertEquals(expected, actual); - } - - @Test - void childrenTest() { - Text actual; - Text expected; - - actual = Text.builder().append("123").append((Text) null).build(); - expected = new Text("123", null); - assertEquals(expected, actual); - - actual = Text.builder().append("123").append(Text.EMPTY).build(); - expected = new Text("123", null); - assertEquals(expected, actual); - - Text child = Text.of("456"); - actual = Text.builder().append("123").append(child).build(); - expected = new Text("123", ImmutableList.of(child)); + actual = Text.builder().append(Text.of("123")).append(Text.of("456")).build(); + expected = new Text(null, null, "123", List.of(Text.of("456"))); assertEquals(expected, actual); } } \ No newline at end of file From 54b9ccb7e5135dc2b28b02ec520273698b828c60 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Wed, 28 Apr 2021 22:29:47 +0300 Subject: [PATCH 20/34] =?UTF-8?q?=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20Text?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/mc/protocol/model/ServerInfo.java | 3 +- .../java/mc/protocol/model/text/Text.java | 4 ++ .../packets/server/DisconnectPacket.java | 7 +-- .../packets/server/StatusServerResponse.java | 42 +-------------- .../serializer/ServerInfoSerializer.java | 51 +++++++++++++++++++ .../protocol/serializer/TextSerializer.java | 41 +++++++++++++++ server/src/main/java/mc/server/Main.java | 5 +- 7 files changed, 107 insertions(+), 46 deletions(-) create mode 100644 protocol/src/main/java/mc/protocol/serializer/ServerInfoSerializer.java create mode 100644 protocol/src/main/java/mc/protocol/serializer/TextSerializer.java diff --git a/protocol/src/main/java/mc/protocol/model/ServerInfo.java b/protocol/src/main/java/mc/protocol/model/ServerInfo.java index 6924d14..e5a7af7 100644 --- a/protocol/src/main/java/mc/protocol/model/ServerInfo.java +++ b/protocol/src/main/java/mc/protocol/model/ServerInfo.java @@ -6,6 +6,7 @@ import lombok.ToString; import lombok.RequiredArgsConstructor; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; +import mc.protocol.model.text.Text; import java.util.List; @@ -18,7 +19,7 @@ public class ServerInfo { private final Version version = new Version(); private final Players players = new Players(); - private String description; + private Text description; private String favicon; @Getter diff --git a/protocol/src/main/java/mc/protocol/model/text/Text.java b/protocol/src/main/java/mc/protocol/model/text/Text.java index 0b5a8c3..11d1d50 100644 --- a/protocol/src/main/java/mc/protocol/model/text/Text.java +++ b/protocol/src/main/java/mc/protocol/model/text/Text.java @@ -1,12 +1,16 @@ package mc.protocol.model.text; import lombok.EqualsAndHashCode; +import lombok.Getter; import lombok.ToString; +import lombok.experimental.Accessors; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; +@Accessors(fluent = true) +@Getter @EqualsAndHashCode @ToString public class Text { diff --git a/protocol/src/main/java/mc/protocol/packets/server/DisconnectPacket.java b/protocol/src/main/java/mc/protocol/packets/server/DisconnectPacket.java index c45891c..7eae3aa 100644 --- a/protocol/src/main/java/mc/protocol/packets/server/DisconnectPacket.java +++ b/protocol/src/main/java/mc/protocol/packets/server/DisconnectPacket.java @@ -1,10 +1,11 @@ package mc.protocol.packets.server; -import com.eclipsesource.json.Json; import lombok.Data; import mc.protocol.State; import mc.protocol.io.NetByteBuf; +import mc.protocol.model.text.Text; import mc.protocol.packets.ServerSidePacket; +import mc.protocol.serializer.TextSerializer; /** * Diconnect packet. @@ -34,10 +35,10 @@ public class DisconnectPacket implements ServerSidePacket { /** * Причина отключения. */ - private String reason; + private Text reason; @Override public void writeSelf(NetByteBuf netByteBuf) { - netByteBuf.writeString(Json.object().add("text", reason).toString()); + netByteBuf.writeString(TextSerializer.toJsonObject(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 index 32b26c7..35973c1 100644 --- a/protocol/src/main/java/mc/protocol/packets/server/StatusServerResponse.java +++ b/protocol/src/main/java/mc/protocol/packets/server/StatusServerResponse.java @@ -1,15 +1,10 @@ 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; +import mc.protocol.serializer.ServerInfoSerializer; /** * Status server packet, response. @@ -61,39 +56,6 @@ public class StatusServerResponse implements ServerSidePacket { @Override public void writeSelf(NetByteBuf netByteBuf) { - JsonObject jsonObject = Json.object() - .add("version", createVersionObj()) - .add("players", createPlayersObj()) - .add("description", Json.object().add("text", info.description())); - - if (info.favicon() != null && !info.favicon().isEmpty()) { - jsonObject.add("favicon", info.favicon()); - } - - netByteBuf.writeString(jsonObject.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; + netByteBuf.writeString(ServerInfoSerializer.toJsonObject(info).toString()); } } diff --git a/protocol/src/main/java/mc/protocol/serializer/ServerInfoSerializer.java b/protocol/src/main/java/mc/protocol/serializer/ServerInfoSerializer.java new file mode 100644 index 0000000..3b98b3d --- /dev/null +++ b/protocol/src/main/java/mc/protocol/serializer/ServerInfoSerializer.java @@ -0,0 +1,51 @@ +package mc.protocol.serializer; + +import com.eclipsesource.json.Json; +import com.eclipsesource.json.JsonArray; +import com.eclipsesource.json.JsonObject; +import com.google.common.collect.Streams; +import lombok.experimental.UtilityClass; +import mc.protocol.model.ServerInfo; + +import java.util.stream.Collector; + +@UtilityClass +public class ServerInfoSerializer { + + public JsonObject toJsonObject(ServerInfo info) { + JsonObject jsonObject = Json.object() + .add("version", createVersionObj(info)) + .add("players", createPlayersObj(info)) + .add("description", TextSerializer.toJsonObject(info.description())); + + if (info.favicon() != null && !info.favicon().isEmpty()) { + jsonObject.add("favicon", info.favicon()); + } + + return jsonObject; + } + + private JsonObject createVersionObj(ServerInfo info) { + return Json.object() + .add("name", info.version().name()) + .add("protocol", info.version().protocol()); + } + + private JsonObject createPlayersObj(ServerInfo info) { + 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, ServerInfoSerializer::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/serializer/TextSerializer.java b/protocol/src/main/java/mc/protocol/serializer/TextSerializer.java new file mode 100644 index 0000000..69f2ff3 --- /dev/null +++ b/protocol/src/main/java/mc/protocol/serializer/TextSerializer.java @@ -0,0 +1,41 @@ +package mc.protocol.serializer; + +import com.eclipsesource.json.Json; +import com.eclipsesource.json.JsonArray; +import com.eclipsesource.json.JsonObject; +import lombok.experimental.UtilityClass; +import mc.protocol.model.text.Text; + +@UtilityClass +public class TextSerializer { + + public JsonObject toJsonObject(Text text) { + JsonObject jsonObject = Json.object(); + + if (text.content() != null) { + jsonObject.add("text", text.content()); + } + + if (text.color() != null) { + jsonObject.add("color", text.color().getName()); + } + + if (text.style() != null) { + //@formatter:off + if (text.style().bold() != null) jsonObject.add("bold", text.style().bold()); + if (text.style().italic() != null) jsonObject.add("italic", text.style().italic()); + if (text.style().underline() != null) jsonObject.add("underline", text.style().underline()); + if (text.style().strikethrough() != null) jsonObject.add("strikethrough", text.style().strikethrough()); + if (text.style().obfuscated() != null) jsonObject.add("obfuscated", text.style().obfuscated()); + //@formatter:on + } + + if (text.children() != null && !text.children().isEmpty()) { + JsonArray extra = Json.array(); + text.children().forEach(child -> extra.add(toJsonObject(child))); + jsonObject.add("extra", extra); + } + + return jsonObject; + } +} diff --git a/server/src/main/java/mc/server/Main.java b/server/src/main/java/mc/server/Main.java index c07e3c1..5b38960 100644 --- a/server/src/main/java/mc/server/Main.java +++ b/server/src/main/java/mc/server/Main.java @@ -4,6 +4,7 @@ import lombok.extern.slf4j.Slf4j; import mc.protocol.NettyServer; import mc.protocol.ProtocolConstant; import mc.protocol.model.ServerInfo; +import mc.protocol.model.text.Text; import mc.protocol.packets.PingPacket; import mc.protocol.packets.client.HandshakePacket; import mc.protocol.packets.client.LoginStartPacket; @@ -61,7 +62,7 @@ public class Main { serverInfo.players().max(config.players().maxOnlile()); serverInfo.players().online(config.players().onlile()); serverInfo.players().sample(Collections.emptyList()); - serverInfo.description(config.motd()); + serverInfo.description(Text.of(config.motd())); if (config.iconPath() != null) { serverInfo.favicon(faviconToBase64(config.iconPath())); @@ -77,7 +78,7 @@ public class Main { .doOnNext(channel -> log.info("{}", channel.getPacket())) .subscribe(channel -> { DisconnectPacket disconnectPacket = new DisconnectPacket(); - disconnectPacket.setReason("Server is not available."); + disconnectPacket.setReason(Text.of("Server is not available.")); channel.getCtx().writeAndFlush(disconnectPacket).channel().disconnect(); }); From 626ad9c206662c03c977d469af156214273b4292 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Wed, 28 Apr 2021 22:31:16 +0300 Subject: [PATCH 21/34] lombok.config -> @lombok.Accessors --- server/src/main/java/mc/server/config/Config.java | 2 ++ server/src/main/java/mc/server/config/lombok.config | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) delete mode 100644 server/src/main/java/mc/server/config/lombok.config diff --git a/server/src/main/java/mc/server/config/Config.java b/server/src/main/java/mc/server/config/Config.java index f8f5f14..310adf6 100644 --- a/server/src/main/java/mc/server/config/Config.java +++ b/server/src/main/java/mc/server/config/Config.java @@ -3,9 +3,11 @@ package mc.server.config; import lombok.Getter; import lombok.Setter; import lombok.ToString; +import lombok.experimental.Accessors; import java.nio.file.Path; +@Accessors(fluent = true) @Getter @Setter @ToString diff --git a/server/src/main/java/mc/server/config/lombok.config b/server/src/main/java/mc/server/config/lombok.config deleted file mode 100644 index f4387a7..0000000 --- a/server/src/main/java/mc/server/config/lombok.config +++ /dev/null @@ -1 +0,0 @@ -lombok.accessors.fluent=true \ No newline at end of file From e93a24d76510d1e4037c55e78da864dfc7299030 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Thu, 29 Apr 2021 15:40:17 +0300 Subject: [PATCH 22/34] use jOptSimple --- libs.gradle | 3 +- server/build.gradle | 1 + server/src/main/java/mc/server/Main.java | 49 ++++++++++++++++++++---- 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/libs.gradle b/libs.gradle index a4eb76f..6bac138 100644 --- a/libs.gradle +++ b/libs.gradle @@ -17,7 +17,8 @@ ext { reactor : 'io.projectreactor:reactor-core:3.4.5', yaml : 'org.yaml:snakeyaml:1.28', json : 'com.eclipsesource.minimal-json:minimal-json:0.9.5', - ioutils : 'commons-io:commons-io:2.6' + ioutils : 'commons-io:commons-io:2.6', + jopt : 'net.sf.jopt-simple:jopt-simple:6.0-alpha-3' ] libs.logger = [ diff --git a/server/build.gradle b/server/build.gradle index 3854cf5..91cb14c 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -21,4 +21,5 @@ dependencies { implementation libs.guava implementation libs.yaml implementation libs.ioutils + implementation libs.jopt } diff --git a/server/src/main/java/mc/server/Main.java b/server/src/main/java/mc/server/Main.java index 5b38960..a4bd7ab 100644 --- a/server/src/main/java/mc/server/Main.java +++ b/server/src/main/java/mc/server/Main.java @@ -1,5 +1,8 @@ package mc.server; +import joptsimple.OptionParser; +import joptsimple.OptionSet; +import joptsimple.util.PathConverter; import lombok.extern.slf4j.Slf4j; import mc.protocol.NettyServer; import mc.protocol.ProtocolConstant; @@ -23,19 +26,15 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Base64; import java.util.Collections; +import java.util.List; @Slf4j public class Main { - public static void main(String[] args) { + private void run(OptionSet optionSet) { log.info("mc-project launch"); - ConfigModule configModule; - if (args.length > 0) { - configModule = new ConfigModule(Paths.get(args[0])); - } else { - configModule = new ConfigModule(Paths.get("config.yml")); - } + ConfigModule configModule = new ConfigModule((Path) optionSet.valueOf("config")); ServerComponent serverComponent = DaggerServerComponent.builder() .configModule(configModule) @@ -86,6 +85,42 @@ public class Main { server.bind(config.server().host(), config.server().port()); } + @SuppressWarnings("java:S106") + public static void main(String[] args) { + OptionParser optionParser = createOptionParser(); + OptionSet optionSet = optionParser.parse(args); + + if (optionSet.has("help")) { + try { + optionParser.printHelpOn(System.out); + } catch (IOException e) { + System.err.printf("Can't print help page: %s%n", e.getMessage()); + e.printStackTrace(System.err); + } + return; + } + + if (log.isDebugEnabled()) { + optionSet.asMap().forEach((optionSpec, objects) -> { + if (optionSpec.isForHelp()) return; + log.debug("OptionSet | {} = {}", optionSpec.options(), objects); + }); + } + + new Main().run(optionSet); + } + + private static OptionParser createOptionParser() { + OptionParser optionParser = new OptionParser(); + optionParser.acceptsAll(List.of("h", "help"), "Help page").forHelp(); + optionParser.accepts("config", "Path to configuration file") + .withRequiredArg() + .withValuesConvertedBy(new PathConverter()) + .defaultsTo(Paths.get("config.yml")); + + return optionParser; + } + private static String faviconToBase64(Path iconPath) { try { return "data:image/png;base64," + From dc7b4a7ab0af9a37ea821f70c913e855e7e21f1c Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Thu, 29 Apr 2021 16:44:08 +0300 Subject: [PATCH 23/34] =?UTF-8?q?Text:=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=B4=D0=B8=D0=B7=D0=B0=D0=B9=D0=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/mc/protocol/model/text/Text.java | 142 +++++++++++++----- .../mc/protocol/model/text/TextStyle.java | 66 ++++++-- .../java/mc/protocol/model/text/TextTest.java | 12 +- 3 files changed, 158 insertions(+), 62 deletions(-) diff --git a/protocol/src/main/java/mc/protocol/model/text/Text.java b/protocol/src/main/java/mc/protocol/model/text/Text.java index 11d1d50..0472114 100644 --- a/protocol/src/main/java/mc/protocol/model/text/Text.java +++ b/protocol/src/main/java/mc/protocol/model/text/Text.java @@ -1,79 +1,139 @@ package mc.protocol.model.text; -import lombok.EqualsAndHashCode; -import lombok.Getter; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; import lombok.ToString; import lombok.experimental.Accessors; import java.util.ArrayList; -import java.util.LinkedList; import java.util.List; @Accessors(fluent = true) -@Getter -@EqualsAndHashCode -@ToString +@AllArgsConstructor +@Data public class Text { - public static final Text EMPTY = of(""); - private TextColor color; private TextStyle style; private String content; private List children; - Text(TextColor color, TextStyle style, String content, List children) { - this.color = color; - this.style = style; - this.content = content; - this.children = children; + public static Text of(String string) { + return new Text(null, null, string, null); } - public static Text of(String content) { - return new Text(null, null, content, null); + public static Text of(TextColor color, String string) { + return new Text(color, null, string, null); } - public static Text of(TextColor color, String content) { - return new Text(color, null, content, null); + public static Text of(TextStyle style, String string) { + return new Text(null, style, string, null); } - public static Text of(TextStyle style, String content) { - return new Text(null, style, content, null); + public static Text of(TextColor color, TextStyle style, String string) { + return new Text(color, style, string, null); } - public static Text of(TextColor color, TextStyle style, String content) { - return new Text(color, style, content, null); - } - - public static Text.Builder builder() { - return new Text.Builder(); + public static Builder builder() { + return new Builder(); } + @NoArgsConstructor + @ToString public static class Builder { - private final LinkedList chain = new LinkedList<>(); + + private StringBuilder contentBuilder; + private TextStyle.Builder styleBuilder; + private TextColor color; + private List children; + + public Builder append(String content) { + if (this.contentBuilder == null) { + this.contentBuilder = new StringBuilder(content); + } else { + this.contentBuilder.append(content); + } + return this; + } public Builder append(Text text) { - if (text == null || EMPTY.equals(text)) { - return this; + if (children == null) { + children = new ArrayList<>(); } - chain.add(text); + children.add(text); + return this; + } + + public Builder style(TextStyle style) { + //@formatter:off + if (style.bold() != null) bold(style.bold()); + if (style.italic() != null) italic(style.italic()); + if (style.underline() != null) underline(style.underline()); + if (style.strikethrough() != null) strikethrough(style.strikethrough()); + if (style.obfuscated() != null) obfuscated(style.obfuscated()); + //@formatter:on + + return this; + } + + public Builder color(TextColor color) { + this.color = color; + return this; + } + + public Builder bold(Boolean bold) { + if (this.styleBuilder == null) { + this.styleBuilder = TextStyle.builder(); + } + + this.styleBuilder.bold(bold); + return this; + } + + public Builder italic(Boolean italic) { + if (this.styleBuilder == null) { + this.styleBuilder = TextStyle.builder(); + } + + this.styleBuilder.italic(italic); + return this; + } + + public Builder underline(Boolean underline) { + if (this.styleBuilder == null) { + this.styleBuilder = TextStyle.builder(); + } + + this.styleBuilder.underline(underline); + return this; + } + + public Builder strikethrough(Boolean strikethrough) { + if (this.styleBuilder == null) { + this.styleBuilder = TextStyle.builder(); + } + + this.styleBuilder.strikethrough(strikethrough); + return this; + } + + public Builder obfuscated(Boolean obfuscated) { + if (this.styleBuilder == null) { + this.styleBuilder = TextStyle.builder(); + } + + this.styleBuilder.obfuscated(obfuscated); return this; } public Text build() { - if (chain.isEmpty()) { - return EMPTY; - } - - Text rootText = chain.pollFirst(); - - if (!chain.isEmpty()) { - rootText.children = new ArrayList<>(); - rootText.children.addAll(chain); - } - - return rootText; + return new Text( + color, + styleBuilder == null ? null : styleBuilder.build(), + contentBuilder == null ? null : contentBuilder.toString(), + children); } } } diff --git a/protocol/src/main/java/mc/protocol/model/text/TextStyle.java b/protocol/src/main/java/mc/protocol/model/text/TextStyle.java index e4856e3..06c6040 100644 --- a/protocol/src/main/java/mc/protocol/model/text/TextStyle.java +++ b/protocol/src/main/java/mc/protocol/model/text/TextStyle.java @@ -4,12 +4,8 @@ import lombok.*; import lombok.experimental.Accessors; @AllArgsConstructor(access = AccessLevel.PRIVATE) -@Builder(builderClassName = "Builder") @Accessors(fluent = true) -@Getter -@Setter(AccessLevel.PACKAGE) -@EqualsAndHashCode -@ToString +@Data @SuppressWarnings("java:S1845") public class TextStyle { @@ -28,11 +24,59 @@ public class TextStyle { private Boolean strikethrough; private Boolean obfuscated; - void merge(TextStyle style) { - if (style.bold != null) this.bold = style.bold; - if (style.italic != null) this.italic = style.italic; - if (style.underline != null) this.underline = style.underline; - if (style.strikethrough != null) this.strikethrough = style.strikethrough; - if (style.obfuscated != null) this.obfuscated = style.obfuscated; + public static Builder builder() { + return new TextStyle.Builder(); + } + + @NoArgsConstructor + @ToString + public static class Builder { + + private Boolean bold; + private Boolean italic; + private Boolean underline; + private Boolean strikethrough; + private Boolean obfuscated; + + public Builder bold(Boolean bold) { + this.bold = bold; + return this; + } + + public Builder italic(Boolean italic) { + this.italic = italic; + return this; + } + + public Builder underline(Boolean underline) { + this.underline = underline; + return this; + } + + public Builder strikethrough(Boolean strikethrough) { + this.strikethrough = strikethrough; + return this; + } + + public Builder obfuscated(Boolean obfuscated) { + this.obfuscated = obfuscated; + return this; + } + + public Builder merge(TextStyle style) { + //@formatter:off + if (style.bold != null) this.bold = style.bold; + if (style.italic != null) this.italic = style.italic; + if (style.underline != null) this.underline = style.underline; + if (style.strikethrough != null) this.strikethrough = style.strikethrough; + if (style.obfuscated != null) this.obfuscated = style.obfuscated; + //@formatter:on + + return this; + } + + public TextStyle build() { + return new TextStyle(bold, italic, underline, strikethrough, obfuscated); + } } } diff --git a/protocol/src/test/java/mc/protocol/model/text/TextTest.java b/protocol/src/test/java/mc/protocol/model/text/TextTest.java index cbed53f..601576c 100644 --- a/protocol/src/test/java/mc/protocol/model/text/TextTest.java +++ b/protocol/src/test/java/mc/protocol/model/text/TextTest.java @@ -8,24 +8,16 @@ import static org.junit.jupiter.api.Assertions.assertEquals; class TextTest { - @Test - void emptyTest() { - Text actual = Text.builder().build(); - Text expected = Text.EMPTY; - - assertEquals(expected, actual); - } - @Test void contentTest() { Text actual; Text expected; - actual = Text.builder().append(Text.of("123")).build(); + actual = Text.builder().append("123").build(); expected = new Text(null, null, "123", null); assertEquals(expected, actual); - actual = Text.builder().append(Text.of("123")).append(Text.of("456")).build(); + actual = Text.builder().append("123").append(Text.of("456")).build(); expected = new Text(null, null, "123", List.of(Text.of("456"))); assertEquals(expected, actual); } From ac0ebea708d89c84c4d5b91b06ffc2f45434bea8 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Thu, 29 Apr 2021 18:56:54 +0300 Subject: [PATCH 24/34] =?UTF-8?q?Text:=20=D0=BA=D0=BE=D0=BD=D0=B2=D0=B5?= =?UTF-8?q?=D1=80=D1=82=D0=B0=D1=86=D0=B8=D1=8F=20=D0=B8=D0=B7=20legacy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/mc/protocol/model/text/Text.java | 12 +++ .../mc/protocol/model/text/TextColor.java | 5 +- .../protocol/serializer/TextSerializer.java | 88 +++++++++++++++++++ .../serializer/TextSerializerTest.java | 40 +++++++++ 4 files changed, 142 insertions(+), 3 deletions(-) create mode 100644 protocol/src/test/java/mc/protocol/serializer/TextSerializerTest.java diff --git a/protocol/src/main/java/mc/protocol/model/text/Text.java b/protocol/src/main/java/mc/protocol/model/text/Text.java index 0472114..d7527e2 100644 --- a/protocol/src/main/java/mc/protocol/model/text/Text.java +++ b/protocol/src/main/java/mc/protocol/model/text/Text.java @@ -4,8 +4,10 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; +import lombok.Getter; import lombok.experimental.Accessors; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; @@ -43,11 +45,21 @@ public class Text { @ToString public static class Builder { + @Getter(onMethod = @__(@Nullable)) private StringBuilder contentBuilder; private TextStyle.Builder styleBuilder; private TextColor color; private List children; + public Builder append(char content) { + if (this.contentBuilder == null) { + this.contentBuilder = new StringBuilder(); + } + + this.contentBuilder.append(content); + return this; + } + public Builder append(String content) { if (this.contentBuilder == null) { this.contentBuilder = new StringBuilder(content); diff --git a/protocol/src/main/java/mc/protocol/model/text/TextColor.java b/protocol/src/main/java/mc/protocol/model/text/TextColor.java index ba0b1c2..8e914cc 100644 --- a/protocol/src/main/java/mc/protocol/model/text/TextColor.java +++ b/protocol/src/main/java/mc/protocol/model/text/TextColor.java @@ -20,10 +20,9 @@ public enum TextColor { GREEN ("green", 'a'), AQUA ("aqua", 'b'), RED ("red", 'c'), - PUEPLE ("light_purple",'d'), + PURPLE ("light_purple",'d'), YELLOW ("yellow", 'e'), - WHITE ("white", 'f'), - RESET ("reset", 'r'); + WHITE ("white", 'f'); //@formatter:on private final String name; diff --git a/protocol/src/main/java/mc/protocol/serializer/TextSerializer.java b/protocol/src/main/java/mc/protocol/serializer/TextSerializer.java index 69f2ff3..8633d02 100644 --- a/protocol/src/main/java/mc/protocol/serializer/TextSerializer.java +++ b/protocol/src/main/java/mc/protocol/serializer/TextSerializer.java @@ -5,10 +5,17 @@ import com.eclipsesource.json.JsonArray; import com.eclipsesource.json.JsonObject; import lombok.experimental.UtilityClass; import mc.protocol.model.text.Text; +import mc.protocol.model.text.TextColor; +import mc.protocol.model.text.TextStyle; + +import java.util.Map; @UtilityClass public class TextSerializer { + private static final Map legacyStyleCodes; + private static final Map legacyColorCodes; + public JsonObject toJsonObject(Text text) { JsonObject jsonObject = Json.object(); @@ -38,4 +45,85 @@ public class TextSerializer { return jsonObject; } + + /** + * Преобразование строки вида "&4красный" в {@link Text}. + * + * @param string тест + * @return Text + */ + @SuppressWarnings({"java:S3776", "java:S2583", "java:S135"}) + public Text fromPlain(String string) { + boolean flagSys = false; + Text.Builder rootTextBuilder = Text.builder(); + Text.Builder textBuilder = rootTextBuilder; + + for (char ch : string.toCharArray()) { + if (!flagSys) { + if ('&' == ch) { + flagSys = true; + } else { + textBuilder.append(ch); + } + continue; + } + + if (!legacyStyleCodes.containsKey(ch) && !legacyColorCodes.containsKey(ch) && '&' == ch) { + textBuilder.append('&'); + flagSys = false; + continue; + } + + //noinspection ConstantConditions + if (textBuilder.contentBuilder() != null && textBuilder.contentBuilder().length() > 0) { + if (textBuilder != rootTextBuilder) { + rootTextBuilder.append(textBuilder.build()); + } + textBuilder = Text.builder(); + } + + if (legacyStyleCodes.containsKey(ch)) { + textBuilder.style(legacyStyleCodes.get(ch)); + } else { + textBuilder.color(legacyColorCodes.get(ch)); + } + + flagSys = false; + } + + if (textBuilder != rootTextBuilder) { + rootTextBuilder.append(textBuilder.build()); + } + + return rootTextBuilder.build(); + } + + static { + legacyColorCodes = Map.ofEntries( + Map.entry('0', TextColor.BLACK), + Map.entry('1', TextColor.DARK_BLUE), + Map.entry('2', TextColor.DARK_GREEN), + Map.entry('3', TextColor.DARK_AQUA), + Map.entry('4', TextColor.DARK_RED), + Map.entry('5', TextColor.DARK_PUEPLE), + Map.entry('6', TextColor.GOLD), + Map.entry('7', TextColor.GRAY), + Map.entry('8', TextColor.DARK_GRAY), + Map.entry('9', TextColor.BLUE), + Map.entry('a', TextColor.GREEN), + Map.entry('b', TextColor.AQUA), + Map.entry('c', TextColor.RED), + Map.entry('d', TextColor.PURPLE), + Map.entry('e', TextColor.YELLOW), + Map.entry('f', TextColor.WHITE) + ); + + legacyStyleCodes = Map.of( + 'k', TextStyle.OBFUSCATED, + 'l', TextStyle.BOLD, + 'm', TextStyle.STRIKETHOUGH, + 'n', TextStyle.UNDERLINE, + 'o', TextStyle.ITALIC + ); + } } diff --git a/protocol/src/test/java/mc/protocol/serializer/TextSerializerTest.java b/protocol/src/test/java/mc/protocol/serializer/TextSerializerTest.java new file mode 100644 index 0000000..61bd4fa --- /dev/null +++ b/protocol/src/test/java/mc/protocol/serializer/TextSerializerTest.java @@ -0,0 +1,40 @@ +package mc.protocol.serializer; + +import mc.protocol.model.text.Text; +import mc.protocol.model.text.TextColor; +import mc.protocol.model.text.TextStyle; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class TextSerializerTest { + + @ParameterizedTest + @MethodSource("paramsPlain") + void fromPlain(String sample, Text expected) { + Text actual = TextSerializer.fromPlain(sample); + assertEquals(expected, actual); + } + + @SuppressWarnings("unused") + static Stream paramsPlain() { + return Stream.of( + Arguments.of("text", Text.of("text")), + Arguments.of("&&text", Text.of("&text")), + Arguments.of("&ztext", Text.of("text")), + Arguments.of("&4red_text", Text.of(TextColor.DARK_RED, "red_text")), + Arguments.of("&l&4red_text", Text.of(TextColor.DARK_RED, TextStyle.BOLD, "red_text")), + Arguments.of("&4&lred_text", Text.of(TextColor.DARK_RED, TextStyle.BOLD, "red_text")), + + Arguments.of("&4red_text &eyellow_text", Text.builder() + .color(TextColor.DARK_RED) + .append("red_text ") + .append(Text.of(TextColor.YELLOW, "yellow_text")) + .build()) + ); + } +} \ No newline at end of file From aa0e9bce3bfc24a8f49f4530b6ac6362fb6cd797 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Thu, 29 Apr 2021 19:09:45 +0300 Subject: [PATCH 25/34] =?UTF-8?q?=D0=BC=D0=BD=D0=BE=D0=B3=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D1=80=D0=BE=D1=87=D0=BD=D1=8B=D0=B9=20motd?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/main/java/mc/server/Main.java | 3 ++- server/src/main/resources/config.yml | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/mc/server/Main.java b/server/src/main/java/mc/server/Main.java index a4bd7ab..b18143b 100644 --- a/server/src/main/java/mc/server/Main.java +++ b/server/src/main/java/mc/server/Main.java @@ -14,6 +14,7 @@ import mc.protocol.packets.client.LoginStartPacket; import mc.protocol.packets.client.StatusServerRequestPacket; import mc.protocol.packets.server.DisconnectPacket; import mc.protocol.packets.server.StatusServerResponse; +import mc.protocol.serializer.TextSerializer; import mc.server.config.Config; import mc.server.di.ConfigModule; import mc.server.di.DaggerServerComponent; @@ -61,7 +62,7 @@ public class Main { serverInfo.players().max(config.players().maxOnlile()); serverInfo.players().online(config.players().onlile()); serverInfo.players().sample(Collections.emptyList()); - serverInfo.description(Text.of(config.motd())); + serverInfo.description(TextSerializer.fromPlain(config.motd())); if (config.iconPath() != null) { serverInfo.favicon(faviconToBase64(config.iconPath())); diff --git a/server/src/main/resources/config.yml b/server/src/main/resources/config.yml index 81df62d..8ae56bf 100644 --- a/server/src/main/resources/config.yml +++ b/server/src/main/resources/config.yml @@ -2,7 +2,9 @@ server: host: 127.0.0.1 port: 25565 -motd: 'mc-project::ZERO' +motd: | + &bmc-project &8:: &4ZERO + &8develop by &7DmitriyMX players: max-online: 0 From 27c739ca09e7a7c078bfd8a87b31ac5980ef5aeb Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Thu, 29 Apr 2021 21:14:10 +0300 Subject: [PATCH 26/34] =?UTF-8?q?fix:=20=D0=BE=D1=82=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BA=D0=B0=20=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=B2=20NetByteBuf?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/mc/protocol/io/NetByteBuf.java | 15 +++++-------- .../mc/protocol/io/NetByteBufWriteTest.java | 22 +++++++++++-------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/protocol/src/main/java/mc/protocol/io/NetByteBuf.java b/protocol/src/main/java/mc/protocol/io/NetByteBuf.java index d1c3638..da59f07 100644 --- a/protocol/src/main/java/mc/protocol/io/NetByteBuf.java +++ b/protocol/src/main/java/mc/protocol/io/NetByteBuf.java @@ -93,19 +93,16 @@ public class NetByteBuf extends ByteBuf { } public void writeString(String string) { - byte[] buf; - int length = (int) string.codePoints().count(); + byte[] buf = string.getBytes(StandardCharsets.UTF_8); - if (length > Short.MAX_VALUE) { - log.warn("String is too long: {} > {}", length, Short.MAX_VALUE); - buf = string.substring(0, Short.MAX_VALUE).getBytes(StandardCharsets.UTF_8); + if (buf.length > Short.MAX_VALUE) { + log.warn("String is too long: {} > {}", buf.length, Short.MAX_VALUE); writeVarInt(Short.MAX_VALUE); + writeBytes(buf, 0, Short.MAX_VALUE); } else { - buf = string.getBytes(StandardCharsets.UTF_8); - writeVarInt(length); + writeVarInt(buf.length); + writeBytes(buf); } - - writeBytes(buf); } //endregion diff --git a/protocol/src/test/java/mc/protocol/io/NetByteBufWriteTest.java b/protocol/src/test/java/mc/protocol/io/NetByteBufWriteTest.java index 74b6c5a..3386041 100644 --- a/protocol/src/test/java/mc/protocol/io/NetByteBufWriteTest.java +++ b/protocol/src/test/java/mc/protocol/io/NetByteBufWriteTest.java @@ -50,15 +50,15 @@ class NetByteBufWriteTest { @ParameterizedTest @MethodSource("paramsWriteString") - void writeString(String string) { + void writeString(String string, int exceptedLength) { ByteBuf byteBuf = Unpooled.buffer(); NetByteBuf netByteBuf = new NetByteBuf(byteBuf); netByteBuf.writeString(string); byte[] actualArray = netByteBuf.copy(0, netByteBuf.readableBytes()).array(); - int length = actualArray[0]; // допустим, что размер поместился в один байт - assertEquals(string.codePoints().count(), length); + int actualLength = actualArray[0]; // допустим, что размер поместился в один байт + assertEquals(exceptedLength, actualLength); byte[] dataBytes = new byte[actualArray.length - 1]; System.arraycopy(actualArray, 1, dataBytes, 0, dataBytes.length); @@ -196,12 +196,16 @@ class NetByteBufWriteTest { @SuppressWarnings("unused") private static Stream paramsWriteString() { return Stream.of( - Arguments.of(""), - Arguments.of("Latin"), - Arguments.of("Кириллица"), - Arguments.of("العربية"), - Arguments.of("ﬦﬣﬡ"), // Алфавитные формы представления - Arguments.of("\uD800\uDD07") // Эгейские цифры, [один] + Arguments.of("", 0), + Arguments.of("Latin", 5), + Arguments.of("Кириллица", 37), + // (9) -> "Кириллица"(18) => 18*2=36 (37?) + Arguments.of("العربية", 30), + // (7) -> "Ш§Щ„Ш№Ш±ШЁЩЉШ©"(14) => 14*2=28 (30?) + Arguments.of("ﬦﬣﬡ", 18), // Алфавитные формы представления + // (3) -> "ﬦﬣﬡ"(9) => 9*2=18 + Arguments.of("\uD800\uDD07", 4) // Эгейские цифры, [один] + // (1) -> "𐄇" => ...4! ); } From 9b6fccd9bd741f34eac3c69e19d2aeb953c01254 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Thu, 29 Apr 2021 21:43:07 +0300 Subject: [PATCH 27/34] =?UTF-8?q?=D0=BF=D1=80=D0=B8=D1=87=D0=B8=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=BE=D1=82=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=BE=D1=82=20=D1=81=D0=B5=D1=80=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=20=D0=B2=20=D0=BA=D0=BE=D0=BD=D1=84=D0=B8=D0=B3=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/main/java/mc/server/Main.java | 3 +-- server/src/main/java/mc/server/config/Config.java | 1 + server/src/main/java/mc/server/di/ConfigModule.java | 1 + server/src/main/resources/config.yml | 2 ++ 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/mc/server/Main.java b/server/src/main/java/mc/server/Main.java index b18143b..c839916 100644 --- a/server/src/main/java/mc/server/Main.java +++ b/server/src/main/java/mc/server/Main.java @@ -7,7 +7,6 @@ import lombok.extern.slf4j.Slf4j; import mc.protocol.NettyServer; import mc.protocol.ProtocolConstant; import mc.protocol.model.ServerInfo; -import mc.protocol.model.text.Text; import mc.protocol.packets.PingPacket; import mc.protocol.packets.client.HandshakePacket; import mc.protocol.packets.client.LoginStartPacket; @@ -78,7 +77,7 @@ public class Main { .doOnNext(channel -> log.info("{}", channel.getPacket())) .subscribe(channel -> { DisconnectPacket disconnectPacket = new DisconnectPacket(); - disconnectPacket.setReason(Text.of("Server is not available.")); + disconnectPacket.setReason(TextSerializer.fromPlain(config.disconnectReason())); channel.getCtx().writeAndFlush(disconnectPacket).channel().disconnect(); }); diff --git a/server/src/main/java/mc/server/config/Config.java b/server/src/main/java/mc/server/config/Config.java index 310adf6..07340fc 100644 --- a/server/src/main/java/mc/server/config/Config.java +++ b/server/src/main/java/mc/server/config/Config.java @@ -17,6 +17,7 @@ public class Config { private final Players players = new Players(); private String motd; + private String disconnectReason; private Path iconPath; @Getter diff --git a/server/src/main/java/mc/server/di/ConfigModule.java b/server/src/main/java/mc/server/di/ConfigModule.java index 510b077..c4bd5b0 100644 --- a/server/src/main/java/mc/server/di/ConfigModule.java +++ b/server/src/main/java/mc/server/di/ConfigModule.java @@ -28,6 +28,7 @@ public class ConfigModule { config.server().host(fromYamlPath("server/host", map, "127.0.0.1")); config.server().port(fromYamlPath("server/port", map, 25565)); config.motd(fromYamlPath("motd", map, "")); + config.disconnectReason(fromYamlPath("disconnect-reason", map, "")); config.players().maxOnlile(fromYamlPath("players/max-online", map, 0)); config.players().onlile(fromYamlPath("players/online", map, 0)); diff --git a/server/src/main/resources/config.yml b/server/src/main/resources/config.yml index 8ae56bf..7bbd46a 100644 --- a/server/src/main/resources/config.yml +++ b/server/src/main/resources/config.yml @@ -6,6 +6,8 @@ motd: | &bmc-project &8:: &4ZERO &8develop by &7DmitriyMX +disconnect-reason: '&4Server is not available.' + players: max-online: 0 online: 0 From e72a8443cdbcafb1a3e090c67b59399280265940 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Thu, 29 Apr 2021 22:01:16 +0300 Subject: [PATCH 28/34] gradle upgrade --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 442d913..f371643 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From d4f7192e92ff182e5b184bbb962c8f691624bb14 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Thu, 29 Apr 2021 23:23:21 +0300 Subject: [PATCH 29/34] =?UTF-8?q?gradle:=20=D0=BD=D0=B0=D0=B2=D0=BE=D0=B4?= =?UTF-8?q?=D0=B8=D0=BC=20=D0=BF=D0=BE=D1=80=D1=8F=D0=B4=D0=BE=D0=BA=20?= =?UTF-8?q?=D0=B2=20=D0=B7=D0=B0=D0=B2=D0=B8=D1=81=D0=B8=D0=BC=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D1=8F=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs.gradle | 5 +++-- logic.gradle | 1 + protocol/build.gradle | 5 ++--- .../main/java/mc/protocol/di/ProtocolModule.java | 13 +++++-------- .../protocol/serializer/ServerInfoSerializer.java | 8 ++++++-- server/build.gradle | 13 ++++++++++--- 6 files changed, 27 insertions(+), 18 deletions(-) diff --git a/libs.gradle b/libs.gradle index 6bac138..691322b 100644 --- a/libs.gradle +++ b/libs.gradle @@ -6,14 +6,15 @@ def slf4j_version = '1.7.30' def logback_version = '1.2.3' def dagger2_version = '2.33' def junit_version = '5.5.2' +def netty_version = '4.1.22.Final' ext { libs = [ lombok : 'org.projectlombok:lombok:1.18.12', annotations: 'com.google.code.findbugs:jsr305:3.0.2', - guava : 'com.google.guava:guava:30.1-jre', lang3 : 'org.apache.commons:commons-lang3:3.11', - netty : 'io.netty:netty-all:4.1.22.Final', + netty : ["io.netty:netty-transport:${netty_version}", + "io.netty:netty-handler:${netty_version}"], reactor : 'io.projectreactor:reactor-core:3.4.5', yaml : 'org.yaml:snakeyaml:1.28', json : 'com.eclipsesource.minimal-json:minimal-json:0.9.5', diff --git a/logic.gradle b/logic.gradle index eb5630f..68886aa 100644 --- a/logic.gradle +++ b/logic.gradle @@ -1,5 +1,6 @@ //file:noinspection GrUnresolvedAccess apply plugin: 'java' +apply plugin: 'java-library' apply from: rootDir.toPath().resolve('libs.gradle').toFile() String getProperty1(String propertyName1, String propertyName2) { diff --git a/protocol/build.gradle b/protocol/build.gradle index 1a4110a..03ac861 100644 --- a/protocol/build.gradle +++ b/protocol/build.gradle @@ -1,9 +1,8 @@ apply from: rootDir.toPath().resolve('logic.gradle').toFile() dependencies { - implementation libs.netty - implementation libs.reactor - implementation libs.guava + api libs.netty + api libs.reactor implementation libs.json testImplementation libs.lang3 diff --git a/protocol/src/main/java/mc/protocol/di/ProtocolModule.java b/protocol/src/main/java/mc/protocol/di/ProtocolModule.java index 479e6c9..167d27f 100644 --- a/protocol/src/main/java/mc/protocol/di/ProtocolModule.java +++ b/protocol/src/main/java/mc/protocol/di/ProtocolModule.java @@ -1,6 +1,5 @@ package mc.protocol.di; -import com.google.common.collect.ImmutableMap; import dagger.Module; import dagger.Provides; import io.netty.bootstrap.ServerBootstrap; @@ -22,9 +21,11 @@ import mc.protocol.io.codec.ProtocolSplitter; import mc.protocol.packets.Packet; import reactor.core.publisher.Sinks; +import javax.annotation.Nonnull; import javax.inject.Provider; import java.util.LinkedHashMap; import java.util.Map; +import java.util.stream.Collectors; import java.util.stream.Stream; @Module @@ -54,7 +55,7 @@ public class ProtocolModule { return new ChannelInitializer<>() { @Override - protected void initChannel(SocketChannel socketChannel) { + protected void initChannel(@Nonnull SocketChannel socketChannel) { ChannelPipeline pipeline = socketChannel.pipeline(); channelHandlerMapProvider.get().forEach(pipeline::addLast); } @@ -81,12 +82,8 @@ public class ProtocolModule { @Provides @ServerScope Map, Sinks.Many> provideObservedMap() { - ImmutableMap.Builder, Sinks.Many> builder = ImmutableMap.builder(); - - Stream.of(State.values()) + return Stream.of(State.values()) .flatMap(state -> state.getClientSidePackets().values().stream()) - .forEach(packetClass -> builder.put(packetClass, Sinks.many().multicast().directBestEffort())); - - return builder.build(); + .collect(Collectors.toMap(packetClass -> packetClass, v -> Sinks.many().multicast().directBestEffort())); } } diff --git a/protocol/src/main/java/mc/protocol/serializer/ServerInfoSerializer.java b/protocol/src/main/java/mc/protocol/serializer/ServerInfoSerializer.java index 3b98b3d..f215b55 100644 --- a/protocol/src/main/java/mc/protocol/serializer/ServerInfoSerializer.java +++ b/protocol/src/main/java/mc/protocol/serializer/ServerInfoSerializer.java @@ -3,11 +3,13 @@ package mc.protocol.serializer; import com.eclipsesource.json.Json; import com.eclipsesource.json.JsonArray; import com.eclipsesource.json.JsonObject; -import com.google.common.collect.Streams; import lombok.experimental.UtilityClass; import mc.protocol.model.ServerInfo; +import java.util.Spliterator; +import java.util.Spliterators; import java.util.stream.Collector; +import java.util.stream.StreamSupport; @UtilityClass public class ServerInfoSerializer { @@ -45,7 +47,9 @@ public class ServerInfoSerializer { } private static JsonArray jsonArrayAddAll(JsonArray jsonArrayTo, JsonArray jsonArrayFrom) { - Streams.stream(jsonArrayFrom).forEach(jsonArrayTo::add); + StreamSupport.stream( + Spliterators.spliteratorUnknownSize(jsonArrayFrom.iterator(), Spliterator.ORDERED), false) + .forEach(jsonArrayTo::add); return jsonArrayTo; } } diff --git a/server/build.gradle b/server/build.gradle index 91cb14c..b4c92f4 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -4,6 +4,10 @@ */ //file:noinspection GrUnresolvedAccess +plugins { + id 'com.github.johnrengelman.shadow' version '7.0.0' +} + apply from: rootDir.toPath().resolve('logic.gradle').toFile() apply plugin: 'application' @@ -16,10 +20,13 @@ dependencies { implementation libs.logger.logback - implementation libs.netty - implementation libs.reactor - implementation libs.guava implementation libs.yaml implementation libs.ioutils implementation libs.jopt } + +shadowJar { + archiveBaseName.set(jar.archiveBaseName.get()) + archiveVersion.set(project.version as String) + archiveClassifier.set('') +} \ No newline at end of file From 2b4e58ae160c2c5610e2fe5be538bf79bd0ba54f Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Fri, 30 Apr 2021 00:49:55 +0300 Subject: [PATCH 30/34] =?UTF-8?q?=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.MD | 10 +++++++++- server/build.gradle | 4 ++++ .../resources/{config.yml => config-sample.yml} | 5 +++-- server/src/main/resources/favicon.png | Bin 1675 -> 0 bytes .../{logback.xml => logback-sample.xml} | 0 5 files changed, 16 insertions(+), 3 deletions(-) rename server/src/main/resources/{config.yml => config-sample.yml} (72%) delete mode 100644 server/src/main/resources/favicon.png rename server/src/main/resources/{logback.xml => logback-sample.xml} (100%) diff --git a/README.MD b/README.MD index f0e5040..04e53ca 100644 --- a/README.MD +++ b/README.MD @@ -12,6 +12,14 @@ ## Запуск +### Gradle + ```shell -gradle :server:run +gradle :server:run --args="--config=config.yml" --project-prop jvmArgs="-Dlogback.configurationFile=logback.xml" +``` + +### Jar + +```shell +java -Dlogback.configurationFile=logback.xml -jar server.jar --config=config.yml ``` \ No newline at end of file diff --git a/server/build.gradle b/server/build.gradle index b4c92f4..4802380 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -13,6 +13,10 @@ apply plugin: 'application' application { mainClassName = 'mc.server.Main' + + if (project.hasProperty('jvmArgs')) { + applicationDefaultJvmArgs = List.of((project.jvmArgs as String).split('\\s+')) + } } dependencies { diff --git a/server/src/main/resources/config.yml b/server/src/main/resources/config-sample.yml similarity index 72% rename from server/src/main/resources/config.yml rename to server/src/main/resources/config-sample.yml index 7bbd46a..c26428c 100644 --- a/server/src/main/resources/config.yml +++ b/server/src/main/resources/config-sample.yml @@ -12,6 +12,7 @@ players: max-online: 0 online: 0 +# Размер значка: 64x64 px icon: - enable: true - path: src/main/resources/favicon.png \ No newline at end of file + enable: false + path: favicon.png \ No newline at end of file diff --git a/server/src/main/resources/favicon.png b/server/src/main/resources/favicon.png deleted file mode 100644 index d512fc5472e1d4b4573ba22b5e3e71587dbd4c9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1675 zcmV;626Xv}P)09zrl&^1WzcGf>6{pC7KKEp~p(7 zm8$R+BqT&YDrzr1B0?|WNG@&Q)Kgp3N=;EK4kUb5;xDLFQ7H?^5{eKeBm_fnt9);4 z_pn}j*IwH*J2STPlPs-g-^_dS+u4~n@6BpcQ&VUHf&eZ8_=ZvbTL2dT7&48Zlvb7b zWGbk@IDkU&w+{BsqbR#>t3NK?x*}u~Fo3erLlWB^vb8%Pv0Z5doP}xJElKUw!>yvO zvoabJC13)kF_$IS!i&pA-4h~>1O)0youCA81SSzd02{oOy^Me#(LSBG!vOFzZzbLl zunv>ycEuMkC(ICQ1s(zlywz-H;Z9ZWW}5U?3LZ=s>>jR;tiWJoJf zw-5CQ_z4`7NgE>svoEgDYHWu5;9OG&Pkzm3mLSdy4dU>?XFOGcl+vm`)fxfZ4n-@F z$z)&{%r1$mpxZKd-HS2Xdx)26p7GAxI{*OLY!-<`0>NNo_e9tA>y*+#dzl*nM@0Kttz#*yDvK`y0*UpH(X>rVM`=}ojZD5?-?68 zq@O*oAGpUcqZTpe|NcS26u0jodJ?uL0i9_bW z_df{fuSbHe>%US;Pg?}Y3}8Ai{Ui;auiD@8`Fxm}eSv&FkFG=6uy3{yxxs?>ov>&iFj2AYnKF#@HDT^oJ?v4^y(6l?EFLn)FF< z&!Nv9|DWEx>pGj;p?VT@gGGXL0-oNyTUFMI4zfaJc6d`jsUOhyZg1&2^>`W|b_B3J z}SADsBhDam=pu7tF21QY! zHr^DC17%nElnM=gpO5)x_XJfV6bgY-dKysd2jm)r!diuRyu3TL6L1uQXYSnKkAz*z zbE|8JMz;b0mX}xHM*(49<594blX76Clq0kgpu}Cvt*)Ub*hj@Jf9O$#f;+9AFM2|wG0Lza89UDD8SgLuKs%Ajn^iH5Dtfd8VR6U1mpl*0q`ZO zlA{L?a2qCqcs#}|8;ixRpvD8Obxh8}8aU1hGM>^mZY^%KS8vW6cX}DiT;b5AY>MG;n+=(kc=NAqF@e7;k1M1aoy@HHNc! z?+Ay(AcXt^&I8_FQe$6%<4{F2NFanD7K;S|oZ+qOH8;2cbC@xmD^^7UAq0ew>qT2U zIc}oK(PKsB=NbvhBq5nhf)H}9sQZ{mTe7mlmth)nu%3_z387HPdg6yPGkzxJV@=uV z@!K$o&;VR@6W}4Cv$NCc^woGgZnZ1*^IVlN!6B3*%|V!lvCacbBzy;81Wour^M8T$ Vqx`lI%8LL1002ovPDHLkV1m=#{XPHy diff --git a/server/src/main/resources/logback.xml b/server/src/main/resources/logback-sample.xml similarity index 100% rename from server/src/main/resources/logback.xml rename to server/src/main/resources/logback-sample.xml From b90ab4b5dba258efdf7532917961fdde83587929 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Sat, 1 May 2021 00:21:18 +0300 Subject: [PATCH 31/34] =?UTF-8?q?cli:=20=D0=BF=D0=BE=D0=B4=D0=B3=D0=BE?= =?UTF-8?q?=D1=82=D0=BE=D0=B2=D0=BA=D0=B0=20=D0=BE=D0=BA=D1=80=D1=83=D0=B6?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/main/java/mc/server/Main.java | 44 +++++++++++++++++++++--- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/server/src/main/java/mc/server/Main.java b/server/src/main/java/mc/server/Main.java index c839916..6f57b77 100644 --- a/server/src/main/java/mc/server/Main.java +++ b/server/src/main/java/mc/server/Main.java @@ -21,20 +21,25 @@ import mc.server.di.ServerComponent; import org.apache.commons.io.IOUtils; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Base64; import java.util.Collections; import java.util.List; +import java.util.Objects; @Slf4j +@SuppressWarnings("java:S106") public class Main { + private static final String CLI_CONFIG = "config"; private void run(OptionSet optionSet) { log.info("mc-project launch"); - ConfigModule configModule = new ConfigModule((Path) optionSet.valueOf("config")); + ConfigModule configModule = new ConfigModule((Path) optionSet.valueOf(CLI_CONFIG)); ServerComponent serverComponent = DaggerServerComponent.builder() .configModule(configModule) @@ -85,8 +90,7 @@ public class Main { server.bind(config.server().host(), config.server().port()); } - @SuppressWarnings("java:S106") - public static void main(String[] args) { + public static void main(String[] args) throws IOException { OptionParser optionParser = createOptionParser(); OptionSet optionSet = optionParser.parse(args); @@ -98,6 +102,25 @@ public class Main { e.printStackTrace(System.err); } return; + } else if (optionSet.has("init")) { + Path configPath = (Path) optionSet.valueOf(CLI_CONFIG); + Path logbackPath = Paths.get(System.getProperty("logback.configurationFile", "logback.xml")); + + if (!initializeCheckFiles(configPath, logbackPath)) { + return; + } + + InputStream configResource = Objects.requireNonNull(Main.class.getResourceAsStream("/config-sample.yml")); + InputStream logbackResource = Objects.requireNonNull(Main.class.getResourceAsStream("/logback-sample.xml")); + + try(OutputStream configOut = Files.newOutputStream(configPath); + OutputStream logbackOut = Files.newOutputStream(logbackPath)) { + IOUtils.copy(configResource, configOut); + IOUtils.copy(logbackResource, logbackOut); + } + + System.out.println("Initialization environment done."); + return; } if (log.isDebugEnabled()) { @@ -113,10 +136,11 @@ public class Main { private static OptionParser createOptionParser() { OptionParser optionParser = new OptionParser(); optionParser.acceptsAll(List.of("h", "help"), "Help page").forHelp(); - optionParser.accepts("config", "Path to configuration file") + optionParser.accepts(CLI_CONFIG, "Path to configuration file") .withRequiredArg() .withValuesConvertedBy(new PathConverter()) .defaultsTo(Paths.get("config.yml")); + optionParser.accepts("init", "Initialize environment"); return optionParser; } @@ -131,4 +155,16 @@ public class Main { return ""; } } + + private static boolean initializeCheckFiles(Path... paths) { + for (Path path : paths) { + if (Files.exists(path)) { + System.err.printf("File '%s' already exist. Initialization environment canceled.%n", + path.toAbsolutePath()); + return false; + } + } + + return true; + } } From b97bb8432d79fa53880dfc43e0bb45c509037c25 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Sat, 1 May 2021 15:34:00 +0300 Subject: [PATCH 32/34] =?UTF-8?q?cli:=20=D0=BF=D1=83=D1=82=D1=8C=20=D0=B4?= =?UTF-8?q?=D0=BE=20=D0=BD=D0=B0=D1=81=D1=82=D1=80=D0=BE=D0=B5=D0=BA=20?= =?UTF-8?q?=D0=BB=D0=BE=D0=B3=D0=B3=D0=B5=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.MD | 4 +-- server/src/main/java/mc/server/Main.java | 34 ++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/README.MD b/README.MD index 04e53ca..968e795 100644 --- a/README.MD +++ b/README.MD @@ -15,11 +15,11 @@ ### Gradle ```shell -gradle :server:run --args="--config=config.yml" --project-prop jvmArgs="-Dlogback.configurationFile=logback.xml" +gradle :server:run --args="--config=config.yml --logconfig==logback.xml" ``` ### Jar ```shell -java -Dlogback.configurationFile=logback.xml -jar server.jar --config=config.yml +java -jar server.jar --config=config.yml --logconfig==logback.xml ``` \ No newline at end of file diff --git a/server/src/main/java/mc/server/Main.java b/server/src/main/java/mc/server/Main.java index 6f57b77..c5f506e 100644 --- a/server/src/main/java/mc/server/Main.java +++ b/server/src/main/java/mc/server/Main.java @@ -1,5 +1,8 @@ package mc.server; +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.joran.JoranConfigurator; +import ch.qos.logback.core.joran.spi.JoranException; import joptsimple.OptionParser; import joptsimple.OptionSet; import joptsimple.util.PathConverter; @@ -19,6 +22,7 @@ import mc.server.di.ConfigModule; import mc.server.di.DaggerServerComponent; import mc.server.di.ServerComponent; import org.apache.commons.io.IOUtils; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.InputStream; @@ -35,6 +39,7 @@ import java.util.Objects; @SuppressWarnings("java:S106") public class Main { private static final String CLI_CONFIG = "config"; + private static final String CLI_LOGCONFIG = "logconfig"; private void run(OptionSet optionSet) { log.info("mc-project launch"); @@ -104,7 +109,7 @@ public class Main { return; } else if (optionSet.has("init")) { Path configPath = (Path) optionSet.valueOf(CLI_CONFIG); - Path logbackPath = Paths.get(System.getProperty("logback.configurationFile", "logback.xml")); + Path logbackPath = (Path) optionSet.valueOf(CLI_LOGCONFIG); if (!initializeCheckFiles(configPath, logbackPath)) { return; @@ -123,6 +128,8 @@ public class Main { return; } + reconfigureLogback(optionSet); + if (log.isDebugEnabled()) { optionSet.asMap().forEach((optionSpec, objects) -> { if (optionSpec.isForHelp()) return; @@ -135,12 +142,19 @@ public class Main { private static OptionParser createOptionParser() { OptionParser optionParser = new OptionParser(); + optionParser.acceptsAll(List.of("h", "help"), "Help page").forHelp(); + optionParser.accepts("init", "Initialize environment"); + optionParser.accepts(CLI_CONFIG, "Path to configuration file") .withRequiredArg() .withValuesConvertedBy(new PathConverter()) .defaultsTo(Paths.get("config.yml")); - optionParser.accepts("init", "Initialize environment"); + + optionParser.accepts(CLI_LOGCONFIG, "Path to logger configuratuin file") + .withRequiredArg() + .withValuesConvertedBy(new PathConverter()) + .defaultsTo(Paths.get("logback.xml")); return optionParser; } @@ -167,4 +181,20 @@ public class Main { return true; } + + private static void reconfigureLogback(OptionSet optionSet) throws IOException { + LoggerContext logbackContext = (LoggerContext) LoggerFactory.getILoggerFactory(); + logbackContext.reset(); + JoranConfigurator configurator = new JoranConfigurator(); + + Path logbackPath = (Path) optionSet.valueOf(CLI_LOGCONFIG); + try(InputStream in = Objects.requireNonNull( + Files.newInputStream(logbackPath), "File not found: " + logbackPath.toAbsolutePath())) { + + configurator.setContext(logbackContext); + configurator.doConfigure(in); + } catch (JoranException e) { + throw new IOException(e); + } + } } From 80eab876b3a7bdc61b94374f70061efde90287a7 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Sat, 1 May 2021 15:37:11 +0300 Subject: [PATCH 33/34] =?UTF-8?q?cli:=20=D0=BF=D0=BE=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=B4=D0=B5=D1=84=D0=BE=D0=BB?= =?UTF-8?q?=D1=82=D0=BD=D1=8B=D0=B5=20=D0=BD=D0=B0=D1=81=D1=82=D1=80=D0=BE?= =?UTF-8?q?=D0=B9=D0=BA=D0=B8=20logback?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/main/resources/logback-sample.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/src/main/resources/logback-sample.xml b/server/src/main/resources/logback-sample.xml index 192c634..f72ea29 100644 --- a/server/src/main/resources/logback-sample.xml +++ b/server/src/main/resources/logback-sample.xml @@ -4,7 +4,7 @@ - %d{HH:mm:ss.SSS} %-5level [%35.35logger{34}] -- %msg%n + %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%35.35logger{34}] -- %msg%n @@ -12,7 +12,9 @@ + \ No newline at end of file From 4d849efcf2070d80d33f1046953212b391ee74e0 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Sat, 1 May 2021 16:27:13 +0300 Subject: [PATCH 34/34] update README --- README.MD | 96 +++++++++++++++++++++++++++++++++++++++++---- server/build.gradle | 5 ++- 2 files changed, 93 insertions(+), 8 deletions(-) diff --git a/README.MD b/README.MD index 968e795..352a11a 100644 --- a/README.MD +++ b/README.MD @@ -4,22 +4,104 @@ ![codename: ZERO](https://img.shields.io/badge/codename-ZERO-509.svg?style=flat) ![protocol: 1.12.2](https://img.shields.io/badge/protocol-1.12.2-075.svg?style=flat) +Написанный с нуля сервер **Minecraft 1.12.2**. + +На данный момент может только показывать информацию о себе. Подключение к серверу не возможно. + --- +## Требования + * Java 11 ---- - ## Запуск -### Gradle +Для запуска требуются некоторые файлы настроек. Для их генерации можно воспользоваться командой инициализации окружения: ```shell -gradle :server:run --args="--config=config.yml --logconfig==logback.xml" +java -jar server.jar --init ``` -### Jar +После выполнить запуск самого сервера: ```shell -java -jar server.jar --config=config.yml --logconfig==logback.xml -``` \ No newline at end of file +java -jar server.jar +``` + +### Параметры командной строки + +`--init` +Инициализация окружения. Генерирует необхидимые для запуска сервера файлы. + +`--config=path/to/config.yml` +Указание альтернативного пути для конфигурационного файла сервера. + +`--logconfig=path/to/logback.xml` +Указание альтернативного пути для конфигурационного файла логгера (logback). + +## Настройки + +### Стилизованный текст + +Файл конфига позволяет использовать специальные коды для добавления цвета и стиля в текст. + +| Код | Цвет | Код | Стиль | +| ---- | ------------------------------------------- | ---- | --------------------------------------------------------------- | +| `&0` | Black | `&l` | Bold | +| `&1` | Dark Blue | `&o` | Italic | +| `&2` | Dark Green | `&n` | Underline | +| `&3` | Dark Aqua | `&m` | Strikethrough | +| `&4` | Dark Red | `&k` | Obfuscated | +| `&5` | Dark Purple | +| `&6` | Gold | +| `&7` | Gray | +| `&8` | Dark Gray | +| `&9` | Blue | +| `&a` | Green | +| `&b` | Aqua | +| `&c` | Red | +| `&d` | Purple | +| `&e` | Yellow | +| `&f` | White | + + +### motd + +```yaml +motd: | + mc-project :: ZERO + develop by DmitriyMX +``` + +Настройка надписи, которая будет отображаться в списке серверов у клиента. Максимум может состоять из двух строк. + +### disconnect-reason + +```yaml +disconnect-reason: Server is not available. +``` + +Причина отключения от сервера. Количество строк не ограничено. + +### players + +```yaml +players: + max-online: 0 + online: 0 +``` + +Фиктивные данные об онлайне сервера. + +### icon + +```yaml +icon: + enable: true + path: favicon.png +``` + +Использовать значок сервера. +Настройка `enable` говорит о факте использования значка, а в настройке `path` указывается путь к значку. + +Формат значка должен быть **PNG** и быть размерами **64x64 px**. Другие форматы или размеры _не поддерживаются_. \ No newline at end of file diff --git a/server/build.gradle b/server/build.gradle index 4802380..7b27ae3 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -1,6 +1,9 @@ /* Запуск - gradle :server:run + gradle :server:run --args="--config=config.yml --logconfig==logback.xml" + +Сборка + gradle :server:shadowJar */ //file:noinspection GrUnresolvedAccess