mirror of
https://github.com/Minestom/Minestom.git
synced 2024-11-07 11:20:09 +01:00
Added GroupedPacketHandler to prevent rewriting the same packet multiple times
This commit is contained in:
parent
3455c77eb7
commit
4060f8d290
@ -16,10 +16,7 @@ import io.netty.handler.traffic.GlobalChannelTrafficShapingHandler;
|
||||
import io.netty.handler.traffic.TrafficCounter;
|
||||
import net.minestom.server.network.PacketProcessor;
|
||||
import net.minestom.server.network.netty.channel.ClientChannel;
|
||||
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 net.minestom.server.network.netty.codec.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
@ -37,6 +34,7 @@ public final class NettyServer {
|
||||
public static final String ENCRYPT_HANDLER_NAME = "encrypt"; // Write
|
||||
public static final String DECRYPT_HANDLER_NAME = "decrypt"; // Read
|
||||
|
||||
public static final String GROUPED_PACKET_HANDLER_NAME = "grouped-packet"; // Write
|
||||
public static final String FRAMER_HANDLER_NAME = "framer"; // Read/write
|
||||
|
||||
public static final String COMPRESSOR_HANDLER_NAME = "compressor"; // Read/write
|
||||
@ -110,6 +108,9 @@ public final class NettyServer {
|
||||
// Removed from the pipeline later in LegacyPingHandler if unnecessary (>1.6)
|
||||
pipeline.addLast(LEGACY_PING_HANDLER_NAME, new LegacyPingHandler());
|
||||
|
||||
// Used to bypass all the previous handlers by directly sending a framed buffer
|
||||
pipeline.addLast(GROUPED_PACKET_HANDLER_NAME, new GroupedPacketHandler());
|
||||
|
||||
// Adds packetLength at start | Reads framed bytebuf
|
||||
pipeline.addLast(FRAMER_HANDLER_NAME, new PacketFramer(packetProcessor));
|
||||
|
||||
|
@ -0,0 +1,14 @@
|
||||
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.netty.packet.FramedPacket;
|
||||
|
||||
public class GroupedPacketHandler extends MessageToByteEncoder<FramedPacket> {
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, FramedPacket msg, ByteBuf out) {
|
||||
out.writeBytes(msg.body.retainedSlice());
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ 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.PacketUtils;
|
||||
import net.minestom.server.utils.Utils;
|
||||
|
||||
import java.util.List;
|
||||
@ -42,24 +43,7 @@ public class PacketCompressor extends ByteToMessageCodec<ByteBuf> {
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, ByteBuf from, ByteBuf to) {
|
||||
final int packetLength = from.readableBytes();
|
||||
|
||||
if (packetLength < this.threshold) {
|
||||
Utils.writeVarIntBuf(to, 0);
|
||||
to.writeBytes(from);
|
||||
} else {
|
||||
Utils.writeVarIntBuf(to, packetLength);
|
||||
|
||||
deflater.setInput(from.nioBuffer());
|
||||
deflater.finish();
|
||||
|
||||
while (!deflater.finished()) {
|
||||
final int length = deflater.deflate(buffer);
|
||||
to.writeBytes(buffer, 0, length);
|
||||
}
|
||||
|
||||
deflater.reset();
|
||||
}
|
||||
PacketUtils.compressBuffer(deflater, buffer, from, to);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -7,6 +7,7 @@ import io.netty.handler.codec.CorruptedFrameException;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.network.PacketProcessor;
|
||||
import net.minestom.server.network.player.PlayerConnection;
|
||||
import net.minestom.server.utils.PacketUtils;
|
||||
import net.minestom.server.utils.Utils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -25,17 +26,7 @@ public class PacketFramer extends ByteToMessageCodec<ByteBuf> {
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, ByteBuf from, ByteBuf to) {
|
||||
final int packetSize = from.readableBytes();
|
||||
final 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);
|
||||
PacketUtils.frameBuffer(from, to);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,18 @@
|
||||
package net.minestom.server.network.netty.packet;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents a packet which is already framed.
|
||||
* Can be used if you want to send the exact same buffer to multiple clients without processing it more than once.
|
||||
*/
|
||||
public class FramedPacket {
|
||||
|
||||
public final ByteBuf body;
|
||||
|
||||
public FramedPacket(@NotNull ByteBuf body) {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
}
|
@ -134,7 +134,7 @@ public class NettyPlayerConnection extends PlayerConnection {
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
channel.close();
|
||||
this.channel.close();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
@ -5,6 +5,7 @@ import io.netty.buffer.Unpooled;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.listener.manager.PacketListenerManager;
|
||||
import net.minestom.server.network.netty.packet.FramedPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.player.NettyPlayerConnection;
|
||||
import net.minestom.server.network.player.PlayerConnection;
|
||||
@ -12,6 +13,7 @@ import net.minestom.server.utils.binary.BinaryWriter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.zip.Deflater;
|
||||
|
||||
/**
|
||||
* Utils class for packets. Including writing a {@link ServerPacket} into a {@link ByteBuf}
|
||||
@ -21,6 +23,9 @@ public final class PacketUtils {
|
||||
|
||||
private static final PacketListenerManager PACKET_LISTENER_MANAGER = MinecraftServer.getPacketListenerManager();
|
||||
|
||||
private static Deflater deflater = new Deflater();
|
||||
private static byte[] buffer = new byte[8192];
|
||||
|
||||
private PacketUtils() {
|
||||
|
||||
}
|
||||
@ -36,13 +41,14 @@ public final class PacketUtils {
|
||||
public static void sendGroupedPacket(@NotNull Collection<Player> players, @NotNull ServerPacket packet) {
|
||||
final boolean success = PACKET_LISTENER_MANAGER.processServerPacket(packet, players);
|
||||
if (success) {
|
||||
final ByteBuf buffer = writePacket(packet);
|
||||
final ByteBuf finalBuffer = createFramedPacket(packet);
|
||||
final FramedPacket framedPacket = new FramedPacket(finalBuffer);
|
||||
|
||||
for (Player player : players) {
|
||||
final PlayerConnection playerConnection = player.getPlayerConnection();
|
||||
if (playerConnection instanceof NettyPlayerConnection) {
|
||||
final NettyPlayerConnection nettyPlayerConnection = (NettyPlayerConnection) playerConnection;
|
||||
nettyPlayerConnection.getChannel().write(buffer.retainedSlice());
|
||||
nettyPlayerConnection.getChannel().write(framedPacket);
|
||||
} else {
|
||||
playerConnection.sendPacket(packet);
|
||||
}
|
||||
@ -108,4 +114,62 @@ public final class PacketUtils {
|
||||
return writer.getBuffer();
|
||||
}
|
||||
|
||||
public static void frameBuffer(@NotNull ByteBuf from, @NotNull ByteBuf to) {
|
||||
final int packetSize = from.readableBytes();
|
||||
final 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);
|
||||
}
|
||||
|
||||
public static void compressBuffer(@NotNull Deflater deflater, @NotNull byte[] buffer, @NotNull ByteBuf from, @NotNull ByteBuf to) {
|
||||
final int packetLength = from.readableBytes();
|
||||
|
||||
if (packetLength < MinecraftServer.getCompressionThreshold()) {
|
||||
Utils.writeVarIntBuf(to, 0);
|
||||
to.writeBytes(from);
|
||||
} else {
|
||||
Utils.writeVarIntBuf(to, packetLength);
|
||||
|
||||
deflater.setInput(from.nioBuffer());
|
||||
deflater.finish();
|
||||
|
||||
while (!deflater.finished()) {
|
||||
final int length = deflater.deflate(buffer);
|
||||
to.writeBytes(buffer, 0, length);
|
||||
}
|
||||
|
||||
deflater.reset();
|
||||
}
|
||||
}
|
||||
|
||||
private static ByteBuf createFramedPacket(@NotNull ServerPacket serverPacket) {
|
||||
ByteBuf packetBuf = writePacket(serverPacket);
|
||||
|
||||
if (MinecraftServer.getCompressionThreshold() > 0) {
|
||||
|
||||
ByteBuf compressedBuf = Unpooled.buffer();
|
||||
ByteBuf framedBuf = Unpooled.buffer();
|
||||
synchronized (deflater) {
|
||||
compressBuffer(deflater, buffer, packetBuf, compressedBuf);
|
||||
}
|
||||
|
||||
frameBuffer(compressedBuf, framedBuf);
|
||||
|
||||
return framedBuf;
|
||||
} else {
|
||||
ByteBuf framedBuf = Unpooled.buffer();
|
||||
frameBuffer(packetBuf, framedBuf);
|
||||
|
||||
return framedBuf;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user