From 7a82ded94b1229c5a9e55e33e3ac7ad28d8cc9cf Mon Sep 17 00:00:00 2001 From: KennyTV Date: Mon, 14 Jun 2021 21:09:47 +0200 Subject: [PATCH] Fix Velocity compatibility (requires Velocity 3.0.0) This finally removes the hacky reorder fix on Velocity; it added a few more events that could benefit us, but this is the most important right now. --- .../viaversion/viaversion/VelocityPlugin.java | 2 +- .../handlers/VelocityChannelInitializer.java | 35 +++++---- .../handlers/VelocityDecodeHandler.java | 77 ++++++------------- .../handlers/VelocityEncodeHandler.java | 46 ----------- .../providers/VelocityVersionProvider.java | 1 + 5 files changed, 48 insertions(+), 113 deletions(-) diff --git a/velocity/src/main/java/com/viaversion/viaversion/VelocityPlugin.java b/velocity/src/main/java/com/viaversion/viaversion/VelocityPlugin.java index 573f2d2ca..cc78237b5 100644 --- a/velocity/src/main/java/com/viaversion/viaversion/VelocityPlugin.java +++ b/velocity/src/main/java/com/viaversion/viaversion/VelocityPlugin.java @@ -39,11 +39,11 @@ import com.viaversion.viaversion.util.GsonUtil; import com.viaversion.viaversion.util.VersionInfo; import com.viaversion.viaversion.velocity.command.VelocityCommandHandler; import com.viaversion.viaversion.velocity.command.VelocityCommandSender; -import com.viaversion.viaversion.velocity.platform.VelocityViaTask; import com.viaversion.viaversion.velocity.platform.VelocityViaAPI; import com.viaversion.viaversion.velocity.platform.VelocityViaConfig; import com.viaversion.viaversion.velocity.platform.VelocityViaInjector; import com.viaversion.viaversion.velocity.platform.VelocityViaLoader; +import com.viaversion.viaversion.velocity.platform.VelocityViaTask; import com.viaversion.viaversion.velocity.service.ProtocolDetectorService; import com.viaversion.viaversion.velocity.util.LoggerWrapper; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; diff --git a/velocity/src/main/java/com/viaversion/viaversion/velocity/handlers/VelocityChannelInitializer.java b/velocity/src/main/java/com/viaversion/viaversion/velocity/handlers/VelocityChannelInitializer.java index e6b43aad7..59c3d6468 100644 --- a/velocity/src/main/java/com/viaversion/viaversion/velocity/handlers/VelocityChannelInitializer.java +++ b/velocity/src/main/java/com/viaversion/viaversion/velocity/handlers/VelocityChannelInitializer.java @@ -26,33 +26,42 @@ import io.netty.channel.ChannelInitializer; import java.lang.reflect.Method; public class VelocityChannelInitializer extends ChannelInitializer { + public static final String MINECRAFT_ENCODER = "minecraft-encoder"; + public static final String MINECRAFT_DECODER = "minecraft-decoder"; + public static final String VIA_ENCODER = "via-encoder"; + public static final String VIA_DECODER = "via-decoder"; + public static final Object COMPRESSION_ENABLED_EVENT; + private static final Method INIT_CHANNEL; + private final ChannelInitializer original; private final boolean clientSide; - private static Method initChannel; + + static { + try { + INIT_CHANNEL = ChannelInitializer.class.getDeclaredMethod("initChannel", Channel.class); + INIT_CHANNEL.setAccessible(true); + + Class eventClass = Class.forName("com.velocitypowered.proxy.protocol.VelocityConnectionEvent"); + COMPRESSION_ENABLED_EVENT = eventClass.getDeclaredField("COMPRESSION_ENABLED").get(null); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } public VelocityChannelInitializer(ChannelInitializer original, boolean clientSide) { this.original = original; this.clientSide = clientSide; } - static { - try { - initChannel = ChannelInitializer.class.getDeclaredMethod("initChannel", Channel.class); - initChannel.setAccessible(true); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } - } - @Override protected void initChannel(Channel channel) throws Exception { - initChannel.invoke(original, channel); + INIT_CHANNEL.invoke(original, channel); UserConnection user = new UserConnectionImpl(channel, clientSide); new ProtocolPipelineImpl(user); // We need to add a separated handler because Velocity uses pipeline().get(MINECRAFT_DECODER) - channel.pipeline().addBefore("minecraft-encoder", "via-encoder", new VelocityEncodeHandler(user)); - channel.pipeline().addBefore("minecraft-decoder", "via-decoder", new VelocityDecodeHandler(user)); + channel.pipeline().addBefore(MINECRAFT_ENCODER, VIA_ENCODER, new VelocityEncodeHandler(user)); + channel.pipeline().addBefore(MINECRAFT_DECODER, VIA_DECODER, new VelocityDecodeHandler(user)); } } diff --git a/velocity/src/main/java/com/viaversion/viaversion/velocity/handlers/VelocityDecodeHandler.java b/velocity/src/main/java/com/viaversion/viaversion/velocity/handlers/VelocityDecodeHandler.java index e7eea8168..e24ea472f 100644 --- a/velocity/src/main/java/com/viaversion/viaversion/velocity/handlers/VelocityDecodeHandler.java +++ b/velocity/src/main/java/com/viaversion/viaversion/velocity/handlers/VelocityDecodeHandler.java @@ -20,21 +20,17 @@ package com.viaversion.viaversion.velocity.handlers; import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.exception.CancelCodecException; import com.viaversion.viaversion.exception.CancelDecoderException; -import com.viaversion.viaversion.util.PipelineUtil; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.MessageToByteEncoder; +import io.netty.channel.ChannelPipeline; import io.netty.handler.codec.MessageToMessageDecoder; -import java.lang.reflect.InvocationTargetException; import java.util.List; @ChannelHandler.Sharable public class VelocityDecodeHandler extends MessageToMessageDecoder { private final UserConnection info; - private boolean handledCompression; - private boolean skipDoubleTransform; public VelocityDecodeHandler(UserConnection info) { this.info = info; @@ -42,12 +38,6 @@ public class VelocityDecodeHandler extends MessageToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List out) throws Exception { - if (skipDoubleTransform) { - skipDoubleTransform = false; - out.add(bytebuf.retain()); - return; - } - if (!info.checkIncomingPacket()) throw CancelDecoderException.generate(null); if (!info.shouldTransformPacket()) { out.add(bytebuf.retain()); @@ -56,58 +46,39 @@ public class VelocityDecodeHandler extends MessageToMessageDecoder { ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf); try { - boolean needsCompress = handleCompressionOrder(ctx, transformedBuf); - info.transformIncoming(transformedBuf, CancelDecoderException::generate); - - if (needsCompress) { - recompress(ctx, transformedBuf); - skipDoubleTransform = true; - } out.add(transformedBuf.retain()); } finally { transformedBuf.release(); } } - private boolean handleCompressionOrder(ChannelHandlerContext ctx, ByteBuf buf) throws InvocationTargetException { - if (handledCompression) return false; - - int decoderIndex = ctx.pipeline().names().indexOf("compression-decoder"); - if (decoderIndex == -1) return false; - handledCompression = true; - if (decoderIndex > ctx.pipeline().names().indexOf("via-decoder")) { - // Need to decompress this packet due to bad order - ByteBuf decompressed = (ByteBuf) PipelineUtil.callDecode((MessageToMessageDecoder) ctx.pipeline().get("compression-decoder"), ctx, buf).get(0); - try { - buf.clear().writeBytes(decompressed); - } finally { - decompressed.release(); - } - ChannelHandler encoder = ctx.pipeline().get("via-encoder"); - ChannelHandler decoder = ctx.pipeline().get("via-decoder"); - ctx.pipeline().remove(encoder); - ctx.pipeline().remove(decoder); - ctx.pipeline().addAfter("compression-encoder", "via-encoder", encoder); - ctx.pipeline().addAfter("compression-decoder", "via-decoder", decoder); - return true; - } - return false; - } - - private void recompress(ChannelHandlerContext ctx, ByteBuf buf) throws Exception { - ByteBuf compressed = ctx.alloc().buffer(); - try { - PipelineUtil.callEncode((MessageToByteEncoder) ctx.pipeline().get("compression-encoder"), ctx, buf, compressed); - buf.clear().writeBytes(compressed); - } finally { - compressed.release(); - } - } - @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { if (cause instanceof CancelCodecException) return; super.exceptionCaught(ctx, cause); } + + // Abuse decoder handler to catch events + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object event) throws Exception { + if (event != VelocityChannelInitializer.COMPRESSION_ENABLED_EVENT) { + super.userEventTriggered(ctx, event); + return; + } + + // When Velocity adds the compression handlers, the order becomes Minecraft Encoder -> Compressor -> Via Encoder + // Move Via codec handlers back to right position + ChannelPipeline pipeline = ctx.pipeline(); + + ChannelHandler encoder = pipeline.get(VelocityChannelInitializer.VIA_ENCODER); + pipeline.remove(encoder); + pipeline.addBefore(VelocityChannelInitializer.MINECRAFT_ENCODER, VelocityChannelInitializer.VIA_ENCODER, encoder); + + ChannelHandler decoder = pipeline.get(VelocityChannelInitializer.VIA_DECODER); + pipeline.remove(decoder); + pipeline.addBefore(VelocityChannelInitializer.MINECRAFT_DECODER, VelocityChannelInitializer.VIA_DECODER, decoder); + + super.userEventTriggered(ctx, event); + } } diff --git a/velocity/src/main/java/com/viaversion/viaversion/velocity/handlers/VelocityEncodeHandler.java b/velocity/src/main/java/com/viaversion/viaversion/velocity/handlers/VelocityEncodeHandler.java index cb3d233df..90cb44b5c 100644 --- a/velocity/src/main/java/com/viaversion/viaversion/velocity/handlers/VelocityEncodeHandler.java +++ b/velocity/src/main/java/com/viaversion/viaversion/velocity/handlers/VelocityEncodeHandler.java @@ -20,21 +20,16 @@ package com.viaversion.viaversion.velocity.handlers; import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.exception.CancelCodecException; import com.viaversion.viaversion.exception.CancelEncoderException; -import com.viaversion.viaversion.util.PipelineUtil; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.MessageToByteEncoder; -import io.netty.handler.codec.MessageToMessageDecoder; import io.netty.handler.codec.MessageToMessageEncoder; -import java.lang.reflect.InvocationTargetException; import java.util.List; @ChannelHandler.Sharable public class VelocityEncodeHandler extends MessageToMessageEncoder { private final UserConnection info; - private boolean handledCompression; public VelocityEncodeHandler(UserConnection info) { this.info = info; @@ -50,54 +45,13 @@ public class VelocityEncodeHandler extends MessageToMessageEncoder { ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf); try { - boolean needsCompress = handleCompressionOrder(ctx, transformedBuf); - info.transformOutgoing(transformedBuf, CancelEncoderException::generate); - - if (needsCompress) { - recompress(ctx, transformedBuf); - } out.add(transformedBuf.retain()); } finally { transformedBuf.release(); } } - private boolean handleCompressionOrder(ChannelHandlerContext ctx, ByteBuf buf) throws InvocationTargetException { - if (handledCompression) return false; - - int encoderIndex = ctx.pipeline().names().indexOf("compression-encoder"); - if (encoderIndex == -1) return false; - handledCompression = true; - if (encoderIndex > ctx.pipeline().names().indexOf("via-encoder")) { - // Need to decompress this packet due to bad order - ByteBuf decompressed = (ByteBuf) PipelineUtil.callDecode((MessageToMessageDecoder) ctx.pipeline().get("compression-decoder"), ctx, buf).get(0); - try { - buf.clear().writeBytes(decompressed); - } finally { - decompressed.release(); - } - ChannelHandler encoder = ctx.pipeline().get("via-encoder"); - ChannelHandler decoder = ctx.pipeline().get("via-decoder"); - ctx.pipeline().remove(encoder); - ctx.pipeline().remove(decoder); - ctx.pipeline().addAfter("compression-encoder", "via-encoder", encoder); - ctx.pipeline().addAfter("compression-decoder", "via-decoder", decoder); - return true; - } - return false; - } - - private void recompress(ChannelHandlerContext ctx, ByteBuf buf) throws InvocationTargetException { - ByteBuf compressed = ctx.alloc().buffer(); - try { - PipelineUtil.callEncode((MessageToByteEncoder) ctx.pipeline().get("compression-encoder"), ctx, buf, compressed); - buf.clear().writeBytes(compressed); - } finally { - compressed.release(); - } - } - @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { if (cause instanceof CancelCodecException) return; diff --git a/velocity/src/main/java/com/viaversion/viaversion/velocity/providers/VelocityVersionProvider.java b/velocity/src/main/java/com/viaversion/viaversion/velocity/providers/VelocityVersionProvider.java index 8652b3274..8605d1076 100644 --- a/velocity/src/main/java/com/viaversion/viaversion/velocity/providers/VelocityVersionProvider.java +++ b/velocity/src/main/java/com/viaversion/viaversion/velocity/providers/VelocityVersionProvider.java @@ -48,6 +48,7 @@ public class VelocityVersionProvider extends BaseVersionProvider { } private int getBackProtocol(UserConnection user) throws Exception { + //TODO use newly added Velocity netty event ChannelHandler mcHandler = user.getChannel().pipeline().get("handler"); return ProtocolDetectorService.getProtocolId( ((ServerConnection) getAssociation.invoke(mcHandler)).getServerInfo().getName());