Fix packet interception error with ViaVersion (#724)

Thanks to @KennyTV and @MedicOP for their help in tracking this bug down. Essentially the decode method we were using could be different depending on when the player logged in, which clashed with PL's static handling of it.

Fixes #724
Fixes #791
Fixes #803
Fixes #811
Fixes #813
Fixes #819
...and probably some others...
This commit is contained in:
Dan Mulloy 2020-05-24 15:29:01 -04:00
parent bfa0eee91e
commit b04fca8324
No known key found for this signature in database
GPG Key ID: 2B62F7DACFF133E8

View File

@ -79,23 +79,23 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
// Versioning // Versioning
private static Class<?> PACKET_SET_PROTOCOL = null; private static Class<?> PACKET_SET_PROTOCOL = null;
private static AtomicInteger keyId = new AtomicInteger(); private static final AtomicInteger keyId = new AtomicInteger();
private static AttributeKey<Integer> PROTOCOL_KEY; private static final AttributeKey<Integer> PROTOCOL_KEY;
static { static {
PROTOCOL_KEY = AttributeKey.valueOf("PROTOCOL-" + keyId.getAndIncrement()); PROTOCOL_KEY = AttributeKey.valueOf("PROTOCOL-" + keyId.getAndIncrement());
} }
// Saved accessors // Saved accessors
private static Method DECODE_BUFFER; private Method decodeBuffer;
private static Method ENCODE_BUFFER; private Method encodeBuffer;
private static FieldAccessor ENCODER_TYPE_MATCHER; private static FieldAccessor ENCODER_TYPE_MATCHER;
// For retrieving the protocol // For retrieving the protocol
private static FieldAccessor PROTOCOL_ACCESSOR; private static FieldAccessor PROTOCOL_ACCESSOR;
// The factory that created this injector // The factory that created this injector
private InjectionFactory factory; private final InjectionFactory factory;
// The player, or temporary player // The player, or temporary player
private Player player; private Player player;
@ -108,10 +108,10 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
// The current network manager and channel // The current network manager and channel
private final Object networkManager; private final Object networkManager;
private final Channel originalChannel; private final Channel originalChannel;
private VolatileField channelField; private final VolatileField channelField;
// Known network markers // Known network markers
private Map<Object, NetworkMarker> packetMarker = new WeakHashMap<>(); private final Map<Object, NetworkMarker> packetMarker = new WeakHashMap<>();
/** /**
* Indicate that this packet has been processed by event listeners. * Indicate that this packet has been processed by event listeners.
@ -134,13 +134,13 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
private ByteToMessageDecoder vanillaDecoder; private ByteToMessageDecoder vanillaDecoder;
private MessageToByteEncoder<Object> vanillaEncoder; private MessageToByteEncoder<Object> vanillaEncoder;
private Deque<PacketEvent> finishQueue = new ArrayDeque<>(); private final Deque<PacketEvent> finishQueue = new ArrayDeque<>();
// The channel listener // The channel listener
private ChannelListener channelListener; private final ChannelListener channelListener;
// Processing network markers // Processing network markers
private NetworkProcessor processor; private final NetworkProcessor processor;
// Closed // Closed
private boolean injected; private boolean injected;
@ -178,6 +178,24 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
return value != null ? value : MinecraftProtocolVersion.getCurrentVersion(); return value != null ? value : MinecraftProtocolVersion.getCurrentVersion();
} }
private void updateBufferMethods() {
try {
decodeBuffer = vanillaDecoder.getClass().getDeclaredMethod("decode",
ChannelHandlerContext.class, ByteBuf.class, List.class);
decodeBuffer.setAccessible(true);
} catch (NoSuchMethodException ex) {
throw new IllegalArgumentException("Unable to find decode method in " + vanillaDecoder.getClass());
}
try {
encodeBuffer = vanillaEncoder.getClass().getDeclaredMethod("encode",
ChannelHandlerContext.class, Object.class, ByteBuf.class);
encodeBuffer.setAccessible(true);
} catch (NoSuchMethodException ex) {
throw new IllegalArgumentException("Unable to find encode method in " + vanillaEncoder.getClass());
}
}
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public boolean inject() { public boolean inject() {
@ -212,25 +230,7 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
throw new IllegalArgumentException("Unable to find vanilla encoder in " + originalChannel.pipeline()); throw new IllegalArgumentException("Unable to find vanilla encoder in " + originalChannel.pipeline());
patchEncoder(vanillaEncoder); patchEncoder(vanillaEncoder);
if (DECODE_BUFFER == null) { updateBufferMethods();
try {
DECODE_BUFFER = vanillaDecoder.getClass().getDeclaredMethod("decode",
ChannelHandlerContext.class, ByteBuf.class, List.class);
DECODE_BUFFER.setAccessible(true);
} catch (NoSuchMethodException ex) {
throw new IllegalArgumentException("Unable to find decode method in " + vanillaDecoder.getClass());
}
}
if (ENCODE_BUFFER == null) {
try {
ENCODE_BUFFER = vanillaEncoder.getClass().getDeclaredMethod("encode",
ChannelHandlerContext.class, Object.class, ByteBuf.class);
ENCODE_BUFFER.setAccessible(true);
} catch (NoSuchMethodException ex) {
throw new IllegalArgumentException("Unable to find encode method in " + vanillaEncoder.getClass());
}
}
// Intercept sent packets // Intercept sent packets
MessageToByteEncoder<Object> protocolEncoder = new MessageToByteEncoder<Object>() { MessageToByteEncoder<Object> protocolEncoder = new MessageToByteEncoder<Object>() {
@ -447,7 +447,7 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
// Process output handler // Process output handler
if (packet != null && event != null && NetworkMarker.hasOutputHandlers(marker)) { if (packet != null && event != null && NetworkMarker.hasOutputHandlers(marker)) {
ByteBuf packetBuffer = ctx.alloc().buffer(); ByteBuf packetBuffer = ctx.alloc().buffer();
ENCODE_BUFFER.invoke(vanillaEncoder, ctx, packet, packetBuffer); encodeBuffer.invoke(vanillaEncoder, ctx, packet, packetBuffer);
// Let each handler prepare the actual output // Let each handler prepare the actual output
byte[] data = processor.processOutput(event, marker, getBytes(packetBuffer)); byte[] data = processor.processOutput(event, marker, getBytes(packetBuffer));
@ -470,7 +470,7 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
// Attempt to handle the packet nevertheless // Attempt to handle the packet nevertheless
if (packet != null) { if (packet != null) {
try { try {
ENCODE_BUFFER.invoke(vanillaEncoder, ctx, packet, output); encodeBuffer.invoke(vanillaEncoder, ctx, packet, output);
} catch (InvocationTargetException ex) { } catch (InvocationTargetException ex) {
if (ex.getCause() instanceof Exception) { if (ex.getCause() instanceof Exception) {
//noinspection ThrowFromFinallyBlock //noinspection ThrowFromFinallyBlock
@ -510,7 +510,12 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
@Override @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuffer, List<Object> packets) throws Exception { protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuffer, List<Object> packets) throws Exception {
try { try {
DECODE_BUFFER.invoke(vanillaDecoder, ctx, byteBuffer, packets); try {
decodeBuffer.invoke(vanillaDecoder, ctx, byteBuffer, packets);
} catch (IllegalArgumentException ex) {
updateBufferMethods();
decodeBuffer.invoke(vanillaDecoder, ctx, byteBuffer, packets);
}
// Reset queue // Reset queue
finishQueue.clear(); finishQueue.clear();