From a8a1e9448e37cffac0eebf5786196e743fb6816d Mon Sep 17 00:00:00 2001 From: creeper123123321 <7974274+creeper123123321@users.noreply.github.com> Date: Sun, 7 Jun 2020 10:35:27 +0200 Subject: [PATCH] Netty handler tidy --- .../bukkit/handlers/BukkitDecodeHandler.java | 74 +++++---------- .../bukkit/handlers/BukkitEncodeHandler.java | 42 +++------ .../myles/ViaVersion/bukkit/util/NMSUtil.java | 18 ++++ .../bungee/handlers/BungeeDecodeHandler.java | 63 +++---------- .../bungee/handlers/BungeeEncodeHandler.java | 92 +++++++++---------- .../ViaVersion/api/data/UserConnection.java | 80 ++++++++++++++++ .../ViaVersion/api/protocol/Protocol.java | 2 +- .../exception/CancelDecoderException.java | 42 +++++++++ .../exception/CancelEncoderException.java | 42 +++++++++ .../ViaVersion/exception/CancelException.java | 14 +++ .../myles/ViaVersion/handlers/ViaHandler.java | 4 +- .../sponge/handlers/SpongeDecodeHandler.java | 69 ++++---------- .../sponge/handlers/SpongeEncodeHandler.java | 53 ++++------- .../handlers/VelocityDecodeHandler.java | 61 +++--------- .../handlers/VelocityEncodeHandler.java | 86 ++++++++--------- 15 files changed, 379 insertions(+), 363 deletions(-) create mode 100644 common/src/main/java/us/myles/ViaVersion/exception/CancelDecoderException.java create mode 100644 common/src/main/java/us/myles/ViaVersion/exception/CancelEncoderException.java diff --git a/bukkit/src/main/java/us/myles/ViaVersion/bukkit/handlers/BukkitDecodeHandler.java b/bukkit/src/main/java/us/myles/ViaVersion/bukkit/handlers/BukkitDecodeHandler.java index 59f2f3e18..d4d7c72b8 100644 --- a/bukkit/src/main/java/us/myles/ViaVersion/bukkit/handlers/BukkitDecodeHandler.java +++ b/bukkit/src/main/java/us/myles/ViaVersion/bukkit/handlers/BukkitDecodeHandler.java @@ -3,19 +3,15 @@ package us.myles.ViaVersion.bukkit.handlers; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; -import us.myles.ViaVersion.api.PacketWrapper; import us.myles.ViaVersion.api.data.UserConnection; -import us.myles.ViaVersion.api.type.Type; -import us.myles.ViaVersion.exception.CancelException; -import us.myles.ViaVersion.packets.Direction; -import us.myles.ViaVersion.protocols.base.ProtocolInfo; +import us.myles.ViaVersion.bukkit.util.NMSUtil; +import us.myles.ViaVersion.exception.CancelDecoderException; import us.myles.ViaVersion.util.PipelineUtil; import java.lang.reflect.InvocationTargetException; import java.util.List; public class BukkitDecodeHandler extends ByteToMessageDecoder { - private final ByteToMessageDecoder minecraftDecoder; private final UserConnection info; @@ -26,64 +22,40 @@ public class BukkitDecodeHandler extends ByteToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List list) throws Exception { - // use transformers - if (bytebuf.readableBytes() > 0) { - // Ignore if pending disconnect - if (info.isPendingDisconnect()) { - return; - } - // Increment received - boolean second = info.incrementReceived(); - // Check PPS - if (second) { - if (info.handlePPS()) - return; + if (!info.checkIncomingPacket()) { + bytebuf.clear(); // Don't accumulate + throw CancelDecoderException.generate(null); + } + + ByteBuf draft = null; + try { + if (info.shouldTransformPacket()) { + draft = ctx.alloc().buffer().writeBytes(bytebuf); + info.transformIncoming(draft, CancelDecoderException::generate); } - if (info.isActive()) { - // Handle ID - int id = Type.VAR_INT.read(bytebuf); - // Transform - ByteBuf newPacket = ctx.alloc().buffer(); - try { - if (id == PacketWrapper.PASSTHROUGH_ID) { - newPacket.writeBytes(bytebuf); - } else { - PacketWrapper wrapper = new PacketWrapper(id, bytebuf, info); - ProtocolInfo protInfo = info.get(ProtocolInfo.class); - protInfo.getPipeline().transform(Direction.INCOMING, protInfo.getState(), wrapper); - wrapper.writeToBuffer(newPacket); - } - - bytebuf.clear(); - bytebuf = newPacket; - } catch (Exception e) { - // Clear Buffer - bytebuf.clear(); - // Release Packet, be free! - newPacket.release(); - throw e; - } - } - - // call minecraft decoder try { - list.addAll(PipelineUtil.callDecode(this.minecraftDecoder, ctx, bytebuf)); + list.addAll(PipelineUtil.callDecode(this.minecraftDecoder, ctx, draft == null ? bytebuf : draft)); } catch (InvocationTargetException e) { if (e.getCause() instanceof Exception) { throw (Exception) e.getCause(); + } else if (e.getCause() instanceof Error) { + throw (Error) e.getCause(); } - } finally { - if (info.isActive()) { - bytebuf.release(); - } + } + } finally { + if (draft != null) { + draft.release(); } } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - if (PipelineUtil.containsCause(cause, CancelException.class)) return; + if (PipelineUtil.containsCause(cause, CancelDecoderException.class)) return; // ProtocolLib compat super.exceptionCaught(ctx, cause); + if (!NMSUtil.isDebugPropertySet()) { + cause.printStackTrace(); // Print if CB doesn't already do it + } } } diff --git a/bukkit/src/main/java/us/myles/ViaVersion/bukkit/handlers/BukkitEncodeHandler.java b/bukkit/src/main/java/us/myles/ViaVersion/bukkit/handlers/BukkitEncodeHandler.java index 2e040983f..420c4cf06 100644 --- a/bukkit/src/main/java/us/myles/ViaVersion/bukkit/handlers/BukkitEncodeHandler.java +++ b/bukkit/src/main/java/us/myles/ViaVersion/bukkit/handlers/BukkitEncodeHandler.java @@ -3,22 +3,18 @@ package us.myles.ViaVersion.bukkit.handlers; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; -import us.myles.ViaVersion.api.PacketWrapper; import us.myles.ViaVersion.api.data.UserConnection; -import us.myles.ViaVersion.api.type.Type; import us.myles.ViaVersion.bukkit.util.NMSUtil; -import us.myles.ViaVersion.exception.CancelException; +import us.myles.ViaVersion.exception.CancelEncoderException; import us.myles.ViaVersion.handlers.ChannelHandlerContextWrapper; import us.myles.ViaVersion.handlers.ViaHandler; -import us.myles.ViaVersion.packets.Direction; -import us.myles.ViaVersion.protocols.base.ProtocolInfo; import us.myles.ViaVersion.util.PipelineUtil; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; public class BukkitEncodeHandler extends MessageToByteEncoder implements ViaHandler { - private static Field versionField = null; + private static Field versionField; static { try { @@ -51,6 +47,8 @@ public class BukkitEncodeHandler extends MessageToByteEncoder implements ViaHand } catch (InvocationTargetException e) { if (e.getCause() instanceof Exception) { throw (Exception) e.getCause(); + } else if (e.getCause() instanceof Error) { + throw (Error) e.getCause(); } } } @@ -59,35 +57,17 @@ public class BukkitEncodeHandler extends MessageToByteEncoder implements ViaHand } public void transform(ByteBuf bytebuf) throws Exception { - if (bytebuf.readableBytes() == 0) { - return; // Someone Already Decoded It! - } - // Increment sent - info.incrementSent(); - if (info.isActive()) { - // Handle ID - int id = Type.VAR_INT.read(bytebuf); - // Transform - ByteBuf oldPacket = bytebuf.copy(); - bytebuf.clear(); - - try { - PacketWrapper wrapper = new PacketWrapper(id, oldPacket, info); - ProtocolInfo protInfo = info.get(ProtocolInfo.class); - protInfo.getPipeline().transform(Direction.OUTGOING, protInfo.getState(), wrapper); - wrapper.writeToBuffer(bytebuf); - } catch (Exception e) { - bytebuf.clear(); - throw e; - } finally { - oldPacket.release(); - } - } + info.checkOutgoingPacket(); + if (!info.shouldTransformPacket()) return; + info.transformOutgoing(bytebuf, CancelEncoderException::generate); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - if (PipelineUtil.containsCause(cause, CancelException.class)) return; + if (PipelineUtil.containsCause(cause, CancelEncoderException.class)) return; // ProtocolLib compat super.exceptionCaught(ctx, cause); + if (!NMSUtil.isDebugPropertySet()) { + cause.printStackTrace(); // Print if CB doesn't already do it + } } } diff --git a/bukkit/src/main/java/us/myles/ViaVersion/bukkit/util/NMSUtil.java b/bukkit/src/main/java/us/myles/ViaVersion/bukkit/util/NMSUtil.java index b3f6186d7..b4f02acda 100644 --- a/bukkit/src/main/java/us/myles/ViaVersion/bukkit/util/NMSUtil.java +++ b/bukkit/src/main/java/us/myles/ViaVersion/bukkit/util/NMSUtil.java @@ -5,6 +5,17 @@ import org.bukkit.Bukkit; public class NMSUtil { private static final String BASE = Bukkit.getServer().getClass().getPackage().getName(); private static final String NMS = BASE.replace("org.bukkit.craftbukkit", "net.minecraft.server"); + private static final boolean DEBUG_PROPERTY = loadDebugProperty(); + + private static boolean loadDebugProperty() { + try { + Class serverClass = nms("MinecraftServer"); + Object server = serverClass.getDeclaredMethod("getServer").invoke(null); + return (boolean) serverClass.getMethod("isDebugging").invoke(server); + } catch (ReflectiveOperationException e) { + return false; + } + } public static Class nms(String className) throws ClassNotFoundException { return Class.forName(NMS + "." + className); @@ -17,4 +28,11 @@ public class NMSUtil { public static String getVersion() { return BASE.substring(BASE.lastIndexOf('.') + 1); } + + /** + * @return true if debug=true is set in the server.properties (added by CB) + */ + public static boolean isDebugPropertySet() { + return DEBUG_PROPERTY; + } } diff --git a/bungee/src/main/java/us/myles/ViaVersion/bungee/handlers/BungeeDecodeHandler.java b/bungee/src/main/java/us/myles/ViaVersion/bungee/handlers/BungeeDecodeHandler.java index 20d862992..5e01ebfc3 100644 --- a/bungee/src/main/java/us/myles/ViaVersion/bungee/handlers/BungeeDecodeHandler.java +++ b/bungee/src/main/java/us/myles/ViaVersion/bungee/handlers/BungeeDecodeHandler.java @@ -4,19 +4,13 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageDecoder; -import us.myles.ViaVersion.api.PacketWrapper; import us.myles.ViaVersion.api.data.UserConnection; -import us.myles.ViaVersion.api.type.Type; -import us.myles.ViaVersion.exception.CancelException; -import us.myles.ViaVersion.packets.Direction; -import us.myles.ViaVersion.protocols.base.ProtocolInfo; -import us.myles.ViaVersion.util.PipelineUtil; +import us.myles.ViaVersion.exception.CancelDecoderException; import java.util.List; @ChannelHandler.Sharable public class BungeeDecodeHandler extends MessageToMessageDecoder { - private final UserConnection info; public BungeeDecodeHandler(UserConnection info) { @@ -25,55 +19,24 @@ public class BungeeDecodeHandler extends MessageToMessageDecoder { @Override protected void decode(final ChannelHandlerContext ctx, ByteBuf bytebuf, List out) throws Exception { - // use transformers - if (bytebuf.readableBytes() > 0) { - // Ignore if pending disconnect - if (info.isPendingDisconnect()) { - return; - } - // Increment received - boolean second = info.incrementReceived(); - // Check PPS - if (second) { - if (info.handlePPS()) - return; - } + if (!info.checkIncomingPacket()) throw CancelDecoderException.generate(null); + if (!info.shouldTransformPacket()) { + out.add(bytebuf.retain()); + return; + } - if (info.isActive()) { - // Handle ID - int id = Type.VAR_INT.read(bytebuf); - // Transform - ByteBuf newPacket = ctx.alloc().buffer(); - try { - if (id == PacketWrapper.PASSTHROUGH_ID) { - newPacket.writeBytes(bytebuf); - } else { - PacketWrapper wrapper = new PacketWrapper(id, bytebuf, info); - ProtocolInfo protInfo = info.get(ProtocolInfo.class); - protInfo.getPipeline().transform(Direction.INCOMING, protInfo.getState(), wrapper); - wrapper.writeToBuffer(newPacket); - } - - bytebuf.clear(); - bytebuf = newPacket; - } catch (Throwable e) { - // Clear Buffer - bytebuf.clear(); - // Release Packet, be free! - newPacket.release(); - throw e; - } - } else { - bytebuf.retain(); - } - - out.add(bytebuf); + ByteBuf draft = ctx.alloc().buffer().writeBytes(bytebuf); + try { + info.transformIncoming(draft, CancelDecoderException::generate); + out.add(draft.retain()); + } finally { + draft.release(); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - if (PipelineUtil.containsCause(cause, CancelException.class)) return; + if (cause instanceof CancelDecoderException) return; super.exceptionCaught(ctx, cause); } } diff --git a/bungee/src/main/java/us/myles/ViaVersion/bungee/handlers/BungeeEncodeHandler.java b/bungee/src/main/java/us/myles/ViaVersion/bungee/handlers/BungeeEncodeHandler.java index e8106a9f1..01d6f84eb 100644 --- a/bungee/src/main/java/us/myles/ViaVersion/bungee/handlers/BungeeEncodeHandler.java +++ b/bungee/src/main/java/us/myles/ViaVersion/bungee/handlers/BungeeEncodeHandler.java @@ -4,84 +4,80 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageEncoder; -import us.myles.ViaVersion.api.PacketWrapper; -import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.data.UserConnection; -import us.myles.ViaVersion.api.type.Type; import us.myles.ViaVersion.bungee.util.BungeePipelineUtil; -import us.myles.ViaVersion.exception.CancelException; -import us.myles.ViaVersion.packets.Direction; -import us.myles.ViaVersion.protocols.base.ProtocolInfo; -import us.myles.ViaVersion.util.PipelineUtil; +import us.myles.ViaVersion.exception.CancelEncoderException; import java.util.List; @ChannelHandler.Sharable public class BungeeEncodeHandler extends MessageToMessageEncoder { private final UserConnection info; - private boolean handledCompression = false; + private boolean handledCompression; public BungeeEncodeHandler(UserConnection info) { this.info = info; } - @Override protected void encode(final ChannelHandlerContext ctx, ByteBuf bytebuf, List out) throws Exception { - if (bytebuf.readableBytes() == 0) { - throw Via.getManager().isDebug() ? new CancelException() : CancelException.CACHED; + info.checkOutgoingPacket(); + if (!info.shouldTransformPacket()) { + out.add(bytebuf.retain()); + return; } + + ByteBuf draft = ctx.alloc().buffer().writeBytes(bytebuf); + try { + boolean needsCompress = handleCompressionOrder(ctx, draft); + info.transformOutgoing(draft, CancelEncoderException::generate); + + if (needsCompress) { + recompress(ctx, draft); + } + + out.add(draft.retain()); + } finally { + draft.release(); + } + } + + private boolean handleCompressionOrder(ChannelHandlerContext ctx, ByteBuf draft) { boolean needsCompress = false; if (!handledCompression) { if (ctx.pipeline().names().indexOf("compress") > ctx.pipeline().names().indexOf("via-encoder")) { // Need to decompress this packet due to bad order - bytebuf = BungeePipelineUtil.decompress(ctx, bytebuf); - ChannelHandler encoder = ctx.pipeline().get("via-decoder"); - ChannelHandler decoder = ctx.pipeline().get("via-encoder"); - ctx.pipeline().remove(encoder); - ctx.pipeline().remove(decoder); - ctx.pipeline().addAfter("decompress", "via-decoder", encoder); - ctx.pipeline().addAfter("compress", "via-encoder", decoder); + ByteBuf decompressed = BungeePipelineUtil.decompress(ctx, draft); + try { + draft.clear().writeBytes(decompressed); + } finally { + decompressed.release(); + } + ChannelHandler dec = ctx.pipeline().get("via-decoder"); + ChannelHandler enc = ctx.pipeline().get("via-encoder"); + ctx.pipeline().remove(dec); + ctx.pipeline().remove(enc); + ctx.pipeline().addAfter("decompress", "via-decoder", dec); + ctx.pipeline().addAfter("compress", "via-encoder", enc); needsCompress = true; handledCompression = true; } } - // Increment sent - info.incrementSent(); + return needsCompress; + } - if (info.isActive()) { - // Handle ID - int id = Type.VAR_INT.read(bytebuf); - // Transform - ByteBuf oldPacket = bytebuf.copy(); - bytebuf.clear(); - - try { - PacketWrapper wrapper = new PacketWrapper(id, oldPacket, info); - ProtocolInfo protInfo = info.get(ProtocolInfo.class); - protInfo.getPipeline().transform(Direction.OUTGOING, protInfo.getState(), wrapper); - wrapper.writeToBuffer(bytebuf); - } catch (Throwable e) { - bytebuf.clear(); - throw e; - } finally { - oldPacket.release(); - } - } - - if (needsCompress) { - ByteBuf old = bytebuf; - bytebuf = BungeePipelineUtil.compress(ctx, bytebuf); - old.release(); - out.add(bytebuf); - } else { - out.add(bytebuf.retain()); + private void recompress(ChannelHandlerContext ctx, ByteBuf draft) { + ByteBuf compressed = BungeePipelineUtil.compress(ctx, draft); + try { + draft.clear().writeBytes(compressed); + } finally { + compressed.release(); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - if (PipelineUtil.containsCause(cause, CancelException.class)) return; + if (cause instanceof CancelEncoderException) return; super.exceptionCaught(ctx, cause); } } diff --git a/common/src/main/java/us/myles/ViaVersion/api/data/UserConnection.java b/common/src/main/java/us/myles/ViaVersion/api/data/UserConnection.java index 5369fc4ed..1ff17a2bf 100644 --- a/common/src/main/java/us/myles/ViaVersion/api/data/UserConnection.java +++ b/common/src/main/java/us/myles/ViaVersion/api/data/UserConnection.java @@ -11,6 +11,8 @@ import us.myles.ViaVersion.api.PacketWrapper; import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.ViaVersionConfig; import us.myles.ViaVersion.api.type.Type; +import us.myles.ViaVersion.exception.CancelException; +import us.myles.ViaVersion.packets.Direction; import us.myles.ViaVersion.protocols.base.ProtocolInfo; import us.myles.ViaVersion.util.PipelineUtil; @@ -18,6 +20,7 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Function; public class UserConnection { private static final AtomicLong IDS = new AtomicLong(); @@ -190,6 +193,8 @@ public class UserConnection { channel.close(); // =) } }); + } else { + getChannel().close(); // Just disconnect, we don't know what the connection is } } @@ -340,6 +345,81 @@ public class UserConnection { this.warnings = warnings; } + /** + * Monitors serverbound packets. + * + * @return false if this packet should be cancelled + */ + public boolean checkIncomingPacket() { + // Ignore if pending disconnect + if (pendingDisconnect) return false; + // Increment received + Check PPS + return !incrementReceived() || !handlePPS(); + } + + /** + * Monitors clientbound packets. + */ + public void checkOutgoingPacket() { + incrementSent(); + } + + /** + * Checks if packets needs transforming. + * + * @return if packets should be passed through + */ + public boolean shouldTransformPacket() { + return active; + } + + /** + * Transforms the clientbound packet contained in draft ByteBuf. + * + * @param draft ByteBuf with packet id and packet contents + * @param cancelSupplier Function called with original CancelException for generating the Exception used when + * packet is cancelled + * @throws Exception when transforming failed or this packet is cancelled + */ + public void transformOutgoing(ByteBuf draft, Function cancelSupplier) throws Exception { + if (!draft.isReadable()) return; + transform(draft, Direction.OUTGOING, cancelSupplier); + } + + /** + * Transforms the serverbound packet contained in draft ByteBuf. + * + * @param draft ByteBuf with packet id and packet contents + * @param cancelSupplier Function called with original CancelException for generating the Exception used when + * packet is cancelled + * @throws Exception when transforming failed or this packet is cancelled + */ + public void transformIncoming(ByteBuf draft, Function cancelSupplier) throws Exception { + if (!draft.isReadable()) return; + transform(draft, Direction.INCOMING, cancelSupplier); + } + + private void transform(ByteBuf draft, Direction direction, Function cancelSupplier) throws Exception { + int id = Type.VAR_INT.read(draft); + if (id == PacketWrapper.PASSTHROUGH_ID) return; + + PacketWrapper wrapper = new PacketWrapper(id, draft, this); + ProtocolInfo protInfo = get(ProtocolInfo.class); + try { + protInfo.getPipeline().transform(direction, protInfo.getState(), wrapper); + } catch (CancelException ex) { + throw cancelSupplier.apply(ex); + } + + ByteBuf transformed = draft.alloc().buffer(); + try { + wrapper.writeToBuffer(transformed); + draft.clear().writeBytes(transformed); + } finally { + transformed.release(); + } + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/common/src/main/java/us/myles/ViaVersion/api/protocol/Protocol.java b/common/src/main/java/us/myles/ViaVersion/api/protocol/Protocol.java index 119359495..f2055f593 100644 --- a/common/src/main/java/us/myles/ViaVersion/api/protocol/Protocol.java +++ b/common/src/main/java/us/myles/ViaVersion/api/protocol/Protocol.java @@ -435,7 +435,7 @@ public abstract class Protocol list) throws Exception { - // use transformers - if (bytebuf.readableBytes() > 0) { - // Ignore if pending disconnect - if (info.isPendingDisconnect()) { - return; - } - // Increment received - boolean second = info.incrementReceived(); - // Check PPS - if (second) { - if (info.handlePPS()) - return; + if (!info.checkIncomingPacket()) { + bytebuf.clear(); // Don't accumulate + throw CancelDecoderException.generate(null); + } + + ByteBuf draft = null; + try { + if (info.shouldTransformPacket()) { + draft = ctx.alloc().buffer().writeBytes(bytebuf); + info.transformIncoming(draft, CancelDecoderException::generate); } - if (info.isActive()) { - // Handle ID - int id = Type.VAR_INT.read(bytebuf); - // Transform - ByteBuf newPacket = ctx.alloc().buffer(); - try { - if (id == PacketWrapper.PASSTHROUGH_ID) { - newPacket.writeBytes(bytebuf); - } else { - PacketWrapper wrapper = new PacketWrapper(id, bytebuf, info); - ProtocolInfo protInfo = info.get(ProtocolInfo.class); - protInfo.getPipeline().transform(Direction.INCOMING, protInfo.getState(), wrapper); - wrapper.writeToBuffer(newPacket); - } - - bytebuf.clear(); - bytebuf = newPacket; - } catch (Throwable e) { - // Clear Buffer - bytebuf.clear(); - // Release Packet, be free! - newPacket.release(); - throw e; - } - } - - // call minecraft decoder try { - list.addAll(PipelineUtil.callDecode(this.minecraftDecoder, ctx, bytebuf)); + list.addAll(PipelineUtil.callDecode(this.minecraftDecoder, ctx, draft == null ? bytebuf : draft)); } catch (InvocationTargetException e) { if (e.getCause() instanceof Exception) { throw (Exception) e.getCause(); + } else if (e.getCause() instanceof Error) { + throw (Error) e.getCause(); } - } finally { - if (info.isActive()) { - bytebuf.release(); - } + } + } finally { + if (draft != null) { + draft.release(); } } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - if (PipelineUtil.containsCause(cause, CancelException.class)) return; + if (cause instanceof CancelDecoderException) return; super.exceptionCaught(ctx, cause); } } diff --git a/sponge/src/main/java/us/myles/ViaVersion/sponge/handlers/SpongeEncodeHandler.java b/sponge/src/main/java/us/myles/ViaVersion/sponge/handlers/SpongeEncodeHandler.java index 41beb84e9..c5a54dc44 100644 --- a/sponge/src/main/java/us/myles/ViaVersion/sponge/handlers/SpongeEncodeHandler.java +++ b/sponge/src/main/java/us/myles/ViaVersion/sponge/handlers/SpongeEncodeHandler.java @@ -3,69 +3,52 @@ package us.myles.ViaVersion.sponge.handlers; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; -import us.myles.ViaVersion.api.PacketWrapper; -import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.data.UserConnection; -import us.myles.ViaVersion.api.type.Type; -import us.myles.ViaVersion.exception.CancelException; -import us.myles.ViaVersion.packets.Direction; -import us.myles.ViaVersion.protocols.base.ProtocolInfo; +import us.myles.ViaVersion.exception.CancelEncoderException; +import us.myles.ViaVersion.handlers.ChannelHandlerContextWrapper; +import us.myles.ViaVersion.handlers.ViaHandler; import us.myles.ViaVersion.util.PipelineUtil; import java.lang.reflect.InvocationTargetException; -public class SpongeEncodeHandler extends MessageToByteEncoder { +public class SpongeEncodeHandler extends MessageToByteEncoder implements ViaHandler { private final UserConnection info; - private final MessageToByteEncoder minecraftEncoder; + private final MessageToByteEncoder minecraftEncoder; - public SpongeEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) { + public SpongeEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) { this.info = info; this.minecraftEncoder = minecraftEncoder; } - @Override protected void encode(final ChannelHandlerContext ctx, Object o, final ByteBuf bytebuf) throws Exception { // handle the packet type if (!(o instanceof ByteBuf)) { // call minecraft encoder try { - PipelineUtil.callEncode(this.minecraftEncoder, ctx, o, bytebuf); + PipelineUtil.callEncode(this.minecraftEncoder, new ChannelHandlerContextWrapper(ctx, this), o, bytebuf); } catch (InvocationTargetException e) { if (e.getCause() instanceof Exception) { throw (Exception) e.getCause(); + } else if (e.getCause() instanceof Error) { + throw (Error) e.getCause(); } } } - if (bytebuf.readableBytes() == 0) { - throw Via.getManager().isDebug() ? new CancelException() : CancelException.CACHED; - } - // Increment sent - info.incrementSent(); - if (info.isActive()) { - // Handle ID - int id = Type.VAR_INT.read(bytebuf); - // Transform - ByteBuf oldPacket = bytebuf.copy(); - bytebuf.clear(); - try { - PacketWrapper wrapper = new PacketWrapper(id, oldPacket, info); - ProtocolInfo protInfo = info.get(ProtocolInfo.class); - protInfo.getPipeline().transform(Direction.OUTGOING, protInfo.getState(), wrapper); - wrapper.writeToBuffer(bytebuf); - } catch (Throwable e) { - bytebuf.clear(); - throw e; - } finally { - oldPacket.release(); - } - } + transform(bytebuf); + } + + @Override + public void transform(ByteBuf bytebuf) throws Exception { + info.checkOutgoingPacket(); + if (!info.shouldTransformPacket()) return; + info.transformOutgoing(bytebuf, CancelEncoderException::generate); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - if (PipelineUtil.containsCause(cause, CancelException.class)) return; + if (cause instanceof CancelEncoderException) return; super.exceptionCaught(ctx, cause); } } diff --git a/velocity/src/main/java/us/myles/ViaVersion/velocity/handlers/VelocityDecodeHandler.java b/velocity/src/main/java/us/myles/ViaVersion/velocity/handlers/VelocityDecodeHandler.java index 322c066df..0a3fde26b 100644 --- a/velocity/src/main/java/us/myles/ViaVersion/velocity/handlers/VelocityDecodeHandler.java +++ b/velocity/src/main/java/us/myles/ViaVersion/velocity/handlers/VelocityDecodeHandler.java @@ -4,13 +4,8 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageDecoder; -import us.myles.ViaVersion.api.PacketWrapper; import us.myles.ViaVersion.api.data.UserConnection; -import us.myles.ViaVersion.api.type.Type; -import us.myles.ViaVersion.exception.CancelException; -import us.myles.ViaVersion.packets.Direction; -import us.myles.ViaVersion.protocols.base.ProtocolInfo; -import us.myles.ViaVersion.util.PipelineUtil; +import us.myles.ViaVersion.exception.CancelDecoderException; import java.util.List; @@ -24,54 +19,24 @@ public class VelocityDecodeHandler extends MessageToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List out) throws Exception { - // use transformers - if (bytebuf.readableBytes() > 0) { - // Ignore if pending disconnect - if (info.isPendingDisconnect()) { - return; - } - // Increment received - boolean second = info.incrementReceived(); - // Check PPS - if (second) { - if (info.handlePPS()) - return; - } - if (info.isActive()) { - // Handle ID - int id = Type.VAR_INT.read(bytebuf); - // Transform - ByteBuf newPacket = ctx.alloc().buffer(); - try { - if (id == PacketWrapper.PASSTHROUGH_ID) { - newPacket.writeBytes(bytebuf); - } else { - PacketWrapper wrapper = new PacketWrapper(id, bytebuf, info); - ProtocolInfo protInfo = info.get(ProtocolInfo.class); - protInfo.getPipeline().transform(Direction.INCOMING, protInfo.getState(), wrapper); - wrapper.writeToBuffer(newPacket); - } + if (!info.checkIncomingPacket()) throw CancelDecoderException.generate(null); + if (!info.shouldTransformPacket()) { + out.add(bytebuf.retain()); + return; + } - bytebuf.clear(); - bytebuf = newPacket; - } catch (Throwable e) { - // Clear Buffer - bytebuf.clear(); - // Release Packet, be free! - newPacket.release(); - throw e; - } - } else { - bytebuf.retain(); - } - - out.add(bytebuf); + ByteBuf draft = ctx.alloc().buffer().writeBytes(bytebuf); + try { + info.transformIncoming(draft, CancelDecoderException::generate); + out.add(draft.retain()); + } finally { + draft.release(); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - if (PipelineUtil.containsCause(cause, CancelException.class)) return; + if (cause instanceof CancelDecoderException) return; super.exceptionCaught(ctx, cause); } } diff --git a/velocity/src/main/java/us/myles/ViaVersion/velocity/handlers/VelocityEncodeHandler.java b/velocity/src/main/java/us/myles/ViaVersion/velocity/handlers/VelocityEncodeHandler.java index 673ec7541..4d38874e7 100644 --- a/velocity/src/main/java/us/myles/ViaVersion/velocity/handlers/VelocityEncodeHandler.java +++ b/velocity/src/main/java/us/myles/ViaVersion/velocity/handlers/VelocityEncodeHandler.java @@ -6,15 +6,11 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; import io.netty.handler.codec.MessageToMessageDecoder; import io.netty.handler.codec.MessageToMessageEncoder; -import us.myles.ViaVersion.api.PacketWrapper; -import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.data.UserConnection; -import us.myles.ViaVersion.api.type.Type; -import us.myles.ViaVersion.exception.CancelException; -import us.myles.ViaVersion.packets.Direction; -import us.myles.ViaVersion.protocols.base.ProtocolInfo; +import us.myles.ViaVersion.exception.CancelEncoderException; import us.myles.ViaVersion.util.PipelineUtil; +import java.lang.reflect.InvocationTargetException; import java.util.List; @ChannelHandler.Sharable @@ -28,14 +24,38 @@ public class VelocityEncodeHandler extends MessageToMessageEncoder { @Override protected void encode(final ChannelHandlerContext ctx, ByteBuf bytebuf, List out) throws Exception { - if (bytebuf.readableBytes() == 0) { - throw Via.getManager().isDebug() ? new CancelException() : CancelException.CACHED; + info.checkOutgoingPacket(); + if (!info.shouldTransformPacket()) { + out.add(bytebuf.retain()); + return; } + + ByteBuf draft = ctx.alloc().buffer().writeBytes(bytebuf); + try { + boolean needsCompress = handleCompressionOrder(ctx, draft); + + info.transformOutgoing(draft, CancelEncoderException::generate); + + if (needsCompress) { + recompress(ctx, draft); + } + out.add(draft.retain()); + } finally { + draft.release(); + } + } + + private boolean handleCompressionOrder(ChannelHandlerContext ctx, ByteBuf draft) throws InvocationTargetException { boolean needsCompress = false; if (!handledCompression && ctx.pipeline().names().indexOf("compression-encoder") > ctx.pipeline().names().indexOf("via-encoder")) { // Need to decompress this packet due to bad order - bytebuf = (ByteBuf) PipelineUtil.callDecode((MessageToMessageDecoder) ctx.pipeline().get("compression-decoder"), ctx, bytebuf).get(0); + ByteBuf decompressed = (ByteBuf) PipelineUtil.callDecode((MessageToMessageDecoder) ctx.pipeline().get("compression-decoder"), ctx, draft).get(0); + try { + draft.clear().writeBytes(decompressed); + } finally { + decompressed.release(); + } ChannelHandler encoder = ctx.pipeline().get("via-encoder"); ChannelHandler decoder = ctx.pipeline().get("via-decoder"); ctx.pipeline().remove(encoder); @@ -44,51 +64,23 @@ public class VelocityEncodeHandler extends MessageToMessageEncoder { ctx.pipeline().addAfter("compression-decoder", "via-decoder", decoder); needsCompress = true; handledCompression = true; - } else { - bytebuf.retain(); } - // Increment sent - info.incrementSent(); + return needsCompress; + } - - if (info.isActive()) { - // Handle ID - int id = Type.VAR_INT.read(bytebuf); - // Transform - ByteBuf newPacket = bytebuf.alloc().buffer(); - try { - PacketWrapper wrapper = new PacketWrapper(id, bytebuf, info); - ProtocolInfo protInfo = info.get(ProtocolInfo.class); - protInfo.getPipeline().transform(Direction.OUTGOING, protInfo.getState(), wrapper); - - wrapper.writeToBuffer(newPacket); - - bytebuf.clear(); - bytebuf.release(); - bytebuf = newPacket; - } catch (Throwable e) { - bytebuf.clear(); - bytebuf.release(); - newPacket.release(); - throw e; - } + private void recompress(ChannelHandlerContext ctx, ByteBuf draft) throws InvocationTargetException { + ByteBuf compressed = ctx.alloc().buffer(); + try { + PipelineUtil.callEncode((MessageToByteEncoder) ctx.pipeline().get("compression-encoder"), ctx, draft, compressed); + draft.clear().writeBytes(compressed); + } finally { + compressed.release(); } - - if (needsCompress) { - ByteBuf old = bytebuf; - bytebuf = ctx.alloc().buffer(); - try { - PipelineUtil.callEncode((MessageToByteEncoder) ctx.pipeline().get("compression-encoder"), ctx, old, bytebuf); - } finally { - old.release(); - } - } - out.add(bytebuf); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - if (PipelineUtil.containsCause(cause, CancelException.class)) return; + if (cause instanceof CancelEncoderException) return; super.exceptionCaught(ctx, cause); } }