From 796076c97ca13419bd9f0b2442a8a146554f922d Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Sun, 10 Jun 2018 20:04:33 +0300 Subject: [PATCH] Ping server --- .../main/java/mc/core/network/NetStream.java | 3 + .../network/proto_125/NetStream_p125.java | 15 +++ .../network/proto_125/netty/NettyServer.java | 7 +- proto_1.12.2/build.gradle | 11 ++ .../ByteArrayOutputNetStream.java | 121 ++++++++++++++++++ .../network/proto_1_12_2/NetStream_p340.java | 73 +++++++++++ .../mc/core/network/proto_1_12_2/State.java | 61 +++++++++ .../proto_1_12_2/packets/HandshakePacket.java | 30 +++++ .../proto_1_12_2/packets/PingPacket.java | 28 ++++ .../packets/StatusRequestPacket.java | 16 +++ .../packets/StatusResponsePacket.java | 54 ++++++++ proto_1.12.2_netty/build.gradle | 14 ++ .../proto_1_12_2/netty/NettyServer.java | 81 ++++++++++++ .../proto_1_12_2/netty/PacketDecoder.java | 60 +++++++++ .../proto_1_12_2/netty/PacketEncoder.java | 48 +++++++ .../proto_1_12_2/netty/PacketHandler.java | 91 +++++++++++++ .../netty/wrappers/WrapperNetStream.java | 111 ++++++++++++++++ settings.gradle | 2 + 18 files changed, 825 insertions(+), 1 deletion(-) create mode 100644 proto_1.12.2/build.gradle create mode 100644 proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/ByteArrayOutputNetStream.java create mode 100644 proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/NetStream_p340.java create mode 100644 proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/State.java create mode 100644 proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/HandshakePacket.java create mode 100644 proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PingPacket.java create mode 100644 proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/StatusRequestPacket.java create mode 100644 proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/StatusResponsePacket.java create mode 100644 proto_1.12.2_netty/build.gradle create mode 100644 proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/NettyServer.java create mode 100644 proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/PacketDecoder.java create mode 100644 proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/PacketEncoder.java create mode 100644 proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/PacketHandler.java create mode 100644 proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/wrappers/WrapperNetStream.java diff --git a/core/src/main/java/mc/core/network/NetStream.java b/core/src/main/java/mc/core/network/NetStream.java index a2d7312..e947393 100644 --- a/core/src/main/java/mc/core/network/NetStream.java +++ b/core/src/main/java/mc/core/network/NetStream.java @@ -19,6 +19,8 @@ public abstract class NetStream { public abstract int readUnsignedShort(); public abstract short readShort(); public abstract int readInt(); + public abstract int readVarInt(); + public abstract long readLong(); public abstract float readFloat(); public abstract double readDouble(); public abstract String readString(); @@ -28,6 +30,7 @@ public abstract class NetStream { public abstract void writeBytes(byte[] buffer); public abstract void writeShort(int value); public abstract void writeInt(int value); + public abstract void writeVarInt(int value); public abstract void writeLong(long value); public abstract void writeFloat(float value); public abstract void writeDouble(double value); diff --git a/proto125/src/main/java/mc/core/network/proto_125/NetStream_p125.java b/proto125/src/main/java/mc/core/network/proto_125/NetStream_p125.java index 8280116..917d8ab 100644 --- a/proto125/src/main/java/mc/core/network/proto_125/NetStream_p125.java +++ b/proto125/src/main/java/mc/core/network/proto_125/NetStream_p125.java @@ -37,4 +37,19 @@ public abstract class NetStream_p125 extends NetStream { writeBytes(buf); } } + + @Override + public int readVarInt() { + return readInt(); + } + + @Override + public void writeVarInt(int value) { + writeInt(value); + } + + @Override + public long readLong() { + return 0; //FIXME + } } diff --git a/proto125_netty/src/main/java/mc/core/network/proto_125/netty/NettyServer.java b/proto125_netty/src/main/java/mc/core/network/proto_125/netty/NettyServer.java index 06635f3..74dda1f 100644 --- a/proto125_netty/src/main/java/mc/core/network/proto_125/netty/NettyServer.java +++ b/proto125_netty/src/main/java/mc/core/network/proto_125/netty/NettyServer.java @@ -23,7 +23,9 @@ import org.springframework.context.ApplicationContext; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; +import java.util.Collections; import java.util.Map; +import java.util.stream.Collectors; @Slf4j public class NettyServer implements Server { @@ -56,7 +58,10 @@ public class NettyServer implements Server { @Override protected void initChannel(SocketChannel socketChannel) { Map beans = applicationContext.getBeansOfType(ChannelHandler.class); - beans.forEach(socketChannel.pipeline()::addLast); + beans.entrySet().stream() + .sorted((e1, e2) -> e1.getKey().compareToIgnoreCase(e2.getKey())) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)) + .forEach(socketChannel.pipeline()::addLast); } }; } diff --git a/proto_1.12.2/build.gradle b/proto_1.12.2/build.gradle new file mode 100644 index 0000000..463d1fb --- /dev/null +++ b/proto_1.12.2/build.gradle @@ -0,0 +1,11 @@ +group 'mc' +version '1.0-SNAPSHOT' + +dependencies { + /* Core */ + compile_excludeCopy project(':core') + + /* Components */ + compile (group: 'com.google.guava', name: 'guava', version: '24.1-jre') + compile (group: 'com.google.code.gson', name: 'gson', version: '2.8.2') +} diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/ByteArrayOutputNetStream.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/ByteArrayOutputNetStream.java new file mode 100644 index 0000000..b757282 --- /dev/null +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/ByteArrayOutputNetStream.java @@ -0,0 +1,121 @@ +/* + * DmitriyMX + * 2018-06-10 + */ +package mc.core.network.proto_1_12_2; + +import java.io.ByteArrayOutputStream; + +public class ByteArrayOutputNetStream extends NetStream_p340 { + private ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + @Override + public boolean readBoolean() { + throw new UnsupportedOperationException(); + } + + @Override + public byte readByte() { + throw new UnsupportedOperationException(); + } + + @Override + public void readBytes(byte[] buffer) { + throw new UnsupportedOperationException(); + } + + @Override + public int readUnsignedByte() { + throw new UnsupportedOperationException(); + } + + @Override + public int readUnsignedShort() { + throw new UnsupportedOperationException(); + } + + @Override + public short readShort() { + throw new UnsupportedOperationException(); + } + + @Override + public int readInt() { + throw new UnsupportedOperationException(); + } + + @Override + public long readLong() { + throw new UnsupportedOperationException(); + } + + @Override + public float readFloat() { + throw new UnsupportedOperationException(); + } + + @Override + public double readDouble() { + throw new UnsupportedOperationException(); + } + + @Override + public void writeBoolean(boolean value) { + baos.write(value ? 1 : 0); + } + + @Override + public void writeByte(int value) { + baos.write(value); + } + + @Override + public void writeBytes(byte[] buffer) { + baos.write(buffer, 0, buffer.length); + } + + @Override + public void writeShort(int value) { + baos.write((byte) value >>> 8); + baos.write((byte) value); + } + + @Override + public void writeInt(int value) { + baos.write((byte)((int)(value >>> 24))); + baos.write((byte)((int)(value >>> 16))); + baos.write((byte)((int)(value >>> 8))); + baos.write((byte)((int)(value))); + } + + @Override + public void writeLong(long value) { + baos.write((byte)((int)(value >>> 56))); + baos.write((byte)((int)(value >>> 48))); + baos.write((byte)((int)(value >>> 40))); + baos.write((byte)((int)(value >>> 32))); + baos.write((byte)((int)(value >>> 24))); + baos.write((byte)((int)(value >>> 16))); + baos.write((byte)((int)(value >>> 8))); + baos.write((byte)((int)(value))); + } + + @Override + public void writeFloat(float value) { + writeInt(Float.floatToIntBits(value)); + } + + @Override + public void writeDouble(double value) { + writeLong(Double.doubleToLongBits(value)); + } + + @Override + public void skipBytes(int count) { + throw new UnsupportedOperationException(); + } + + public byte[] toByteArray() { + return baos.toByteArray(); + } +} diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/NetStream_p340.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/NetStream_p340.java new file mode 100644 index 0000000..923b4c3 --- /dev/null +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/NetStream_p340.java @@ -0,0 +1,73 @@ +/* + * DmitriyMX + * 2018-06-10 + */ +package mc.core.network.proto_1_12_2; + +import lombok.extern.slf4j.Slf4j; +import mc.core.network.NetStream; + +import java.nio.charset.StandardCharsets; + +@Slf4j +public abstract class NetStream_p340 extends NetStream { + @Override + public int readVarInt() { + int numRead = 0; + int result = 0; + byte read; + do { + read = readByte(); + int value = (read & 0b01111111); + result |= (value << (7 * numRead)); + + numRead++; + if (numRead > 5) { + log.warn("VarInt is too big"); + break; + } + } while ((read & 0b10000000) != 0); + + return result; + } + + @Override + public void writeVarInt(int value) { + do { + byte temp = (byte)(value & 0b01111111); + // Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone + value >>>= 7; + if (value != 0) { + temp |= 0b10000000; + } + writeByte(temp); + } while (value != 0); + } + + @Override + public String readString() { + int size = readVarInt(); + if (size == 0) { + log.warn("String zero length??"); + return ""; + } + + byte[] bytes = new byte[size]; + readBytes(bytes); + return new String(bytes, StandardCharsets.UTF_8); + } + + @Override + public void writeString(String value) { + if (value.length() > Short.MAX_VALUE) { + log.warn("String \"{}\" too long!", value); + byte[] buf = value.substring(0, Short.MAX_VALUE).getBytes(StandardCharsets.UTF_8); + writeVarInt(Short.MAX_VALUE); + writeBytes(buf); + } else { + byte[] buf = value.getBytes(StandardCharsets.UTF_8); + writeVarInt(value.length()); + writeBytes(buf); + } + } +} diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/State.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/State.java new file mode 100644 index 0000000..f4d4da2 --- /dev/null +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/State.java @@ -0,0 +1,61 @@ +/* + * DmitriyMX + * 2018-06-08 + */ +package mc.core.network.proto_1_12_2; + +import com.google.common.collect.BiMap; +import com.google.common.collect.ImmutableBiMap; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import mc.core.network.CSPacket; +import mc.core.network.SCPacket; +import mc.core.network.proto_1_12_2.packets.HandshakePacket; +import mc.core.network.proto_1_12_2.packets.PingPacket; +import mc.core.network.proto_1_12_2.packets.StatusRequestPacket; +import mc.core.network.proto_1_12_2.packets.StatusResponsePacket; + +@Slf4j +@RequiredArgsConstructor +public enum State { + UNKNOWN(-1, null, null), + HANDSHAKE(0, + ImmutableBiMap.>builder() + .put(0, HandshakePacket.class) + .build(), + null + ), + STATUS(1, + ImmutableBiMap.>builder() + .put(0, StatusRequestPacket.class) + .put(1, PingPacket.class) + .build(), + ImmutableBiMap., Integer>builder() + .put(StatusResponsePacket.class, 0) + .put(PingPacket.class, 1) + .build() + ); + + public static State valueOf(int id) { + if (id == 0) return HANDSHAKE; + else if (id == 1) return STATUS; + else { + log.warn("Unknown state: {}", id); + return UNKNOWN; + } + } + + @Getter + private final int id; + private final BiMap> clientSidePacketsMap; + private final BiMap, Integer> serverSidePacketsMap; + + public Class getClientSidePacket(int id) { + return clientSidePacketsMap.get(id); + } + + public Integer getServerSidePacket(Class clazz) { + return serverSidePacketsMap.get(clazz); + } +} diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/HandshakePacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/HandshakePacket.java new file mode 100644 index 0000000..8933818 --- /dev/null +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/HandshakePacket.java @@ -0,0 +1,30 @@ +/* + * DmitriyMX + * 2018-06-10 + */ +package mc.core.network.proto_1_12_2.packets; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import mc.core.network.CSPacket; +import mc.core.network.NetStream; +import mc.core.network.proto_1_12_2.State; + +@NoArgsConstructor +@Getter +@ToString +public class HandshakePacket implements CSPacket { + private int protocolVersion; + private String address; + private int serverPort; + private State nextState; + + @Override + public void readSelf(NetStream netStream) { + this.protocolVersion = netStream.readVarInt(); + this.address = netStream.readString(); + this.serverPort = netStream.readUnsignedShort(); + this.nextState = State.valueOf(netStream.readVarInt()); + } +} diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PingPacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PingPacket.java new file mode 100644 index 0000000..7d709fd --- /dev/null +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PingPacket.java @@ -0,0 +1,28 @@ +/* + * DmitriyMX + * 2018-06-10 + */ +package mc.core.network.proto_1_12_2.packets; + +import lombok.ToString; +import mc.core.network.CSPacket; +import mc.core.network.NetStream; +import mc.core.network.SCPacket; +import mc.core.network.proto_1_12_2.ByteArrayOutputNetStream; + +@ToString +public class PingPacket implements CSPacket, SCPacket { + private long payload; + + @Override + public void readSelf(NetStream netStream) { + this.payload = netStream.readLong(); + } + + @Override + public byte[] toByteArray() { + ByteArrayOutputNetStream netStream = new ByteArrayOutputNetStream(); + netStream.writeLong(payload); + return netStream.toByteArray(); + } +} diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/StatusRequestPacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/StatusRequestPacket.java new file mode 100644 index 0000000..0d3cb2f --- /dev/null +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/StatusRequestPacket.java @@ -0,0 +1,16 @@ +/* + * DmitriyMX + * 2018-06-10 + */ +package mc.core.network.proto_1_12_2.packets; + +import lombok.ToString; +import mc.core.network.CSPacket; +import mc.core.network.NetStream; + +@ToString +public class StatusRequestPacket implements CSPacket { + @Override + public void readSelf(NetStream netStream) { + } +} diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/StatusResponsePacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/StatusResponsePacket.java new file mode 100644 index 0000000..a649d48 --- /dev/null +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/StatusResponsePacket.java @@ -0,0 +1,54 @@ +/* + * DmitriyMX + * 2018-06-10 + */ +package mc.core.network.proto_1_12_2.packets; + +import com.google.gson.JsonObject; +import lombok.Setter; +import lombok.ToString; +import mc.core.network.SCPacket; +import mc.core.network.proto_1_12_2.ByteArrayOutputNetStream; + +@Setter +@ToString +public class StatusResponsePacket implements SCPacket { + private static final JsonObject versionObj; + + static { + versionObj = new JsonObject(); + versionObj.addProperty("name", "1.12.2"); + versionObj.addProperty("protocol", 340); + } + + private int maxOnline; + private int online; + private String description; + private byte[] faviconBase64; + + @Override + public byte[] toByteArray() { + ByteArrayOutputNetStream netStream = new ByteArrayOutputNetStream(); + + JsonObject playersObj = new JsonObject(); + playersObj.addProperty("max", maxOnline); + playersObj.addProperty("online", online); + + JsonObject descriptionObj = new JsonObject(); + descriptionObj.addProperty("text", description); + + JsonObject rootObj = new JsonObject(); + rootObj.add("version", versionObj); + rootObj.add("players", playersObj); + rootObj.add("description", descriptionObj); + + if (faviconBase64 != null && faviconBase64.length > 0) { + rootObj.addProperty("favicon", + "data:image/png;base64," + new String(faviconBase64) + ); + } + + netStream.writeString(rootObj.toString()); + return netStream.toByteArray(); + } +} diff --git a/proto_1.12.2_netty/build.gradle b/proto_1.12.2_netty/build.gradle new file mode 100644 index 0000000..9704176 --- /dev/null +++ b/proto_1.12.2_netty/build.gradle @@ -0,0 +1,14 @@ +group 'mc' +version '1.0-SNAPSHOT' + +ext { + netty_version = '4.1.22.Final' +} + +dependencies { + /* Protocol 1.12.2 */ + compile_excludeCopy project(':proto_1.12.2') + + /* Netty */ + compile (group: 'io.netty', name: 'netty-all', version: netty_version) +} diff --git a/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/NettyServer.java b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/NettyServer.java new file mode 100644 index 0000000..7e777c2 --- /dev/null +++ b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/NettyServer.java @@ -0,0 +1,81 @@ +/* + * DmitriyMX + * 2018-06-10 + */ +package mc.core.network.proto_1_12_2.netty; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelInitializer; +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.util.AttributeKey; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import mc.core.network.Server; +import mc.core.network.StartServerException; +import mc.core.network.proto_1_12_2.State; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; + +import java.util.Map; + +@Slf4j +public class NettyServer implements Server { + static final AttributeKey ATTR_STATE = AttributeKey.newInstance("ATTR_STATE"); + + @Autowired + private ApplicationContext applicationContext; + @Setter + private String host; + @Setter + private int port; + @Setter + private int workerGroupCount = 0; + private EventLoopGroup bossGroup, workerGroup; + + private ChannelInitializer buildChannelInitializer() { + return new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel socketChannel) { + Map beans = applicationContext.getBeansOfType(ChannelHandler.class); + beans.forEach(socketChannel.pipeline()::addLast); + } + }; + } + + private ServerBootstrap buildServerBootstrap() { + ServerBootstrap bootstrap = new ServerBootstrap(); + + bootstrap.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .childHandler(buildChannelInitializer()); + + return bootstrap; + } + + @Override + public void start() throws StartServerException { + log.info("Use protocol 1.7.10"); + bossGroup = new NioEventLoopGroup(1); + workerGroup = new NioEventLoopGroup(workerGroupCount); + + ServerBootstrap serverBootstrap = buildServerBootstrap(); + + log.info("Start server: {}:{}", host, port); + try { + serverBootstrap.bind(host, port).sync().channel().closeFuture().sync(); + } catch (InterruptedException e) { + throw new StartServerException(e); + } + } + + @Override + public void stop() { + log.info("Server shutdown"); + workerGroup.shutdownGracefully(); + bossGroup.shutdownGracefully(); + } +} diff --git a/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/PacketDecoder.java b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/PacketDecoder.java new file mode 100644 index 0000000..fb996a4 --- /dev/null +++ b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/PacketDecoder.java @@ -0,0 +1,60 @@ +/* + * DmitriyMX + * 2018-06-10 + */ +package mc.core.network.proto_1_12_2.netty; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; +import lombok.extern.slf4j.Slf4j; +import mc.core.network.CSPacket; +import mc.core.network.NetStream; +import mc.core.network.proto_1_12_2.State; +import mc.core.network.proto_1_12_2.netty.wrappers.WrapperNetStream; + +import java.util.List; + +import static mc.core.network.proto_1_12_2.netty.NettyServer.ATTR_STATE; + +@Slf4j +public class PacketDecoder extends ByteToMessageDecoder { + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + ctx.channel().attr(ATTR_STATE).set(State.HANDSHAKE); + ctx.fireChannelActive(); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + ctx.channel().attr(ATTR_STATE).set(null); + ctx.fireChannelInactive(); + } + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + log.debug("ByteBuf readableBytes: {}", in.readableBytes()); + + State state = ctx.channel().attr(ATTR_STATE).get(); + NetStream netStream = new WrapperNetStream(in); + + int packetSize = netStream.readVarInt(); + log.debug("Packet size: {}", packetSize); + int rb = in.readableBytes(); + + int packetId = netStream.readVarInt(); + log.debug("Packet id: {}", packetId); + rb = rb - in.readableBytes(); + + Class packetClass = state.getClientSidePacket(packetId); + if (packetClass == null) { + log.warn("Unknown packet: {}:{}", state.name(), packetId); + in.skipBytes(packetSize - rb); + } else { + CSPacket packet = packetClass.newInstance(); + packet.readSelf(netStream); + log.debug("Known packet: {}:{}", state.name(), packet.toString()); + out.add(packet); + } + } +} diff --git a/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/PacketEncoder.java b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/PacketEncoder.java new file mode 100644 index 0000000..c86c4d7 --- /dev/null +++ b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/PacketEncoder.java @@ -0,0 +1,48 @@ +/* + * DmitriyMX + * 2018-06-10 + */ +package mc.core.network.proto_1_12_2.netty; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToByteEncoder; +import lombok.extern.slf4j.Slf4j; +import mc.core.network.NetStream; +import mc.core.network.SCPacket; +import mc.core.network.proto_1_12_2.State; +import mc.core.network.proto_1_12_2.netty.wrappers.WrapperNetStream; + +import static mc.core.network.proto_1_12_2.netty.NettyServer.ATTR_STATE; + +@Slf4j +public class PacketEncoder extends MessageToByteEncoder { + private static int sizeVarInt(final int value) { + byte size = 0; + int v = value; + + do { + v >>>= 7; + size++; + } while (v != 0); + + return size; + } + + @Override + protected void encode(ChannelHandlerContext ctx, SCPacket packet, ByteBuf out) throws Exception { + State state = ctx.channel().attr(ATTR_STATE).get(); + Integer id = state.getServerSidePacket(packet.getClass()); + if (id == null) { + log.error("Not defined ID packet: {}:{}", state.name(), packet.getClass()); + return; + } + + byte[] bytes = packet.toByteArray(); + NetStream netStream = new WrapperNetStream(out); + + netStream.writeVarInt(bytes.length + sizeVarInt(id)); + netStream.writeVarInt(id); + netStream.writeBytes(bytes); + } +} diff --git a/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/PacketHandler.java b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/PacketHandler.java new file mode 100644 index 0000000..29b26b0 --- /dev/null +++ b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/PacketHandler.java @@ -0,0 +1,91 @@ +/* + * DmitriyMX + * 2018-06-10 + */ +package mc.core.network.proto_1_12_2.netty; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.util.AttributeKey; +import lombok.extern.slf4j.Slf4j; +import mc.core.Config; +import mc.core.chat.ChatProcessor; +import mc.core.network.CSPacket; +import mc.core.network.proto_1_12_2.State; +import mc.core.network.proto_1_12_2.packets.HandshakePacket; +import mc.core.network.proto_1_12_2.packets.PingPacket; +import mc.core.network.proto_1_12_2.packets.StatusRequestPacket; +import mc.core.network.proto_1_12_2.packets.StatusResponsePacket; +import mc.core.player.Player; +import mc.core.player.PlayerManager; +import mc.core.world.World; +import org.springframework.beans.factory.annotation.Autowired; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Optional; + +import static mc.core.network.proto_1_12_2.netty.NettyServer.ATTR_STATE; + +@Slf4j +public class PacketHandler extends SimpleChannelInboundHandler { + private static final AttributeKey ATTR_PLAYER = AttributeKey.newInstance("ATTR_PLAYER"); + + @Autowired + private Config config; + @Autowired + private PlayerManager playerManager; + @Autowired + private World world; + @Autowired + private ChatProcessor chatProcessor; + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + super.channelInactive(ctx); + Player player = ctx.channel().attr(ATTR_PLAYER).get(); + if (player != null) { + playerManager.leftServer(player); + player.setChannel(null); + } + ctx.channel().attr(ATTR_PLAYER).set(null); + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, CSPacket packet) throws Exception { + Optional optionalMethod = Arrays.stream(this.getClass().getDeclaredMethods()) + .filter(method -> method.getName().equals("on" + packet.getClass().getSimpleName().replace("Packet", "")) + && method.getParameterCount() == 2 + && method.getParameterTypes()[0].isAssignableFrom(Channel.class) + && method.getParameterTypes()[1].isAssignableFrom(packet.getClass())) + .findFirst(); + + if (optionalMethod.isPresent()) { + Method method = optionalMethod.get(); + method.invoke(this, ctx.channel(), packet); + } + } + + private void onHandshake(Channel channel, HandshakePacket packet) { + if (packet.getNextState().equals(State.UNKNOWN)) return; + channel.attr(ATTR_STATE).set(packet.getNextState()); + } + + private void onStatusRequest(Channel channel, StatusRequestPacket packet) { + if (!channel.attr(ATTR_STATE).get().equals(State.STATUS)) return; + + StatusResponsePacket responsePacket = new StatusResponsePacket(); + responsePacket.setMaxOnline(config.getMaxPlayers()); + responsePacket.setDescription(config.getDescriptionServer()); + responsePacket.setFaviconBase64(config.getFaviconBase64()); + responsePacket.setOnline(playerManager.getCountOnlinePlayers()); + + channel.writeAndFlush(responsePacket); + } + + private void onPing(Channel channel, PingPacket packet) { + if (!channel.attr(ATTR_STATE).get().equals(State.STATUS)) return; + channel.writeAndFlush(packet); + } +} diff --git a/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/wrappers/WrapperNetStream.java b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/wrappers/WrapperNetStream.java new file mode 100644 index 0000000..d782e4b --- /dev/null +++ b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/wrappers/WrapperNetStream.java @@ -0,0 +1,111 @@ +/* + * DmitriyMX + * 2018-04-08 + */ +package mc.core.network.proto_1_12_2.netty.wrappers; + +import io.netty.buffer.ByteBuf; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import mc.core.network.proto_1_12_2.NetStream_p340; + +@Slf4j +@RequiredArgsConstructor +public class WrapperNetStream extends NetStream_p340 { + private final ByteBuf byteBuf; + + @Override + public boolean readBoolean() { + return byteBuf.readBoolean(); + } + + @Override + public byte readByte() { + return byteBuf.readByte(); + } + + @Override + public void readBytes(byte[] buffer) { + byteBuf.readBytes(buffer); + } + + @Override + public int readUnsignedByte() { + return byteBuf.readUnsignedByte(); + } + + @Override + public int readUnsignedShort() { + return byteBuf.readUnsignedShort(); + } + + @Override + public short readShort() { + return byteBuf.readShort(); + } + + @Override + public int readInt() { + return byteBuf.readInt(); + } + + @Override + public long readLong() { + return byteBuf.readLong(); + } + + @Override + public float readFloat() { + return byteBuf.readFloat(); + } + + @Override + public double readDouble() { + return byteBuf.readDouble(); + } + + @Override + public void writeBoolean(boolean value) { + byteBuf.writeBoolean(value); + } + + @Override + public void writeByte(int value) { + byteBuf.writeByte(value); + } + + @Override + public void writeBytes(byte[] buffer) { + byteBuf.writeBytes(buffer); + } + + @Override + public void writeShort(int value) { + byteBuf.writeShort(value); + } + + @Override + public void writeInt(int value) { + byteBuf.writeInt(value); + } + + @Override + public void writeLong(long value) { + byteBuf.writeLong(value); + } + + @Override + public void writeFloat(float value) { + byteBuf.writeFloat(value); + } + + @Override + public void writeDouble(double value) { + byteBuf.writeDouble(value); + } + + @Override + public void skipBytes(int count) { + byteBuf.skipBytes(count); + } +} diff --git a/settings.gradle b/settings.gradle index 14016e6..c798c0e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,3 +5,5 @@ include('proto125') // Protocol 1.2.5 include('proto125_netty') // Protocol 1.2.5 (Netty impl.) include('flat_world') include('vanilla_commands') +include('proto_1.12.2') // Protocol 1.12.2 +include('proto_1.12.2_netty') // Protocol 1.12.2 (Netty impl.)