Archived
0

Ping server

This commit is contained in:
2018-06-10 20:04:33 +03:00
parent 4a5f5cf721
commit 796076c97c
18 changed files with 825 additions and 1 deletions

View File

@@ -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)
}

View File

@@ -0,0 +1,81 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 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<State> 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<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) {
Map<String, ChannelHandler> 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();
}
}

View File

@@ -0,0 +1,60 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 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<Object> 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<? extends CSPacket> 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);
}
}
}

View File

@@ -0,0 +1,48 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 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<SCPacket> {
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);
}
}

View File

@@ -0,0 +1,91 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 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<CSPacket> {
private static final AttributeKey<Player> 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<Method> 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);
}
}

View File

@@ -0,0 +1,111 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 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);
}
}