mirror of
https://github.com/ViaVersion/ViaVersion.git
synced 2024-12-23 08:57:39 +01:00
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.
This commit is contained in:
parent
86278e837a
commit
7a82ded94b
@ -39,11 +39,11 @@ import com.viaversion.viaversion.util.GsonUtil;
|
|||||||
import com.viaversion.viaversion.util.VersionInfo;
|
import com.viaversion.viaversion.util.VersionInfo;
|
||||||
import com.viaversion.viaversion.velocity.command.VelocityCommandHandler;
|
import com.viaversion.viaversion.velocity.command.VelocityCommandHandler;
|
||||||
import com.viaversion.viaversion.velocity.command.VelocityCommandSender;
|
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.VelocityViaAPI;
|
||||||
import com.viaversion.viaversion.velocity.platform.VelocityViaConfig;
|
import com.viaversion.viaversion.velocity.platform.VelocityViaConfig;
|
||||||
import com.viaversion.viaversion.velocity.platform.VelocityViaInjector;
|
import com.viaversion.viaversion.velocity.platform.VelocityViaInjector;
|
||||||
import com.viaversion.viaversion.velocity.platform.VelocityViaLoader;
|
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.service.ProtocolDetectorService;
|
||||||
import com.viaversion.viaversion.velocity.util.LoggerWrapper;
|
import com.viaversion.viaversion.velocity.util.LoggerWrapper;
|
||||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
|
@ -26,33 +26,42 @@ import io.netty.channel.ChannelInitializer;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
public class VelocityChannelInitializer extends ChannelInitializer<Channel> {
|
public class VelocityChannelInitializer extends ChannelInitializer<Channel> {
|
||||||
|
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 ChannelInitializer<?> original;
|
||||||
private final boolean clientSide;
|
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) {
|
public VelocityChannelInitializer(ChannelInitializer<?> original, boolean clientSide) {
|
||||||
this.original = original;
|
this.original = original;
|
||||||
this.clientSide = clientSide;
|
this.clientSide = clientSide;
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
|
||||||
try {
|
|
||||||
initChannel = ChannelInitializer.class.getDeclaredMethod("initChannel", Channel.class);
|
|
||||||
initChannel.setAccessible(true);
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initChannel(Channel channel) throws Exception {
|
protected void initChannel(Channel channel) throws Exception {
|
||||||
initChannel.invoke(original, channel);
|
INIT_CHANNEL.invoke(original, channel);
|
||||||
|
|
||||||
UserConnection user = new UserConnectionImpl(channel, clientSide);
|
UserConnection user = new UserConnectionImpl(channel, clientSide);
|
||||||
new ProtocolPipelineImpl(user);
|
new ProtocolPipelineImpl(user);
|
||||||
|
|
||||||
// We need to add a separated handler because Velocity uses pipeline().get(MINECRAFT_DECODER)
|
// 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_ENCODER, VIA_ENCODER, new VelocityEncodeHandler(user));
|
||||||
channel.pipeline().addBefore("minecraft-decoder", "via-decoder", new VelocityDecodeHandler(user));
|
channel.pipeline().addBefore(MINECRAFT_DECODER, VIA_DECODER, new VelocityDecodeHandler(user));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,21 +20,17 @@ package com.viaversion.viaversion.velocity.handlers;
|
|||||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||||
import com.viaversion.viaversion.exception.CancelCodecException;
|
import com.viaversion.viaversion.exception.CancelCodecException;
|
||||||
import com.viaversion.viaversion.exception.CancelDecoderException;
|
import com.viaversion.viaversion.exception.CancelDecoderException;
|
||||||
import com.viaversion.viaversion.util.PipelineUtil;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandler;
|
import io.netty.channel.ChannelHandler;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.MessageToByteEncoder;
|
import io.netty.channel.ChannelPipeline;
|
||||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ChannelHandler.Sharable
|
@ChannelHandler.Sharable
|
||||||
public class VelocityDecodeHandler extends MessageToMessageDecoder<ByteBuf> {
|
public class VelocityDecodeHandler extends MessageToMessageDecoder<ByteBuf> {
|
||||||
private final UserConnection info;
|
private final UserConnection info;
|
||||||
private boolean handledCompression;
|
|
||||||
private boolean skipDoubleTransform;
|
|
||||||
|
|
||||||
public VelocityDecodeHandler(UserConnection info) {
|
public VelocityDecodeHandler(UserConnection info) {
|
||||||
this.info = info;
|
this.info = info;
|
||||||
@ -42,12 +38,6 @@ public class VelocityDecodeHandler extends MessageToMessageDecoder<ByteBuf> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> out) throws Exception {
|
protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> out) throws Exception {
|
||||||
if (skipDoubleTransform) {
|
|
||||||
skipDoubleTransform = false;
|
|
||||||
out.add(bytebuf.retain());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!info.checkIncomingPacket()) throw CancelDecoderException.generate(null);
|
if (!info.checkIncomingPacket()) throw CancelDecoderException.generate(null);
|
||||||
if (!info.shouldTransformPacket()) {
|
if (!info.shouldTransformPacket()) {
|
||||||
out.add(bytebuf.retain());
|
out.add(bytebuf.retain());
|
||||||
@ -56,58 +46,39 @@ public class VelocityDecodeHandler extends MessageToMessageDecoder<ByteBuf> {
|
|||||||
|
|
||||||
ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf);
|
ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf);
|
||||||
try {
|
try {
|
||||||
boolean needsCompress = handleCompressionOrder(ctx, transformedBuf);
|
|
||||||
|
|
||||||
info.transformIncoming(transformedBuf, CancelDecoderException::generate);
|
info.transformIncoming(transformedBuf, CancelDecoderException::generate);
|
||||||
|
|
||||||
if (needsCompress) {
|
|
||||||
recompress(ctx, transformedBuf);
|
|
||||||
skipDoubleTransform = true;
|
|
||||||
}
|
|
||||||
out.add(transformedBuf.retain());
|
out.add(transformedBuf.retain());
|
||||||
} finally {
|
} finally {
|
||||||
transformedBuf.release();
|
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
|
@Override
|
||||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
if (cause instanceof CancelCodecException) return;
|
if (cause instanceof CancelCodecException) return;
|
||||||
super.exceptionCaught(ctx, cause);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,21 +20,16 @@ package com.viaversion.viaversion.velocity.handlers;
|
|||||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||||
import com.viaversion.viaversion.exception.CancelCodecException;
|
import com.viaversion.viaversion.exception.CancelCodecException;
|
||||||
import com.viaversion.viaversion.exception.CancelEncoderException;
|
import com.viaversion.viaversion.exception.CancelEncoderException;
|
||||||
import com.viaversion.viaversion.util.PipelineUtil;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandler;
|
import io.netty.channel.ChannelHandler;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.MessageToByteEncoder;
|
|
||||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
|
||||||
import io.netty.handler.codec.MessageToMessageEncoder;
|
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ChannelHandler.Sharable
|
@ChannelHandler.Sharable
|
||||||
public class VelocityEncodeHandler extends MessageToMessageEncoder<ByteBuf> {
|
public class VelocityEncodeHandler extends MessageToMessageEncoder<ByteBuf> {
|
||||||
private final UserConnection info;
|
private final UserConnection info;
|
||||||
private boolean handledCompression;
|
|
||||||
|
|
||||||
public VelocityEncodeHandler(UserConnection info) {
|
public VelocityEncodeHandler(UserConnection info) {
|
||||||
this.info = info;
|
this.info = info;
|
||||||
@ -50,54 +45,13 @@ public class VelocityEncodeHandler extends MessageToMessageEncoder<ByteBuf> {
|
|||||||
|
|
||||||
ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf);
|
ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf);
|
||||||
try {
|
try {
|
||||||
boolean needsCompress = handleCompressionOrder(ctx, transformedBuf);
|
|
||||||
|
|
||||||
info.transformOutgoing(transformedBuf, CancelEncoderException::generate);
|
info.transformOutgoing(transformedBuf, CancelEncoderException::generate);
|
||||||
|
|
||||||
if (needsCompress) {
|
|
||||||
recompress(ctx, transformedBuf);
|
|
||||||
}
|
|
||||||
out.add(transformedBuf.retain());
|
out.add(transformedBuf.retain());
|
||||||
} finally {
|
} finally {
|
||||||
transformedBuf.release();
|
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
|
@Override
|
||||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
if (cause instanceof CancelCodecException) return;
|
if (cause instanceof CancelCodecException) return;
|
||||||
|
@ -48,6 +48,7 @@ public class VelocityVersionProvider extends BaseVersionProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int getBackProtocol(UserConnection user) throws Exception {
|
private int getBackProtocol(UserConnection user) throws Exception {
|
||||||
|
//TODO use newly added Velocity netty event
|
||||||
ChannelHandler mcHandler = user.getChannel().pipeline().get("handler");
|
ChannelHandler mcHandler = user.getChannel().pipeline().get("handler");
|
||||||
return ProtocolDetectorService.getProtocolId(
|
return ProtocolDetectorService.getProtocolId(
|
||||||
((ServerConnection) getAssociation.invoke(mcHandler)).getServerInfo().getName());
|
((ServerConnection) getAssociation.invoke(mcHandler)).getServerInfo().getName());
|
||||||
|
Loading…
Reference in New Issue
Block a user