From 20999308de7b2f56780bb4d20a6ca0b96864f8bc Mon Sep 17 00:00:00 2001 From: VendoAU Date: Mon, 14 Oct 2024 19:50:31 +1100 Subject: [PATCH 1/3] Fix server side for fabric --- .../event/ProtocolPacketEvent.java | 7 +- .../fabric/FabricPacketEventsBuilder.java | 46 +++-- ...er.java => PacketEventsClientDecoder.java} | 28 +-- ...er.java => PacketEventsClientEncoder.java} | 4 +- .../handler/PacketEventsServerDecoder.java | 95 +++++++++ .../handler/PacketEventsServerEncoder.java | 184 ++++++++++++++++++ .../injector/CustomPipelineUtil.java | 86 ++++++++ .../ServerConnectionInitializer.java | 105 ++++++++++ .../mixin/PacketEventsInjectorMixin.java | 23 ++- 9 files changed, 538 insertions(+), 40 deletions(-) rename fabric/src/main/java/io/github/retrooper/packetevents/handler/{PacketDecoder.java => PacketEventsClientDecoder.java} (69%) rename fabric/src/main/java/io/github/retrooper/packetevents/handler/{PacketEncoder.java => PacketEventsClientEncoder.java} (94%) create mode 100644 fabric/src/main/java/io/github/retrooper/packetevents/handler/PacketEventsServerDecoder.java create mode 100644 fabric/src/main/java/io/github/retrooper/packetevents/handler/PacketEventsServerEncoder.java create mode 100644 fabric/src/main/java/io/github/retrooper/packetevents/injector/CustomPipelineUtil.java create mode 100644 fabric/src/main/java/io/github/retrooper/packetevents/injector/connection/ServerConnectionInitializer.java diff --git a/api/src/main/java/com/github/retrooper/packetevents/event/ProtocolPacketEvent.java b/api/src/main/java/com/github/retrooper/packetevents/event/ProtocolPacketEvent.java index b4968b81b3..7975925c70 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/event/ProtocolPacketEvent.java +++ b/api/src/main/java/com/github/retrooper/packetevents/event/ProtocolPacketEvent.java @@ -86,7 +86,12 @@ public ProtocolPacketEvent(PacketSide packetSide, Object channel, if (PacketType.getById(packetSide, ConnectionState.PLAY, version, packetID) == PacketType.Play.Server.DISCONNECT) { throw new InvalidDisconnectPacketSend(); } - throw new PacketProcessException("Failed to map the Packet ID " + packetID + " to a PacketType constant. Bound: " + packetSide.getOpposite() + ", Connection state: " + user.getDecoderState() + ", Server version: " + serverVersion.getReleaseName()); + try { + throw new PacketProcessException("Failed to map the Packet ID " + packetID + " to a PacketType constant. Bound: " + packetSide.getOpposite() + ", Connection state: " + user.getDecoderState() + ", Server version: " + serverVersion.getReleaseName()); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } } this.connectionState = state; } diff --git a/fabric/src/main/java/io/github/retrooper/packetevents/factory/fabric/FabricPacketEventsBuilder.java b/fabric/src/main/java/io/github/retrooper/packetevents/factory/fabric/FabricPacketEventsBuilder.java index faf3f9f85e..14423f076d 100644 --- a/fabric/src/main/java/io/github/retrooper/packetevents/factory/fabric/FabricPacketEventsBuilder.java +++ b/fabric/src/main/java/io/github/retrooper/packetevents/factory/fabric/FabricPacketEventsBuilder.java @@ -19,18 +19,23 @@ import com.github.retrooper.packetevents.util.LogManager; import com.github.retrooper.packetevents.util.mappings.GlobalRegistryHolder; import com.github.retrooper.packetevents.util.reflection.ReflectionObject; -import io.github.retrooper.packetevents.handler.PacketDecoder; -import io.github.retrooper.packetevents.handler.PacketEncoder; +import io.github.retrooper.packetevents.handler.PacketEventsClientDecoder; +import io.github.retrooper.packetevents.handler.PacketEventsClientEncoder; +import io.github.retrooper.packetevents.handler.PacketEventsServerDecoder; +import io.github.retrooper.packetevents.handler.PacketEventsServerEncoder; import io.github.retrooper.packetevents.impl.netty.NettyManagerImpl; import io.github.retrooper.packetevents.impl.netty.manager.player.PlayerManagerAbstract; import io.github.retrooper.packetevents.impl.netty.manager.protocol.ProtocolManagerAbstract; import io.github.retrooper.packetevents.impl.netty.manager.server.ServerManagerAbstract; +import io.github.retrooper.packetevents.injector.CustomPipelineUtil; import io.netty.channel.Channel; import net.kyori.adventure.text.format.NamedTextColor; import net.minecraft.SharedConstants; import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; import net.minecraft.network.Connection; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.player.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -100,9 +105,13 @@ public Object getRegistryCacheKey(User user, ClientVersion version) { private final PlayerManagerAbstract playerManager = new PlayerManagerAbstract() { @Override public int getPing(@NotNull Object player) { - String name = ((LocalPlayer) player).getGameProfile().getName(); + String name = ((Player) player).getGameProfile().getName(); try { - return ((LocalPlayer) player).connection.getPlayerInfo(name).getLatency(); + if (player instanceof LocalPlayer localPlayer) { + return localPlayer.connection.getPlayerInfo(name).getLatency(); + } else { + return ((ServerPlayer) player).connection.latency(); + } } catch (Exception ex) { PacketEvents.getAPI().getLogManager().debug("Failed to get ping for player " + name); return -1; @@ -136,20 +145,29 @@ public void uninject() { @Override public void updateUser(Object ch, User user) { Channel channel = (Channel) ch; - PacketDecoder decoder = (PacketDecoder) channel.pipeline().get(PacketEvents.DECODER_NAME); + PacketEventsServerDecoder decoder = (PacketEventsServerDecoder) channel.pipeline().get(PacketEvents.DECODER_NAME); decoder.user = user; - PacketEncoder encoder = (PacketEncoder) channel.pipeline().get(PacketEvents.ENCODER_NAME); + PacketEventsServerEncoder encoder = (PacketEventsServerEncoder) channel.pipeline().get(PacketEvents.ENCODER_NAME); encoder.user = user; } @Override public void setPlayer(Object ch, Object player) { Channel channel = (Channel) ch; - PacketDecoder decoder = (PacketDecoder) channel.pipeline().get(PacketEvents.DECODER_NAME); - decoder.player = (LocalPlayer) player; - PacketEncoder encoder = (PacketEncoder) channel.pipeline().get(PacketEvents.ENCODER_NAME); - encoder.player = (LocalPlayer) player; + if (player instanceof LocalPlayer localPlayer) { + PacketEventsClientDecoder decoder = (PacketEventsClientDecoder) channel.pipeline().get(PacketEvents.DECODER_NAME); + decoder.player = localPlayer; + + PacketEventsClientEncoder encoder = (PacketEventsClientEncoder) channel.pipeline().get(PacketEvents.ENCODER_NAME); + encoder.player = localPlayer; + } else if (player instanceof ServerPlayer serverPlayer) { + PacketEventsServerDecoder decoder = (PacketEventsServerDecoder) channel.pipeline().get(PacketEvents.DECODER_NAME); + decoder.player = serverPlayer; + + PacketEventsServerEncoder encoder = (PacketEventsServerEncoder) channel.pipeline().get(PacketEvents.ENCODER_NAME); + encoder.player = serverPlayer; + } } @Override @@ -181,6 +199,12 @@ public void load() { PacketEvents.CONNECTION_HANDLER_NAME = "pe-connection-handler-" + id; PacketEvents.SERVER_CHANNEL_HANDLER_NAME = "pe-connection-initializer-" + id; + try { + CustomPipelineUtil.init(); + } catch (Exception ex) { + throw new IllegalStateException(ex); + } + injector.inject(); loaded = true; @@ -194,7 +218,7 @@ public void load() { public void onPacketPlaySend(PacketPlaySendEvent event) { if (event.getPacketType() == PacketType.Play.Server.JOIN_GAME) { PacketEvents.getAPI().getInjector().setPlayer(event.getChannel(), - Minecraft.getInstance().player); + event.getPlayer()); } } }); diff --git a/fabric/src/main/java/io/github/retrooper/packetevents/handler/PacketDecoder.java b/fabric/src/main/java/io/github/retrooper/packetevents/handler/PacketEventsClientDecoder.java similarity index 69% rename from fabric/src/main/java/io/github/retrooper/packetevents/handler/PacketDecoder.java rename to fabric/src/main/java/io/github/retrooper/packetevents/handler/PacketEventsClientDecoder.java index c49c717296..790a241cc9 100644 --- a/fabric/src/main/java/io/github/retrooper/packetevents/handler/PacketDecoder.java +++ b/fabric/src/main/java/io/github/retrooper/packetevents/handler/PacketEventsClientDecoder.java @@ -3,26 +3,23 @@ import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.protocol.player.User; import com.github.retrooper.packetevents.util.PacketEventsImplHelper; +import io.github.retrooper.packetevents.injector.CustomPipelineUtil; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.MessageToMessageDecoder; import net.minecraft.client.player.LocalPlayer; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; import java.util.List; @ChannelHandler.Sharable -public class PacketDecoder extends MessageToMessageDecoder { - private static Method DECOMPRESSOR_METHOD, COMPRESSOR_METHOD; +public class PacketEventsClientDecoder extends MessageToMessageDecoder { public User user; public LocalPlayer player; public boolean checkedCompression; - public PacketDecoder(User user) { + public PacketEventsClientDecoder(User user) { this.user = user; } @@ -54,11 +51,7 @@ private boolean handleCompression(ChannelHandlerContext ctx, ByteBuf buffer) { ChannelHandler decompressor = ctx.pipeline().get("decompress"); //CompressionDecoder try { - if (DECOMPRESSOR_METHOD == null) { - DECOMPRESSOR_METHOD = decompressor.getClass().getDeclaredMethod("decode", ChannelHandlerContext.class, ByteBuf.class, List.class); - } - List list = new ArrayList<>(1); - DECOMPRESSOR_METHOD.invoke(decompressor, ctx, buffer, list); + List list = CustomPipelineUtil.callDecode(decompressor, ctx, buffer); ByteBuf decompressed = (ByteBuf) list.get(0); if (buffer != decompressed) { try { @@ -68,13 +61,13 @@ private boolean handleCompression(ChannelHandlerContext ctx, ByteBuf buffer) { } } //Relocate handlers - PacketDecoder decoder = (PacketDecoder) ctx.pipeline().remove(PacketEvents.DECODER_NAME); + PacketEventsClientDecoder decoder = (PacketEventsClientDecoder) ctx.pipeline().remove(PacketEvents.DECODER_NAME); ctx.pipeline().addAfter("decompress", PacketEvents.DECODER_NAME, decoder); - PacketEncoder encoder = (PacketEncoder) ctx.pipeline().remove(PacketEvents.ENCODER_NAME); + PacketEventsClientEncoder encoder = (PacketEventsClientEncoder) ctx.pipeline().remove(PacketEvents.ENCODER_NAME); ctx.pipeline().addAfter("compress", PacketEvents.ENCODER_NAME, encoder); checkedCompression = true; return true; - } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) { + } catch (InvocationTargetException e) { e.printStackTrace(); } } @@ -85,11 +78,8 @@ private void recompress(ChannelHandlerContext ctx, ByteBuf buffer) { ByteBuf compressed = ctx.alloc().buffer(); try { ChannelHandler compressor = ctx.pipeline().get("compress"); - if (COMPRESSOR_METHOD == null) { - COMPRESSOR_METHOD = compressor.getClass().getDeclaredMethod("encode", ChannelHandlerContext.class, ByteBuf.class, ByteBuf.class); - } - COMPRESSOR_METHOD.invoke(compressor, ctx, buffer, compressed); - } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) { + CustomPipelineUtil.callEncode(compressor, ctx, buffer, compressed); + } catch (InvocationTargetException e) { e.printStackTrace(); } try { diff --git a/fabric/src/main/java/io/github/retrooper/packetevents/handler/PacketEncoder.java b/fabric/src/main/java/io/github/retrooper/packetevents/handler/PacketEventsClientEncoder.java similarity index 94% rename from fabric/src/main/java/io/github/retrooper/packetevents/handler/PacketEncoder.java rename to fabric/src/main/java/io/github/retrooper/packetevents/handler/PacketEventsClientEncoder.java index e60c66e823..f2505a5aff 100644 --- a/fabric/src/main/java/io/github/retrooper/packetevents/handler/PacketEncoder.java +++ b/fabric/src/main/java/io/github/retrooper/packetevents/handler/PacketEventsClientEncoder.java @@ -12,11 +12,11 @@ import net.minecraft.client.player.LocalPlayer; @ChannelHandler.Sharable -public class PacketEncoder extends MessageToByteEncoder { +public class PacketEventsClientEncoder extends MessageToByteEncoder { public User user; public LocalPlayer player; - public PacketEncoder(User user) { + public PacketEventsClientEncoder(User user) { this.user = user; } diff --git a/fabric/src/main/java/io/github/retrooper/packetevents/handler/PacketEventsServerDecoder.java b/fabric/src/main/java/io/github/retrooper/packetevents/handler/PacketEventsServerDecoder.java new file mode 100644 index 0000000000..5810ac04c9 --- /dev/null +++ b/fabric/src/main/java/io/github/retrooper/packetevents/handler/PacketEventsServerDecoder.java @@ -0,0 +1,95 @@ +package io.github.retrooper.packetevents.handler; + +import com.github.retrooper.packetevents.PacketEvents; +import com.github.retrooper.packetevents.exception.PacketProcessException; +import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper; +import com.github.retrooper.packetevents.protocol.ConnectionState; +import com.github.retrooper.packetevents.protocol.player.User; +import com.github.retrooper.packetevents.util.ExceptionUtil; +import com.github.retrooper.packetevents.util.PacketEventsImplHelper; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerDisconnect; +import io.github.retrooper.packetevents.injector.connection.ServerConnectionInitializer; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageDecoder; +import net.kyori.adventure.text.Component; +import net.minecraft.server.level.ServerPlayer; + +import java.util.List; + +@ChannelHandler.Sharable +public class PacketEventsServerDecoder extends MessageToMessageDecoder { + public User user; + public ServerPlayer player; + public boolean hasBeenRelocated; + + public PacketEventsServerDecoder(User user) { + this.user = user; + } + + public PacketEventsServerDecoder(PacketEventsServerDecoder decoder) { + user = decoder.user; + player = decoder.player; + hasBeenRelocated = decoder.hasBeenRelocated; + } + + public void read(ChannelHandlerContext ctx, ByteBuf input, List out) throws Exception { + Object buffer = PacketEventsImplHelper.handleServerBoundPacket(ctx.channel(), user, player, input, true); + out.add(ByteBufHelper.retain(buffer)); + } + + @Override + public void decode(ChannelHandlerContext ctx, ByteBuf buffer, List out) throws Exception { + if (buffer.isReadable()) { + read(ctx, buffer, out); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + super.exceptionCaught(ctx, cause); + //Check if the minecraft server will already print our exception for us. + //Don't print errors during handshake + boolean didWeCauseThis = ExceptionUtil.isException(cause, PacketProcessException.class); + if (didWeCauseThis + && (user == null || user.getDecoderState() != ConnectionState.HANDSHAKING)) { + if (PacketEvents.getAPI().getSettings().isFullStackTraceEnabled()) { + cause.printStackTrace(); + } else { + PacketEvents.getAPI().getLogManager().warn(cause.getMessage()); + } + + if (PacketEvents.getAPI().getSettings().isKickOnPacketExceptionEnabled()) { + try { + if (user != null) { + user.sendPacket(new WrapperPlayServerDisconnect(Component.text("Invalid packet"))); + } + } catch (Exception ignored) { // There may (?) be an exception if the player is in the wrong state... + // Do nothing. + } + ctx.channel().close(); + if (player != null) { + player.connection.disconnect(net.minecraft.network.chat.Component.literal("Invalid packet")); + } + + if (user != null) { + PacketEvents.getAPI().getLogManager().warn("Disconnected " + user.getProfile().getName() + " due to invalid packet!"); + } + } + } + } + + @Override + public void userEventTriggered(final ChannelHandlerContext ctx, final Object event) throws Exception { + if (PacketEventsServerEncoder.COMPRESSION_ENABLED_EVENT == null || event != PacketEventsServerEncoder.COMPRESSION_ENABLED_EVENT) { + super.userEventTriggered(ctx, event); + return; + } + + // Via changes the order of handlers in this event, so we must respond to Via changing their stuff + ServerConnectionInitializer.relocateHandlers(ctx.channel(), this, user); + super.userEventTriggered(ctx, event); + } + +} diff --git a/fabric/src/main/java/io/github/retrooper/packetevents/handler/PacketEventsServerEncoder.java b/fabric/src/main/java/io/github/retrooper/packetevents/handler/PacketEventsServerEncoder.java new file mode 100644 index 0000000000..d3a3dee620 --- /dev/null +++ b/fabric/src/main/java/io/github/retrooper/packetevents/handler/PacketEventsServerEncoder.java @@ -0,0 +1,184 @@ +package io.github.retrooper.packetevents.handler; + +import com.github.retrooper.packetevents.PacketEvents; +import com.github.retrooper.packetevents.event.PacketSendEvent; +import com.github.retrooper.packetevents.exception.CancelPacketException; +import com.github.retrooper.packetevents.exception.InvalidDisconnectPacketSend; +import com.github.retrooper.packetevents.exception.PacketProcessException; +import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper; +import com.github.retrooper.packetevents.protocol.ConnectionState; +import com.github.retrooper.packetevents.protocol.player.User; +import com.github.retrooper.packetevents.util.ExceptionUtil; +import com.github.retrooper.packetevents.util.PacketEventsImplHelper; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerDisconnect; +import io.github.retrooper.packetevents.injector.CustomPipelineUtil; +import io.github.retrooper.packetevents.injector.connection.ServerConnectionInitializer; +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPromise; +import io.netty.handler.codec.MessageToMessageEncoder; +import net.kyori.adventure.text.Component; +import net.minecraft.server.level.ServerPlayer; + +import java.lang.reflect.InvocationTargetException; +import java.util.List; + +@ChannelHandler.Sharable +public class PacketEventsServerEncoder extends MessageToMessageEncoder { + public User user; + public ServerPlayer player; + private boolean handledCompression = COMPRESSION_ENABLED_EVENT != null; + private ChannelPromise promise; + public static final Object COMPRESSION_ENABLED_EVENT = paperCompressionEnabledEvent(); + + public PacketEventsServerEncoder(User user) { + this.user = user; + } + + public PacketEventsServerEncoder(ChannelHandler encoder) { + user = ((PacketEventsServerEncoder) encoder).user; + player = ((PacketEventsServerEncoder) encoder).player; + handledCompression = ((PacketEventsServerEncoder) encoder).handledCompression; + promise = ((PacketEventsServerEncoder) encoder).promise; + } + + @Override + protected void encode(ChannelHandlerContext ctx, ByteBuf byteBuf, List list) throws Exception { + handleClientBoundPacket(ctx.channel(), user, player, byteBuf, this.promise); + + boolean needsRecompression = !handledCompression && handleCompression(ctx, byteBuf); + if (needsRecompression) { + compress(ctx, byteBuf); + } + + // So apparently, this is how ViaVersion hacks around bungeecord not supporting sending empty packets + if (!ByteBufHelper.isReadable(byteBuf)) { + throw CancelPacketException.INSTANCE; + } + + list.add(byteBuf.retain()); + } + + private PacketSendEvent handleClientBoundPacket(Channel channel, User user, Object player, ByteBuf buffer, ChannelPromise promise) throws Exception { + PacketSendEvent packetSendEvent = PacketEventsImplHelper.handleClientBoundPacket(channel, user, player, buffer, true); + if (packetSendEvent.hasTasksAfterSend()) { + promise.addListener((p) -> { + for (Runnable task : packetSendEvent.getTasksAfterSend()) { + task.run(); + } + }); + } + return packetSendEvent; + } + + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + // We must restore the old promise (in case we are stacking promises such as sending packets on send event) + // If the old promise was successful, set it to null to avoid memory leaks. + ChannelPromise oldPromise = this.promise != null && !this.promise.isSuccess() ? this.promise : null; + promise.addListener(p -> this.promise = oldPromise); + + this.promise = promise; + super.write(ctx, msg, promise); + } + + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + // This is a terrible hack (to support bungee), I think we should use something other than a MessageToMessageEncoder + if (ExceptionUtil.isException(cause, CancelPacketException.class)) { + return; + } + // Ignore how mojang sends DISCONNECT packets in the wrong state + if (ExceptionUtil.isException(cause, InvalidDisconnectPacketSend.class)) { + return; + } + + boolean didWeCauseThis = ExceptionUtil.isException(cause, PacketProcessException.class); + if (didWeCauseThis + && (user == null || user.getEncoderState() != ConnectionState.HANDSHAKING)) { + if (PacketEvents.getAPI().getSettings().isFullStackTraceEnabled()) { + cause.printStackTrace(); + } else { + PacketEvents.getAPI().getLogManager().warn(cause.getMessage()); + } + + if (PacketEvents.getAPI().getSettings().isKickOnPacketExceptionEnabled()) { + try { + if (user != null) { + user.sendPacket(new WrapperPlayServerDisconnect(Component.text("Invalid packet"))); + } + } catch (Exception ignored) { // There may (?) be an exception if the player is in the wrong state... + // Do nothing. + } + ctx.channel().close(); + if (player != null) { + ((ServerPlayer) player).connection.disconnect(net.minecraft.network.chat.Component.literal("Invalid packet")); + } + + if (user != null) { + PacketEvents.getAPI().getLogManager().warn("Disconnected " + user.getProfile().getName() + " due to invalid packet!"); + } + } + } + + super.exceptionCaught(ctx, cause); + } + + private static Object paperCompressionEnabledEvent() { + // FIXME + /*try { + final Class eventClass = Class.forName("io.papermc.paper.network.ConnectionEvent"); + return eventClass.getDeclaredField("COMPRESSION_THRESHOLD_SET").get(null); + } catch (final ReflectiveOperationException e) { + return null; + }*/ + return null; + } + + private void compress(ChannelHandlerContext ctx, ByteBuf input) throws InvocationTargetException { + ChannelHandler compressor = ctx.pipeline().get("compress"); + ByteBuf temp = ctx.alloc().buffer(); + try { + if (compressor != null) { + CustomPipelineUtil.callEncode(compressor, ctx, input, temp); + } + } finally { + input.clear().writeBytes(temp); + temp.release(); + } + } + + private void decompress(ChannelHandlerContext ctx, ByteBuf input, ByteBuf output) throws InvocationTargetException { + ChannelHandler decompressor = ctx.pipeline().get("decompress"); + if (decompressor != null) { + ByteBuf temp = (ByteBuf) CustomPipelineUtil.callDecode(decompressor, ctx, input).get(0); + try { + output.clear().writeBytes(temp); + } finally { + temp.release(); + } + } + } + + private boolean handleCompression(ChannelHandlerContext ctx, ByteBuf buffer) throws InvocationTargetException { + if (handledCompression) return false; + int compressIndex = ctx.pipeline().names().indexOf("compress"); + if (compressIndex == -1) return false; + handledCompression = true; + int peEncoderIndex = ctx.pipeline().names().indexOf(PacketEvents.ENCODER_NAME); + if (peEncoderIndex == -1) return false; + if (compressIndex > peEncoderIndex) { + //We are ahead of the decompression handler (they are added dynamically) so let us relocate. + //But first we need to compress the data and re-compress it after we do all our processing to avoid issues. + decompress(ctx, buffer, buffer); + //Let us relocate and no longer deal with compression. + PacketEventsServerDecoder decoder = (PacketEventsServerDecoder) ctx.pipeline().get(PacketEvents.DECODER_NAME); + ServerConnectionInitializer.relocateHandlers(ctx.channel(), decoder, user); + return true; + } + return false; + } +} diff --git a/fabric/src/main/java/io/github/retrooper/packetevents/injector/CustomPipelineUtil.java b/fabric/src/main/java/io/github/retrooper/packetevents/injector/CustomPipelineUtil.java new file mode 100644 index 0000000000..81dd188ffd --- /dev/null +++ b/fabric/src/main/java/io/github/retrooper/packetevents/injector/CustomPipelineUtil.java @@ -0,0 +1,86 @@ +package io.github.retrooper.packetevents.injector; + +import com.github.retrooper.packetevents.util.reflection.Reflection; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +public class CustomPipelineUtil { + private static Method DECODE_METHOD; + private static Method ENCODE_METHOD; + private static Method MTM_DECODE; + private static Method MTM_ENCODE; + + public static void init() { + try { + Class compressionDecoderClass = Reflection.getClassByNameWithoutException("net.minecraft.network.CompressionDecoder"); + DECODE_METHOD = compressionDecoderClass.getDeclaredMethod("decode", ChannelHandlerContext.class, ByteBuf.class, List.class); + DECODE_METHOD.setAccessible(true); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } + try { + Class compressionDecoderClass = Reflection.getClassByNameWithoutException("net.minecraft.network.CompressionEncoder"); + ENCODE_METHOD = compressionDecoderClass.getDeclaredMethod("encode", ChannelHandlerContext.class, ByteBuf.class, ByteBuf.class); + ENCODE_METHOD.setAccessible(true); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } + try { + Class messageToMessageDecoderClass = Reflection.getClassByNameWithoutException("io.netty.handler.codec.MessageToMessageDecoder"); + MTM_DECODE = messageToMessageDecoderClass.getDeclaredMethod("decode", ChannelHandlerContext.class, Object.class, List.class); + MTM_DECODE.setAccessible(true); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } + try { + Class messageToMessageDecoderClass = Reflection.getClassByNameWithoutException("io.netty.handler.codec.MessageToMessageEncoder"); + MTM_ENCODE = messageToMessageDecoderClass.getDeclaredMethod("encode", ChannelHandlerContext.class, Object.class, List.class); + MTM_ENCODE.setAccessible(true); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } + } + + public static List callDecode(Object decoder, Object ctx, Object input) throws InvocationTargetException { + List output = new ArrayList<>(); + try { + CustomPipelineUtil.DECODE_METHOD.invoke(decoder, ctx, input, output); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + return output; + } + + public static void callEncode(Object encoder, Object ctx, Object msg, Object output) throws InvocationTargetException { + try { + CustomPipelineUtil.ENCODE_METHOD.invoke(encoder, ctx, msg, output); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + + public static List callMTMEncode(Object encoder, Object ctx, Object msg) { + List output = new ArrayList<>(); + try { + MTM_ENCODE.invoke(encoder, ctx, msg, output); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + return output; + } + + public static List callMTMDecode(Object decoder, Object ctx, Object msg) throws InvocationTargetException { + List output = new ArrayList<>(); + try { + MTM_DECODE.invoke(decoder, ctx, msg, output); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + return output; + } +} diff --git a/fabric/src/main/java/io/github/retrooper/packetevents/injector/connection/ServerConnectionInitializer.java b/fabric/src/main/java/io/github/retrooper/packetevents/injector/connection/ServerConnectionInitializer.java new file mode 100644 index 0000000000..d4757f0d01 --- /dev/null +++ b/fabric/src/main/java/io/github/retrooper/packetevents/injector/connection/ServerConnectionInitializer.java @@ -0,0 +1,105 @@ +package io.github.retrooper.packetevents.injector.connection; + +import com.github.retrooper.packetevents.PacketEvents; +import com.github.retrooper.packetevents.event.UserConnectEvent; +import com.github.retrooper.packetevents.netty.channel.ChannelHelper; +import com.github.retrooper.packetevents.protocol.ConnectionState; +import com.github.retrooper.packetevents.protocol.player.User; +import com.github.retrooper.packetevents.protocol.player.UserProfile; +import com.github.retrooper.packetevents.util.FakeChannelUtil; +import com.github.retrooper.packetevents.util.PacketEventsImplHelper; +import io.github.retrooper.packetevents.handler.PacketEventsServerDecoder; +import io.github.retrooper.packetevents.handler.PacketEventsServerEncoder; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandler; + +import java.util.NoSuchElementException; + +public class ServerConnectionInitializer { + public static void initChannel(Object ch, ConnectionState connectionState) { + Channel channel = (Channel) ch; + if (FakeChannelUtil.isFakeChannel(channel)) { + return; + } + User user = new User(channel, connectionState, null, new UserProfile(null, null)); + + if (connectionState == ConnectionState.PLAY) { + // Player connected before ViaVersion init, therefore the player is server version (mostly true except 1.7 servers) + user.setClientVersion(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion()); + PacketEvents.getAPI().getLogManager().warn("Late injection detected, we missed packets so some functionality may break!"); + } + + synchronized (channel) { + /* + * This is a rather rare one, BUT! + * If the plugin takes a while to initialize and handshakes/pings pile up, + * some may not be handled completely, thus, not having a 'splitter' ChannelHandler. + * We can, of course, wait for them to be handled, but this complexes the algorithm. + * Taken the above into account, here we just drop all unhandled connections. + */ + if (channel.pipeline().get("splitter") == null) { + channel.close(); + return; + } + + UserConnectEvent connectEvent = new UserConnectEvent(user); + PacketEvents.getAPI().getEventManager().callEvent(connectEvent); + if (connectEvent.isCancelled()) { + channel.unsafe().closeForcibly(); + return; + } + + relocateHandlers(channel, null, user); + + channel.closeFuture().addListener((ChannelFutureListener) future -> PacketEventsImplHelper.handleDisconnection(user.getChannel(), user.getUUID())); + PacketEvents.getAPI().getProtocolManager().setUser(channel, user); + } + } + + public static void destroyHandlers(Object ch) { + Channel channel = (Channel) ch; + if (channel.pipeline().get(PacketEvents.DECODER_NAME) != null) { + channel.pipeline().remove(PacketEvents.DECODER_NAME); + } else { + PacketEvents.getAPI().getLogger().warning("Could not find decoder handler in channel pipeline!"); + } + + if (channel.pipeline().get(PacketEvents.ENCODER_NAME) != null) { + channel.pipeline().remove(PacketEvents.ENCODER_NAME); + } else { + PacketEvents.getAPI().getLogger().warning("Could not find encoder handler in channel pipeline!"); + } + } + + public static void relocateHandlers(Channel ctx, PacketEventsServerDecoder decoder, User user) { + // Decoder == null means we haven't made handlers for the user yet + try { + ChannelHandler encoder; + if (decoder != null) { + // This patches a bug where PE 2.0 handlers keep jumping behind one another causing a stackoverflow + if (decoder.hasBeenRelocated) return; + // Make sure we only relocate because of compression once + decoder.hasBeenRelocated = true; + decoder = (PacketEventsServerDecoder) ctx.pipeline().remove(PacketEvents.DECODER_NAME); + encoder = ctx.pipeline().remove(PacketEvents.ENCODER_NAME); + decoder = new PacketEventsServerDecoder(decoder); + encoder = new PacketEventsServerEncoder(encoder); + } else { + encoder = new PacketEventsServerEncoder(user); + decoder = new PacketEventsServerDecoder(user); + } + // We are targeting the encoder and decoder since we don't want to target specific plugins + // (ProtocolSupport has changed its handler name in the past) + // I don't like the hacks required for compression but that's on vanilla, we can't fix it. + // TODO: i think this will only work for server-side packetevents? + String decoderName = ctx.pipeline().names().contains("inbound_config") ? "inbound_config" : "decoder"; + ctx.pipeline().addBefore(decoderName, PacketEvents.DECODER_NAME, decoder); + String encoderName = ctx.pipeline().names().contains("outbound_config") ? "outbound_config" : "encoder"; + ctx.pipeline().addBefore(encoderName, PacketEvents.ENCODER_NAME, encoder); + } catch (NoSuchElementException ex) { + String handlers = ChannelHelper.pipelineHandlerNamesAsString(ctx); + throw new IllegalStateException("PacketEvents failed to add a decoder to the netty pipeline. Pipeline handlers: " + handlers, ex); + } + } +} diff --git a/fabric/src/main/java/io/github/retrooper/packetevents/mixin/PacketEventsInjectorMixin.java b/fabric/src/main/java/io/github/retrooper/packetevents/mixin/PacketEventsInjectorMixin.java index 884c92df48..c6e50c1a23 100644 --- a/fabric/src/main/java/io/github/retrooper/packetevents/mixin/PacketEventsInjectorMixin.java +++ b/fabric/src/main/java/io/github/retrooper/packetevents/mixin/PacketEventsInjectorMixin.java @@ -8,11 +8,13 @@ import com.github.retrooper.packetevents.protocol.player.User; import com.github.retrooper.packetevents.protocol.player.UserProfile; import com.github.retrooper.packetevents.util.PacketEventsImplHelper; -import io.github.retrooper.packetevents.PacketEventsMod; -import io.github.retrooper.packetevents.handler.PacketDecoder; -import io.github.retrooper.packetevents.handler.PacketEncoder; +import io.github.retrooper.packetevents.handler.PacketEventsClientDecoder; +import io.github.retrooper.packetevents.handler.PacketEventsClientEncoder; +import io.github.retrooper.packetevents.handler.PacketEventsServerDecoder; +import io.github.retrooper.packetevents.handler.PacketEventsServerEncoder; import io.netty.channel.Channel; import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelPipeline; import net.minecraft.network.BandwidthDebugMonitor; import net.minecraft.network.protocol.PacketFlow; @@ -21,8 +23,6 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.util.Arrays; - @Mixin(net.minecraft.network.Connection.class) public class PacketEventsInjectorMixin { @@ -40,8 +40,17 @@ private static void configureSerialization(ChannelPipeline pipeline, PacketFlow channel.unsafe().closeForcibly(); return; } - PacketDecoder decoder = new PacketDecoder(user); - PacketEncoder encoder = new PacketEncoder(user); + + ChannelHandler decoder; + ChannelHandler encoder; + if (flow == PacketFlow.CLIENTBOUND) { + decoder = new PacketEventsClientDecoder(user); + encoder = new PacketEventsClientEncoder(user); + } else { + decoder = new PacketEventsServerDecoder(user); + encoder = new PacketEventsServerEncoder(user); + } + channel.pipeline().addAfter("splitter", PacketEvents.DECODER_NAME, decoder); channel.pipeline().addAfter("prepender", PacketEvents.ENCODER_NAME, encoder); channel.closeFuture().addListener((ChannelFutureListener) future -> PacketEventsImplHelper.handleDisconnection(user.getChannel(), user.getUUID())); From 92a62913989497f3d352a3ee3f64c59d5ed07966 Mon Sep 17 00:00:00 2001 From: VendoAU Date: Tue, 15 Oct 2024 00:55:26 +1100 Subject: [PATCH 2/3] Remove weird exception print and rethrow --- .../retrooper/packetevents/event/ProtocolPacketEvent.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/api/src/main/java/com/github/retrooper/packetevents/event/ProtocolPacketEvent.java b/api/src/main/java/com/github/retrooper/packetevents/event/ProtocolPacketEvent.java index 7975925c70..b4968b81b3 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/event/ProtocolPacketEvent.java +++ b/api/src/main/java/com/github/retrooper/packetevents/event/ProtocolPacketEvent.java @@ -86,12 +86,7 @@ public ProtocolPacketEvent(PacketSide packetSide, Object channel, if (PacketType.getById(packetSide, ConnectionState.PLAY, version, packetID) == PacketType.Play.Server.DISCONNECT) { throw new InvalidDisconnectPacketSend(); } - try { - throw new PacketProcessException("Failed to map the Packet ID " + packetID + " to a PacketType constant. Bound: " + packetSide.getOpposite() + ", Connection state: " + user.getDecoderState() + ", Server version: " + serverVersion.getReleaseName()); - } catch (Exception e) { - e.printStackTrace(); - throw e; - } + throw new PacketProcessException("Failed to map the Packet ID " + packetID + " to a PacketType constant. Bound: " + packetSide.getOpposite() + ", Connection state: " + user.getDecoderState() + ", Server version: " + serverVersion.getReleaseName()); } this.connectionState = state; } From 5122804dcbd7a90247d28c410fa8db1d0eefce8b Mon Sep 17 00:00:00 2001 From: VendoAU Date: Tue, 15 Oct 2024 01:43:08 +1100 Subject: [PATCH 3/3] Convert reflection to mixin invokers --- .../fabric/FabricPacketEventsBuilder.java | 6 -- .../handler/PacketEventsClientDecoder.java | 40 ++++------ .../injector/CustomPipelineUtil.java | 74 +++---------------- .../mixin/CompressionDecoderInvoker.java | 15 ++++ .../mixin/CompressionEncoderInvoker.java | 13 ++++ .../mixin/MessageToMessageDecoderInvoker.java | 14 ++++ .../mixin/MessageToMessageEncoderInvoker.java | 14 ++++ .../main/resources/packetevents.mixins.json | 4 + 8 files changed, 88 insertions(+), 92 deletions(-) create mode 100644 fabric/src/main/java/io/github/retrooper/packetevents/mixin/CompressionDecoderInvoker.java create mode 100644 fabric/src/main/java/io/github/retrooper/packetevents/mixin/CompressionEncoderInvoker.java create mode 100644 fabric/src/main/java/io/github/retrooper/packetevents/mixin/MessageToMessageDecoderInvoker.java create mode 100644 fabric/src/main/java/io/github/retrooper/packetevents/mixin/MessageToMessageEncoderInvoker.java diff --git a/fabric/src/main/java/io/github/retrooper/packetevents/factory/fabric/FabricPacketEventsBuilder.java b/fabric/src/main/java/io/github/retrooper/packetevents/factory/fabric/FabricPacketEventsBuilder.java index 14423f076d..4b76894e8d 100644 --- a/fabric/src/main/java/io/github/retrooper/packetevents/factory/fabric/FabricPacketEventsBuilder.java +++ b/fabric/src/main/java/io/github/retrooper/packetevents/factory/fabric/FabricPacketEventsBuilder.java @@ -199,12 +199,6 @@ public void load() { PacketEvents.CONNECTION_HANDLER_NAME = "pe-connection-handler-" + id; PacketEvents.SERVER_CHANNEL_HANDLER_NAME = "pe-connection-initializer-" + id; - try { - CustomPipelineUtil.init(); - } catch (Exception ex) { - throw new IllegalStateException(ex); - } - injector.inject(); loaded = true; diff --git a/fabric/src/main/java/io/github/retrooper/packetevents/handler/PacketEventsClientDecoder.java b/fabric/src/main/java/io/github/retrooper/packetevents/handler/PacketEventsClientDecoder.java index 790a241cc9..d70fa9f1ae 100644 --- a/fabric/src/main/java/io/github/retrooper/packetevents/handler/PacketEventsClientDecoder.java +++ b/fabric/src/main/java/io/github/retrooper/packetevents/handler/PacketEventsClientDecoder.java @@ -50,38 +50,30 @@ private boolean handleCompression(ChannelHandlerContext ctx, ByteBuf buffer) { // Need to decompress this packet due to bad order ChannelHandler decompressor = ctx.pipeline().get("decompress"); //CompressionDecoder - try { - List list = CustomPipelineUtil.callDecode(decompressor, ctx, buffer); - ByteBuf decompressed = (ByteBuf) list.get(0); - if (buffer != decompressed) { - try { - buffer.clear().writeBytes(decompressed); - } finally { - decompressed.release(); - } + List list = CustomPipelineUtil.callDecode(decompressor, ctx, buffer); + ByteBuf decompressed = (ByteBuf) list.get(0); + if (buffer != decompressed) { + try { + buffer.clear().writeBytes(decompressed); + } finally { + decompressed.release(); } - //Relocate handlers - PacketEventsClientDecoder decoder = (PacketEventsClientDecoder) ctx.pipeline().remove(PacketEvents.DECODER_NAME); - ctx.pipeline().addAfter("decompress", PacketEvents.DECODER_NAME, decoder); - PacketEventsClientEncoder encoder = (PacketEventsClientEncoder) ctx.pipeline().remove(PacketEvents.ENCODER_NAME); - ctx.pipeline().addAfter("compress", PacketEvents.ENCODER_NAME, encoder); - checkedCompression = true; - return true; - } catch (InvocationTargetException e) { - e.printStackTrace(); } + //Relocate handlers + PacketEventsClientDecoder decoder = (PacketEventsClientDecoder) ctx.pipeline().remove(PacketEvents.DECODER_NAME); + ctx.pipeline().addAfter("decompress", PacketEvents.DECODER_NAME, decoder); + PacketEventsClientEncoder encoder = (PacketEventsClientEncoder) ctx.pipeline().remove(PacketEvents.ENCODER_NAME); + ctx.pipeline().addAfter("compress", PacketEvents.ENCODER_NAME, encoder); + checkedCompression = true; + return true; } return false; } private void recompress(ChannelHandlerContext ctx, ByteBuf buffer) { ByteBuf compressed = ctx.alloc().buffer(); - try { - ChannelHandler compressor = ctx.pipeline().get("compress"); - CustomPipelineUtil.callEncode(compressor, ctx, buffer, compressed); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } + ChannelHandler compressor = ctx.pipeline().get("compress"); + CustomPipelineUtil.callEncode(compressor, ctx, buffer, compressed); try { buffer.clear().writeBytes(compressed); PacketEvents.getAPI().getLogManager().debug("Recompressed packet!"); diff --git a/fabric/src/main/java/io/github/retrooper/packetevents/injector/CustomPipelineUtil.java b/fabric/src/main/java/io/github/retrooper/packetevents/injector/CustomPipelineUtil.java index 81dd188ffd..c4f3769b72 100644 --- a/fabric/src/main/java/io/github/retrooper/packetevents/injector/CustomPipelineUtil.java +++ b/fabric/src/main/java/io/github/retrooper/packetevents/injector/CustomPipelineUtil.java @@ -1,86 +1,36 @@ package io.github.retrooper.packetevents.injector; -import com.github.retrooper.packetevents.util.reflection.Reflection; +import io.github.retrooper.packetevents.mixin.CompressionDecoderInvoker; +import io.github.retrooper.packetevents.mixin.CompressionEncoderInvoker; +import io.github.retrooper.packetevents.mixin.MessageToMessageDecoderInvoker; +import io.github.retrooper.packetevents.mixin.MessageToMessageEncoderInvoker; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; public class CustomPipelineUtil { - private static Method DECODE_METHOD; - private static Method ENCODE_METHOD; - private static Method MTM_DECODE; - private static Method MTM_ENCODE; - public static void init() { - try { - Class compressionDecoderClass = Reflection.getClassByNameWithoutException("net.minecraft.network.CompressionDecoder"); - DECODE_METHOD = compressionDecoderClass.getDeclaredMethod("decode", ChannelHandlerContext.class, ByteBuf.class, List.class); - DECODE_METHOD.setAccessible(true); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } - try { - Class compressionDecoderClass = Reflection.getClassByNameWithoutException("net.minecraft.network.CompressionEncoder"); - ENCODE_METHOD = compressionDecoderClass.getDeclaredMethod("encode", ChannelHandlerContext.class, ByteBuf.class, ByteBuf.class); - ENCODE_METHOD.setAccessible(true); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } - try { - Class messageToMessageDecoderClass = Reflection.getClassByNameWithoutException("io.netty.handler.codec.MessageToMessageDecoder"); - MTM_DECODE = messageToMessageDecoderClass.getDeclaredMethod("decode", ChannelHandlerContext.class, Object.class, List.class); - MTM_DECODE.setAccessible(true); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } - try { - Class messageToMessageDecoderClass = Reflection.getClassByNameWithoutException("io.netty.handler.codec.MessageToMessageEncoder"); - MTM_ENCODE = messageToMessageDecoderClass.getDeclaredMethod("encode", ChannelHandlerContext.class, Object.class, List.class); - MTM_ENCODE.setAccessible(true); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } - } - - public static List callDecode(Object decoder, Object ctx, Object input) throws InvocationTargetException { + public static List callDecode(Object decoder, ChannelHandlerContext ctx, ByteBuf input) { List output = new ArrayList<>(); - try { - CustomPipelineUtil.DECODE_METHOD.invoke(decoder, ctx, input, output); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } + ((CompressionDecoderInvoker) decoder).invokeDecode(ctx, input, output); return output; } - public static void callEncode(Object encoder, Object ctx, Object msg, Object output) throws InvocationTargetException { - try { - CustomPipelineUtil.ENCODE_METHOD.invoke(encoder, ctx, msg, output); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } + public static void callEncode(Object encoder, ChannelHandlerContext ctx, ByteBuf msg, ByteBuf output) { + ((CompressionEncoderInvoker) encoder).invokeEncode(ctx, msg, output); } - public static List callMTMEncode(Object encoder, Object ctx, Object msg) { + public static List callMTMEncode(Object encoder, ChannelHandlerContext ctx, Object msg) { List output = new ArrayList<>(); - try { - MTM_ENCODE.invoke(encoder, ctx, msg, output); - } catch (IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); - } + ((MessageToMessageEncoderInvoker) encoder).invokeEncode(ctx, msg, output); return output; } - public static List callMTMDecode(Object decoder, Object ctx, Object msg) throws InvocationTargetException { + public static List callMTMDecode(Object decoder, ChannelHandlerContext ctx, Object msg) { List output = new ArrayList<>(); - try { - MTM_DECODE.invoke(decoder, ctx, msg, output); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } + ((MessageToMessageDecoderInvoker) decoder).invokeDecode(ctx, msg, output); return output; } } diff --git a/fabric/src/main/java/io/github/retrooper/packetevents/mixin/CompressionDecoderInvoker.java b/fabric/src/main/java/io/github/retrooper/packetevents/mixin/CompressionDecoderInvoker.java new file mode 100644 index 0000000000..0de8556198 --- /dev/null +++ b/fabric/src/main/java/io/github/retrooper/packetevents/mixin/CompressionDecoderInvoker.java @@ -0,0 +1,15 @@ +package io.github.retrooper.packetevents.mixin; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import net.minecraft.network.CompressionDecoder; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +import java.util.List; + +@Mixin(CompressionDecoder.class) +public interface CompressionDecoderInvoker { + @Invoker("decode") + void invokeDecode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List list); +} diff --git a/fabric/src/main/java/io/github/retrooper/packetevents/mixin/CompressionEncoderInvoker.java b/fabric/src/main/java/io/github/retrooper/packetevents/mixin/CompressionEncoderInvoker.java new file mode 100644 index 0000000000..6b3290677c --- /dev/null +++ b/fabric/src/main/java/io/github/retrooper/packetevents/mixin/CompressionEncoderInvoker.java @@ -0,0 +1,13 @@ +package io.github.retrooper.packetevents.mixin; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import net.minecraft.network.CompressionEncoder; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(CompressionEncoder.class) +public interface CompressionEncoderInvoker { + @Invoker("encode") + void invokeEncode(ChannelHandlerContext context, ByteBuf encodingByteBuf, ByteBuf byteBuf); +} diff --git a/fabric/src/main/java/io/github/retrooper/packetevents/mixin/MessageToMessageDecoderInvoker.java b/fabric/src/main/java/io/github/retrooper/packetevents/mixin/MessageToMessageDecoderInvoker.java new file mode 100644 index 0000000000..4b7d0d7b70 --- /dev/null +++ b/fabric/src/main/java/io/github/retrooper/packetevents/mixin/MessageToMessageDecoderInvoker.java @@ -0,0 +1,14 @@ +package io.github.retrooper.packetevents.mixin; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageDecoder; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +import java.util.List; + +@Mixin(MessageToMessageDecoder.class) +public interface MessageToMessageDecoderInvoker { + @Invoker("decode") + void invokeDecode(ChannelHandlerContext ctx, I msg, List out); +} diff --git a/fabric/src/main/java/io/github/retrooper/packetevents/mixin/MessageToMessageEncoderInvoker.java b/fabric/src/main/java/io/github/retrooper/packetevents/mixin/MessageToMessageEncoderInvoker.java new file mode 100644 index 0000000000..2b63963500 --- /dev/null +++ b/fabric/src/main/java/io/github/retrooper/packetevents/mixin/MessageToMessageEncoderInvoker.java @@ -0,0 +1,14 @@ +package io.github.retrooper.packetevents.mixin; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageEncoder; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +import java.util.List; + +@Mixin(MessageToMessageEncoder.class) +public interface MessageToMessageEncoderInvoker { + @Invoker("encode") + void invokeEncode(ChannelHandlerContext ctx, I msg, List out); +} diff --git a/fabric/src/main/resources/packetevents.mixins.json b/fabric/src/main/resources/packetevents.mixins.json index 27025b0734..95a5081b38 100644 --- a/fabric/src/main/resources/packetevents.mixins.json +++ b/fabric/src/main/resources/packetevents.mixins.json @@ -4,6 +4,10 @@ "package": "io.github.retrooper.packetevents.mixin", "compatibilityLevel": "JAVA_17", "mixins": [ + "CompressionDecoderInvoker", + "CompressionEncoderInvoker", + "MessageToMessageDecoderInvoker", + "MessageToMessageEncoderInvoker", "PacketEventsInjectorMixin" ], "client": [