Conflicts:
	src/main/java/net/minestom/server/network/netty/NettyServer.java
	src/main/java/net/minestom/server/network/packet/client/login/LoginStartPacket.java
	src/main/java/net/minestom/server/network/player/FakePlayerConnection.java
	src/main/java/net/minestom/server/network/player/NettyPlayerConnection.java
	src/main/java/net/minestom/server/network/player/PlayerConnection.java
This commit is contained in:
Eoghanmc22 2020-06-28 18:06:36 -04:00
commit 1f56bc10fc
23 changed files with 571 additions and 178 deletions

View File

@ -18,8 +18,9 @@ repositories {
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
// https://mvnrepository.com/artifact/io.netty/netty-all
api group: 'io.netty', name: 'netty-all', version: '4.1.50.Final'
api 'io.netty:netty-handler:4.1.45.Final'
api 'io.netty:netty-codec:4.1.45.Final'
implementation 'io.netty:netty-transport-native-epoll:4.1.45.Final:linux-x86_64'
api 'com.github.jhg023:Pbbl:1.0.2'

View File

@ -72,6 +72,7 @@ public class MinecraftServer {
// Config
public static final int CHUNK_VIEW_DISTANCE = 10;
public static final int ENTITY_VIEW_DISTANCE = 5;
public static final int COMPRESSION_THRESHOLD = 256;
// Can be modified at performance cost when decreased
private static final int MS_TO_SEC = 1000;
public static final int TICK_MS = MS_TO_SEC / 20;

View File

@ -2,8 +2,10 @@ package net.minestom.server.network;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.SocketChannel;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player;
import net.minestom.server.network.netty.packet.InboundPacket;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.client.ClientPlayPacket;
import net.minestom.server.network.packet.client.ClientPreplayPacket;
@ -40,19 +42,22 @@ public class PacketProcessor {
private List<Integer> printBlackList = Arrays.asList(17, 18, 19);
public void process(ChannelHandlerContext channel, ByteBuf buffer, int id, int offset) {
PlayerConnection playerConnection =
connectionPlayerConnectionMap.computeIfAbsent(channel, c -> new NettyPlayerConnection(channel));
public void process(ChannelHandlerContext channel, InboundPacket packet) {
PlayerConnection playerConnection = connectionPlayerConnectionMap.computeIfAbsent(
channel, c -> new NettyPlayerConnection((SocketChannel) channel.channel())
);
ConnectionState connectionState = playerConnection.getConnectionState();
//if (!printBlackList.contains(id)) {
//System.out.println("RECEIVED ID: 0x" + Integer.toHexString(id) + " State: " + connectionState);
//}
PacketReader packetReader = new PacketReader(buffer);
PacketReader packetReader = new PacketReader(packet.body);
if (connectionState == ConnectionState.UNKNOWN) {
// Should be handshake packet
if (id == 0) {
if (packet.packetId == 0) {
HandshakePacket handshakePacket = new HandshakePacket();
handshakePacket.read(packetReader);
handshakePacket.process(playerConnection, connectionManager);
@ -63,26 +68,23 @@ public class PacketProcessor {
switch (connectionState) {
case PLAY:
Player player = playerConnection.getPlayer();
ClientPlayPacket playPacket = (ClientPlayPacket) playPacketsHandler.getPacketInstance(id);
ClientPlayPacket playPacket = (ClientPlayPacket) playPacketsHandler.getPacketInstance(packet.packetId);
playPacket.read(packetReader);
//System.out.println("play");
player.addPacketToQueue(playPacket);
break;
case LOGIN:
ClientPreplayPacket loginPacket = (ClientPreplayPacket) loginPacketsHandler.getPacketInstance(id);
ClientPreplayPacket loginPacket = (ClientPreplayPacket) loginPacketsHandler.getPacketInstance(packet.packetId);
loginPacket.read(packetReader);
//System.out.println("login");
loginPacket.process(playerConnection, connectionManager);
break;
case STATUS:
ClientPreplayPacket statusPacket = (ClientPreplayPacket) statusPacketsHandler.getPacketInstance(id);
ClientPreplayPacket statusPacket = (ClientPreplayPacket) statusPacketsHandler.getPacketInstance(packet.packetId);
statusPacket.read(packetReader);
statusPacket.process(playerConnection, connectionManager);
break;
case UNKNOWN:
// Ignore packet (unexpected)
break;
}
}

View File

@ -1,30 +1,73 @@
package net.minestom.server.network.netty;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.*;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.ServerSocketChannel;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import net.minestom.server.network.PacketProcessor;
import net.minestom.server.network.netty.channel.ClientChannel;
import net.minestom.server.network.netty.channel.NettyDecoder;
import net.minestom.server.network.netty.codec.LegacyPingHandler;
import net.minestom.server.network.netty.codec.PacketDecoder;
import net.minestom.server.network.netty.codec.PacketEncoder;
import net.minestom.server.network.netty.codec.PacketFramer;
import java.net.InetSocketAddress;
public class NettyServer {
private PacketProcessor packetProcessor;
private EventLoopGroup group;
private final EventLoopGroup boss, worker;
private final ServerBootstrap bootstrap;
private ServerSocketChannel serverChannel;
private String address;
private int port;
public NettyServer(PacketProcessor packetProcessor) {
this.packetProcessor = packetProcessor;
this.group = new NioEventLoopGroup();
Class<? extends ServerChannel> channel;
if (Epoll.isAvailable()) {
boss = new EpollEventLoopGroup(2);
worker = new EpollEventLoopGroup();
channel = EpollServerSocketChannel.class;
} else {
boss = new NioEventLoopGroup(2);
worker = new EpollEventLoopGroup();
channel = NioServerSocketChannel.class;
}
bootstrap = new ServerBootstrap();
bootstrap.group(boss, worker);
bootstrap.channel(channel);
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel ch) {
ChannelConfig config = ch.config();
config.setOption(ChannelOption.TCP_NODELAY, true);
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("legacy-ping", new LegacyPingHandler());
// Adds packetLength at start | Reads framed bytebuf
pipeline.addLast("framer", new PacketFramer());
// Reads bytebuf and creating inbound packet
pipeline.addLast("decoder", new PacketDecoder());
// Writes packet to bytebuf
pipeline.addLast("encoder", new PacketEncoder());
pipeline.addLast("handler", new ClientChannel(packetProcessor));
}
});
}
public void start(String address, int port) {
@ -32,27 +75,15 @@ public class NettyServer {
this.port = port;
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(group);
serverBootstrap.channel(NioServerSocketChannel.class);
serverBootstrap.localAddress(new InetSocketAddress(address, port));
ChannelFuture cf = bootstrap.bind(new InetSocketAddress(address, port)).sync();
serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel socketChannel) {
socketChannel.pipeline().addLast("decoder", new NettyDecoder());
socketChannel.pipeline().addLast("encoder", new ClientChannel(packetProcessor));
}
});
ChannelFuture channelFuture = serverBootstrap.bind().sync();
channelFuture.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
group.shutdownGracefully().sync();
} catch (InterruptedException e) {
e.printStackTrace();
if (!cf.isSuccess()) {
throw new IllegalStateException("Unable to bind server at " + address + ":" + port);
}
serverChannel = (ServerSocketChannel) cf.channel();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
@ -65,10 +96,9 @@ public class NettyServer {
}
public void stop() {
try {
group.shutdownGracefully().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}
serverChannel.close();
worker.shutdownGracefully();
boss.shutdownGracefully();
}
}

View File

@ -1,22 +1,18 @@
package net.minestom.server.network.netty.channel;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.SimpleChannelInboundHandler;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.PacketProcessor;
import net.minestom.server.network.netty.packet.PacketHandler;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.client.status.LegacyServerListPingPacket;
import net.minestom.server.network.netty.packet.InboundPacket;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.utils.Utils;
public class ClientChannel extends ChannelInboundHandlerAdapter {
public class ClientChannel extends SimpleChannelInboundHandler<InboundPacket> {
private ConnectionManager connectionManager = MinecraftServer.getConnectionManager();
private PacketProcessor packetProcessor;
private final ConnectionManager connectionManager = MinecraftServer.getConnectionManager();
private final PacketProcessor packetProcessor;
public ClientChannel(PacketProcessor packetProcessor) {
this.packetProcessor = packetProcessor;
@ -28,26 +24,20 @@ public class ClientChannel extends ChannelInboundHandlerAdapter {
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object obj) {
PacketHandler packetHandler = (PacketHandler) obj;
public void channelRead0(ChannelHandlerContext ctx, InboundPacket packet) {
try {
packetProcessor.process(ctx, packet);
} finally {
int availableBytes = packet.body.readableBytes();
int packetLength = packetHandler.length;
ByteBuf buffer = packetHandler.buffer;
if (availableBytes > 0) {
// TODO log4j2
System.out.println("Packet 0x" + Integer.toHexString(packet.packetId)
+ " not fully read (" + availableBytes + " bytes left)");
if (packetLength == 0xFE) { // Legacy server ping
LegacyServerListPingPacket legacyServerListPingPacket = new LegacyServerListPingPacket();
legacyServerListPingPacket.read(new PacketReader(buffer));
legacyServerListPingPacket.process(null, null);
return;
packet.body.skipBytes(availableBytes);
}
}
final int varIntLength = Utils.lengthVarInt(packetLength);
int packetId = Utils.readVarInt(buffer);
int offset = varIntLength + Utils.lengthVarInt(packetId);
packetProcessor.process(ctx, buffer, packetId, offset);
buffer.release();
}
@Override

View File

@ -1,51 +0,0 @@
package net.minestom.server.network.netty.channel;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import net.minestom.server.network.netty.packet.PacketHandler;
import net.minestom.server.utils.Utils;
import java.util.List;
public class NettyDecoder extends ByteToMessageDecoder {
private int bytesToRead;
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) {
// Fix cut packet
if (bytesToRead != 0) {
int readable = buffer.readableBytes();
if (readable >= bytesToRead) {
PacketHandler packetHandler = new PacketHandler();
packetHandler.length = bytesToRead;
packetHandler.buffer = buffer.readBytes(bytesToRead);
out.add(packetHandler);
bytesToRead = 0;
}
return;
}
int packetLength = Utils.readVarInt(buffer);
PacketHandler packetHandler = new PacketHandler();
packetHandler.length = packetLength;
if (packetLength == 0xFE) { // Legacy server ping
packetHandler.buffer = buffer.readBytes(2);
} else {
int readable = buffer.readableBytes();
if (readable < packetLength) {
// Wait for bytes to arrive
bytesToRead = packetLength;
return;
} else {
// There are enough bytes, read them
packetHandler.buffer = buffer.readBytes(packetLength);
bytesToRead = 0;
}
}
out.add(packetHandler);
}
}

View File

@ -0,0 +1,187 @@
package net.minestom.server.network.netty.codec;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.nio.charset.StandardCharsets;
// Copied from original minecraft :(
public class LegacyPingHandler extends ChannelInboundHandlerAdapter {
private ByteBuf buf;
@Override
public void channelRead(ChannelHandlerContext ctx, Object object) throws Exception {
ByteBuf buf = (ByteBuf) object;
if (this.buf != null) {
try {
readLegacy1_6(ctx, buf);
} finally {
buf.release();
}
return;
}
buf.markReaderIndex();
boolean flag = true;
try {
if (buf.readUnsignedByte() == 0xFE) {
int length = buf.readableBytes();
switch (length) {
case 0:
this.writeResponse(ctx, this.createResponse(formatResponse(-2)));
break;
case 1:
if (buf.readUnsignedByte() != 1) {
return;
}
this.writeResponse(ctx, this.createResponse(formatResponse(-1)));
break;
default:
if (buf.readUnsignedByte() != 0x01 || buf.readUnsignedByte() != 0xFA) return;
readLegacy1_6(ctx, buf);
break;
}
buf.release();
flag = false;
}
} finally {
if (flag) {
buf.resetReaderIndex();
ctx.channel().pipeline().remove("legacy-ping");
ctx.fireChannelRead(object);
}
}
}
private static String readLegacyString(ByteBuf buf) {
int size = buf.readShort() * Character.BYTES;
if (!buf.isReadable(size)) {
return null;
}
String result = buf.toString(buf.readerIndex(), size, StandardCharsets.UTF_16BE);
buf.skipBytes(size);
return result;
}
private void readLegacy1_6(ChannelHandlerContext ctx, ByteBuf part) {
ByteBuf buf = this.buf;
if (buf == null) {
this.buf = buf = ctx.alloc().buffer();
buf.markReaderIndex();
} else {
buf.resetReaderIndex();
}
buf.writeBytes(part);
if (!buf.isReadable(Short.BYTES + Short.BYTES + Byte.BYTES + Short.BYTES + Integer.BYTES)) {
return;
}
String s = readLegacyString(buf);
if (s == null) {
return;
}
if (!s.equals("MC|PingHost")) {
removeHandler(ctx);
return;
}
if (!buf.isReadable(Short.BYTES) || !buf.isReadable(buf.readShort())) {
return;
}
int protocolVersion = buf.readByte();
if (readLegacyString(buf) == null) {
removeHandler(ctx);
return;
}
buf.skipBytes(4); // port
if (buf.isReadable()) {
removeHandler(ctx);
return;
}
buf.release();
this.buf = null;
this.writeResponse(ctx, this.createResponse(formatResponse(protocolVersion)));
}
private String formatResponse(int playerProtocol) {
// todo server motd, online and slots
final String motd = "Minestom";
final String version = "1.15.2";
final int online = 0;
final int max = 1;
final int protocol = 578; // 1.15.2
if (playerProtocol == -2) {
return String.format(
"%s\u00a7%d\u00a7%d",
motd, online, max
);
}
return String.format(
"\u00a71\u0000%d\u0000%s\u0000%s\u0000%d\u0000%d",
protocol, version, motd, online, max
);
}
private void removeHandler(ChannelHandlerContext ctx) {
ByteBuf buf = this.buf;
this.buf = null;
buf.resetReaderIndex();
ctx.pipeline().remove(this);
ctx.fireChannelRead(buf);
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) {
if (this.buf != null) {
this.buf.release();
this.buf = null;
}
}
private void writeResponse(ChannelHandlerContext ctx, ByteBuf buf) {
ctx.pipeline().firstContext().writeAndFlush(buf).addListener(ChannelFutureListener.CLOSE);
}
private ByteBuf createResponse(String s) {
ByteBuf response = Unpooled.buffer();
response.writeByte(255);
char[] chars = s.toCharArray();
response.writeShort(chars.length);
for (char c : chars) {
response.writeChar(c);
}
return response;
}
}

View File

@ -0,0 +1,101 @@
/*
* Copyright (2020) [artem]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.minestom.server.network.netty.codec;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;
import io.netty.handler.codec.DecoderException;
import net.minestom.server.utils.Utils;
import java.util.List;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
// TODO Optimize
public class PacketCompressor extends ByteToMessageCodec<ByteBuf> {
private final byte[] buffer = new byte[8192];
private final int threshold;
private final Inflater inflater;
private final Deflater deflater;
public PacketCompressor(int threshold) {
this.inflater = new Inflater();
this.deflater = new Deflater();
this.threshold = threshold;
}
@Override
protected void encode(ChannelHandlerContext ctx, ByteBuf from, ByteBuf to) {
int i = from.readableBytes();
if (i < this.threshold) {
Utils.writeVarIntBuf(to, 0);
to.writeBytes(from);
} else {
byte[] abyte = new byte[i];
from.readBytes(abyte);
Utils.writeVarIntBuf(to, abyte.length);
this.deflater.setInput(abyte, 0, i);
this.deflater.finish();
while (!this.deflater.finished()) {
int j = this.deflater.deflate(this.buffer);
to.writeBytes(this.buffer, 0, j);
}
this.deflater.reset();
}
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> out) throws Exception {
if (buf.readableBytes() != 0) {
int i = Utils.readVarInt(buf);
if (i == 0) {
out.add(buf.readRetainedSlice(buf.readableBytes()));
} else {
if (i < this.threshold) {
throw new DecoderException("Badly compressed packet - size of " + i + " is below server threshold of " + this.threshold);
}
if (i > 2097152) {
throw new DecoderException("Badly compressed packet - size of " + i + " is larger than protocol maximum of 2097152");
}
byte[] abyte = new byte[buf.readableBytes()];
buf.readBytes(abyte);
this.inflater.setInput(abyte);
byte[] abyte1 = new byte[i];
this.inflater.inflate(abyte1);
out.add(Unpooled.wrappedBuffer(abyte1));
this.inflater.reset();
}
}
}
}

View File

@ -0,0 +1,19 @@
package net.minestom.server.network.netty.codec;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import net.minestom.server.network.netty.packet.InboundPacket;
import net.minestom.server.utils.Utils;
import java.util.List;
public class PacketDecoder extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> list) throws Exception {
if (buf.readableBytes() > 0) {
list.add(new InboundPacket(Utils.readVarInt(buf), buf));
}
}
}

View File

@ -0,0 +1,16 @@
package net.minestom.server.network.netty.codec;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.utils.PacketUtils;
public class PacketEncoder extends MessageToByteEncoder<ServerPacket> {
@Override
protected void encode(ChannelHandlerContext ctx, ServerPacket packet, ByteBuf buf) throws Exception {
PacketUtils.writePacket(buf, packet);
}
}

View File

@ -0,0 +1,57 @@
package net.minestom.server.network.netty.codec;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;
import io.netty.handler.codec.CorruptedFrameException;
import net.minestom.server.utils.Utils;
import java.util.List;
public class PacketFramer extends ByteToMessageCodec<ByteBuf> {
@Override
protected void encode(ChannelHandlerContext ctx, ByteBuf from, ByteBuf to) {
int packetSize = from.readableBytes();
int headerSize = Utils.getVarIntSize(packetSize);
if (headerSize > 3) {
throw new IllegalStateException("Unable to fit " + headerSize + " into 3");
}
to.ensureWritable(packetSize + headerSize);
Utils.writeVarIntBuf(to, packetSize);
to.writeBytes(from, from.readerIndex(), packetSize);
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> out) {
buf.markReaderIndex();
for (int i = 0; i < 3; ++i) {
if (!buf.isReadable()) {
buf.resetReaderIndex();
return;
}
byte b = buf.readByte();
if (b >= 0) {
buf.resetReaderIndex();
int j = Utils.readVarInt(buf);
if (buf.readableBytes() < j) {
buf.resetReaderIndex();
return;
}
out.add(buf.readRetainedSlice(j));
return;
}
}
throw new CorruptedFrameException("length wider than 21-bit");
}
}

View File

@ -0,0 +1,15 @@
package net.minestom.server.network.netty.packet;
import io.netty.buffer.ByteBuf;
public class InboundPacket {
public final int packetId;
public final ByteBuf body;
public InboundPacket(int id, ByteBuf body) {
this.packetId = id;
this.body = body;
}
}

View File

@ -1,10 +0,0 @@
package net.minestom.server.network.netty.packet;
import io.netty.buffer.ByteBuf;
public class PacketHandler {
public int length;
public ByteBuf buffer;
}

View File

@ -9,6 +9,7 @@ import net.minestom.server.utils.Utils;
import java.util.UUID;
// TODO delete
public class PacketReader {
private ByteBuf buffer;

View File

@ -14,6 +14,7 @@ import java.nio.charset.StandardCharsets;
import java.util.UUID;
import java.util.function.Consumer;
// TODO delete
public class PacketWriter {
private ByteArrayOutputStream output = new ByteArrayOutputStream();

View File

@ -1,12 +1,14 @@
package net.minestom.server.network.packet.client.login;
import net.minestom.server.extras.MojangAuth;
import net.minestom.server.MinecraftServer;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.client.ClientPreplayPacket;
import net.minestom.server.network.packet.server.login.EncryptionRequestPacket;
import net.minestom.server.network.packet.server.login.LoginSuccessPacket;
import net.minestom.server.network.packet.server.login.SetCompressionPacket;
import net.minestom.server.network.player.PlayerConnection;
import java.util.UUID;
@ -26,8 +28,14 @@ public class LoginStartPacket implements ClientPreplayPacket {
} else {
UUID playerUuid = connectionManager.getPlayerConnectionUuid(connection, username);
LoginSuccessPacket successPacket = new LoginSuccessPacket(playerUuid, username);
connection.sendPacket(successPacket);
int threshold = MinecraftServer.COMPRESSION_THRESHOLD;
if (threshold > 0) {
connection.enableCompression(threshold);
}
LoginSuccessPacket successPacket = new LoginSuccessPacket(playerUuid, username);
connection.sendPacket(successPacket);
connection.setConnectionState(ConnectionState.PLAY);
connectionManager.createPlayer(playerUuid, username, connection);

View File

@ -0,0 +1,23 @@
package net.minestom.server.network.packet.server.login;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.network.packet.server.ServerPacket;
public class SetCompressionPacket implements ServerPacket {
public int threshold;
public SetCompressionPacket(int threshold) {
this.threshold = threshold;
}
@Override
public void write(PacketWriter writer) {
writer.writeVarInt(threshold);
}
@Override
public int getId() {
return 0x03;
}
}

View File

@ -12,6 +12,11 @@ import java.net.SocketAddress;
public class FakePlayerConnection extends PlayerConnection {
@Override
public void enableCompression(int threshold) {
throw new UnsupportedOperationException("FakePlayer cannot enable compression");
}
@Override
public void sendPacket(ByteBuf buffer, boolean copy) {
throw new UnsupportedOperationException("FakePlayer cannot read Bytebuf");
@ -19,7 +24,7 @@ public class FakePlayerConnection extends PlayerConnection {
@Override
public void writePacket(ByteBuf buffer, boolean copy) {
throw new UnsupportedOperationException("FakePlayer cannot read Bytebuf");
throw new UnsupportedOperationException("FakePlayer cannot write to Bytebuf");
}
@Override

View File

@ -1,13 +1,17 @@
package net.minestom.server.network.player;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import lombok.Getter;
import net.minestom.server.extras.mojangAuth.Decrypter;
import net.minestom.server.extras.mojangAuth.Encrypter;
import net.minestom.server.extras.mojangAuth.MojangCrypt;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import net.minestom.server.network.netty.codec.PacketCompressor;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.utils.PacketUtils;
import net.minestom.server.network.packet.server.login.SetCompressionPacket;
import javax.crypto.SecretKey;
import java.net.SocketAddress;
@ -18,12 +22,11 @@ import java.net.SocketAddress;
*/
public class NettyPlayerConnection extends PlayerConnection {
private ChannelHandlerContext channel;
private final SocketChannel channel;
@Getter
private boolean encrypted = false;
public NettyPlayerConnection(ChannelHandlerContext channel) {
public NettyPlayerConnection(SocketChannel channel) {
super();
this.channel = channel;
}
@ -35,12 +38,19 @@ public class NettyPlayerConnection extends PlayerConnection {
}
@Override
public void enableCompression(int threshold) {
sendPacket(new SetCompressionPacket(threshold));
channel.pipeline().addAfter("framer", "compressor", new PacketCompressor(threshold));
}
@Override
public void sendPacket(ByteBuf buffer, boolean copy) {
//System.out.println(getConnectionState() + " out");
if (encrypted) {
buffer = buffer.copy();
buffer.retain();
getChannel().writeAndFlush(buffer);
channel.writeAndFlush(buffer);
buffer.release();
} else {
buffer.retain();
@ -53,7 +63,7 @@ public class NettyPlayerConnection extends PlayerConnection {
if (encrypted) {
buffer = buffer.copy();
buffer.retain();
getChannel().write(buffer);
channel.write(buffer);
buffer.release();
} else {
buffer.retain();
@ -64,9 +74,8 @@ public class NettyPlayerConnection extends PlayerConnection {
@Override
public void sendPacket(ServerPacket serverPacket) {
//System.out.println(serverPacket.getClass().getName() + " out");
ByteBuf buffer = PacketUtils.writePacket(serverPacket);
sendPacket(buffer, false);
buffer.release();
//TODO check wat this does
channel.writeAndFlush(serverPacket);
}
@Override
@ -76,7 +85,7 @@ public class NettyPlayerConnection extends PlayerConnection {
@Override
public SocketAddress getRemoteAddress() {
return getChannel().channel().remoteAddress();
return getChannel().remoteAddress();
}
@Override
@ -84,7 +93,7 @@ public class NettyPlayerConnection extends PlayerConnection {
getChannel().close();
}
public ChannelHandlerContext getChannel() {
public Channel getChannel() {
return channel;
}

View File

@ -28,6 +28,7 @@ public abstract class PlayerConnection {
this.connectionState = ConnectionState.UNKNOWN;
}
public abstract void enableCompression(int threshold);
/**
*
* @param buffer The buffer to send.

View File

@ -7,27 +7,19 @@ import net.minestom.server.network.packet.server.ServerPacket;
public class PacketUtils {
public static ByteBuf writePacket(ServerPacket serverPacket) {
int id = serverPacket.getId();
PacketWriter packetWriter = new PacketWriter();
public static void writePacket(ByteBuf buf, ServerPacket packet) {
PacketWriter writer = new PacketWriter();
packetWriter.writeVarInt(id);
Utils.writeVarIntBuf(buf, packet.getId());
packet.write(writer);
buf.writeBytes(writer.toByteArray());
}
serverPacket.write(packetWriter);
public static ByteBuf writePacket(ServerPacket packet) {
ByteBuf buffer = Unpooled.buffer();
byte[] bytes = packetWriter.toByteArray();
int length = bytes.length;
writePacket(buffer, packet);
int varIntSize = Utils.lengthVarInt(length);
ByteBuf buffer = Unpooled.buffer(length + varIntSize);
Utils.writeVarIntBuf(buffer, length);
buffer.writeBytes(bytes);
//if(!(serverPacket instanceof ChunkDataPacket) && !(serverPacket instanceof PlayerListHeaderAndFooterPacket))
//System.out.println("WRITE PACKET: " + serverPacket.getClass().getSimpleName());
//Unpooled.copiedBuffer(buffer);
return buffer;
}

View File

@ -18,6 +18,14 @@ import java.util.*;
public class Utils {
public static int getVarIntSize(int input) {
return (input & 0xFFFFFF80) == 0
? 1 : (input & 0xFFFFC000) == 0
? 2 : (input & 0xFFE00000) == 0
? 3 : (input & 0xF0000000) == 0
? 4 : 5;
}
public static void writeVarIntBuf(ByteBuf buffer, int value) {
do {
byte temp = (byte) (value & 0b01111111);
@ -51,19 +59,6 @@ public class Utils {
} while (value != 0);
}
public static int lengthVarInt(int value) {
int i = 0;
do {
i++;
byte temp = (byte) (value & 0b01111111);
value >>>= 7;
if (value != 0) {
temp |= 0b10000000;
}
} while (value != 0);
return i;
}
public static int readVarInt(ByteBuf buffer) {
int numRead = 0;
int result = 0;

View File

@ -35,7 +35,7 @@ public class BufferWrapper {
public void putVarInt(int n) {
Utils.writeVarIntBuffer(this, n);
size += Utils.lengthVarInt(n);
size += Utils.getVarIntSize(n);
}
public void putBytes(byte[] bytes) {