diff --git a/src/main/java/net/minestom/server/network/player/NettyPlayerConnection.java b/src/main/java/net/minestom/server/network/player/NettyPlayerConnection.java index e5ef47e05..0a329b7ef 100644 --- a/src/main/java/net/minestom/server/network/player/NettyPlayerConnection.java +++ b/src/main/java/net/minestom/server/network/player/NettyPlayerConnection.java @@ -63,7 +63,6 @@ public class NettyPlayerConnection extends PlayerConnection { private UUID bungeeUuid; private PlayerSkin bungeeSkin; - private final Object tickBufferLock = new Object(); private final ByteBuffer tickBuffer = ByteBuffer.allocateDirect(Server.SOCKET_BUFFER_SIZE); private ByteBuffer cacheBuffer; @@ -170,8 +169,8 @@ public class NettyPlayerConnection extends PlayerConnection { Check.stateCondition(compressed, "Compression is already enabled!"); final int threshold = MinecraftServer.getCompressionThreshold(); Check.stateCondition(threshold == 0, "Compression cannot be enabled because the threshold is equal to 0"); - this.compressed = true; writeAndFlush(new SetCompressionPacket(threshold)); + this.compressed = true; } /** @@ -209,13 +208,15 @@ public class NettyPlayerConnection extends PlayerConnection { } public void writeAndFlush(@NotNull ServerPacket packet) { - attemptWrite(PacketUtils.createFramedPacket(packet)); - flush(); + synchronized (tickBuffer){ + PacketUtils.writeFramedPacket(tickBuffer, packet, compressed); + flush(); + } } public void attemptWrite(ByteBuffer buffer) { buffer.flip(); - synchronized (tickBufferLock) { + synchronized (tickBuffer) { try { this.tickBuffer.put(buffer); } catch (BufferOverflowException e) { @@ -233,14 +234,14 @@ public class NettyPlayerConnection extends PlayerConnection { } public void flush() { - synchronized (tickBufferLock) { + synchronized (tickBuffer) { this.tickBuffer.flip(); if (tickBuffer.remaining() == 0) { // Nothing to write return; } try { - channel.write(tickBuffer); + this.channel.write(tickBuffer); } catch (IOException e) { MinecraftServer.getExceptionManager().handleException(e); } diff --git a/src/main/java/net/minestom/server/utils/PacketUtils.java b/src/main/java/net/minestom/server/utils/PacketUtils.java index d3f000fbe..720db87bb 100644 --- a/src/main/java/net/minestom/server/utils/PacketUtils.java +++ b/src/main/java/net/minestom/server/utils/PacketUtils.java @@ -130,58 +130,45 @@ public final class PacketUtils { sendGroupedPacket(players, packet, null); } - /** - * Writes a {@link ServerPacket} into a {@link ByteBuffer}. - * - * @param buf the recipient of {@code packet} - * @param packet the packet to write into {@code buf} - */ - public static void writePacket(@NotNull ByteBuffer buf, @NotNull ServerPacket packet) { - Utils.writeVarInt(buf, packet.getId()); - BinaryWriter writer = new BinaryWriter(buf); - try { - packet.write(writer); - } catch (Exception e) { - MinecraftServer.getExceptionManager().handleException(e); - } - } - public static void writeFramedPacket(@NotNull ByteBuffer buffer, - @NotNull ServerPacket serverPacket) { - final int compressionThreshold = MinecraftServer.getCompressionThreshold(); - - // Index of the var-int containing the complete packet length - final int packetLengthIndex = Utils.writeEmptyVarIntHeader(buffer); - final int startIndex = buffer.position(); // Index where the content starts (after length) - if (compressionThreshold > 0) { - // Index of the uncompressed payload length - final int dataLengthIndex = Utils.writeEmptyVarIntHeader(buffer); - - // Write packet - final int contentIndex = buffer.position(); - writePacket(buffer, serverPacket); - final int packetSize = buffer.position() - contentIndex; - - final int uncompressedLength = packetSize >= compressionThreshold ? packetSize : 0; - Utils.writeVarIntHeader(buffer, dataLengthIndex, uncompressedLength); - if (uncompressedLength > 0) { - // Packet large enough, compress - ByteBuffer uncompressedCopy = buffer.duplicate().position(contentIndex).limit(contentIndex + packetSize); - buffer.position(contentIndex); - - var deflater = COMPRESSOR.get(); - deflater.setInput(uncompressedCopy); - deflater.finish(); - deflater.deflate(buffer); - deflater.reset(); - } - } else { - // No compression, write packet id + payload - writePacket(buffer, serverPacket); + @NotNull ServerPacket packet, + boolean compression) { + if (!compression) { + // Length + payload + final int lengthIndex = Utils.writeEmptyVarIntHeader(buffer); + Utils.writeVarInt(buffer, packet.getId()); + packet.write(new BinaryWriter(buffer)); + final int finalSize = buffer.position() - (lengthIndex + 3); + Utils.writeVarIntHeader(buffer, lengthIndex, finalSize); + return; + } + // Compressed format + final int compressedIndex = Utils.writeEmptyVarIntHeader(buffer); + final int uncompressedIndex = Utils.writeEmptyVarIntHeader(buffer); + final int contentStart = buffer.position(); + + Utils.writeVarInt(buffer, packet.getId()); + packet.write(new BinaryWriter(buffer)); + final int packetSize = buffer.position() - contentStart; + if (packetSize >= MinecraftServer.getCompressionThreshold()) { + // Packet large enough, compress + final int limitCache = buffer.limit(); + buffer.position(contentStart).limit(contentStart + packetSize); + var uncompressedCopy = ByteBuffer.allocate(packetSize).put(buffer); + buffer.position(contentStart).limit(limitCache); + + var deflater = COMPRESSOR.get(); + deflater.setInput(uncompressedCopy.flip()); + deflater.finish(); + deflater.deflate(buffer); + deflater.reset(); + + Utils.writeVarIntHeader(buffer, compressedIndex, (buffer.position() - contentStart) + 3); + Utils.writeVarIntHeader(buffer, uncompressedIndex, packetSize); + } else { + Utils.writeVarIntHeader(buffer, compressedIndex, packetSize + 3); + Utils.writeVarIntHeader(buffer, uncompressedIndex, 0); } - // Total length - final int totalPacketLength = buffer.position() - startIndex; - Utils.writeVarIntHeader(buffer, packetLengthIndex, totalPacketLength); } /** @@ -193,7 +180,7 @@ public final class PacketUtils { */ public static @NotNull ByteBuffer createFramedPacket(@NotNull ServerPacket serverPacket) { ByteBuffer packetBuf = ByteBuffer.allocate(2_000_000); - writeFramedPacket(packetBuf, serverPacket); + writeFramedPacket(packetBuf, serverPacket, MinecraftServer.getCompressionThreshold() > 0); return packetBuf; } }