diff --git a/src/main/java/de/florianmichael/viafabricplus/injection/access/IClientConnection.java b/src/main/java/de/florianmichael/viafabricplus/injection/access/IClientConnection.java index b34533c0..e28afda4 100644 --- a/src/main/java/de/florianmichael/viafabricplus/injection/access/IClientConnection.java +++ b/src/main/java/de/florianmichael/viafabricplus/injection/access/IClientConnection.java @@ -28,6 +28,7 @@ public interface IClientConnection { void viafabricplus_setupPreNettyEncryption(); + InetSocketAddress viafabricplus_capturedAddress(); void viafabricplus_captureAddress(final InetSocketAddress socketAddress); void viafabricplus_enableZLibCompression(); diff --git a/src/main/java/de/florianmichael/viafabricplus/injection/mixin/base/MixinClientConnection.java b/src/main/java/de/florianmichael/viafabricplus/injection/mixin/base/MixinClientConnection.java index 76ef145f..4f8e5ee1 100644 --- a/src/main/java/de/florianmichael/viafabricplus/injection/mixin/base/MixinClientConnection.java +++ b/src/main/java/de/florianmichael/viafabricplus/injection/mixin/base/MixinClientConnection.java @@ -17,40 +17,16 @@ */ package de.florianmichael.viafabricplus.injection.mixin.base; -import com.viaversion.viaversion.api.connection.UserConnection; -import com.viaversion.viaversion.connection.UserConnectionImpl; -import com.viaversion.viaversion.protocol.ProtocolPipelineImpl; import de.florianmichael.viafabricplus.event.ChangeProtocolVersionCallback; import de.florianmichael.viafabricplus.injection.access.IClientConnection; import de.florianmichael.viafabricplus.protocolhack.constants.PreNettyConstants; import de.florianmichael.viafabricplus.protocolhack.constants.BedrockRakNetConstants; -import de.florianmichael.viafabricplus.protocolhack.platform.viabedrock.DisconnectHandler; -import de.florianmichael.viafabricplus.protocolhack.platform.viabedrock.PingEncapsulationCodec; -import de.florianmichael.viafabricplus.protocolhack.platform.viabedrock.RakMessageEncapsulationCodec; import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; -import de.florianmichael.viafabricplus.protocolhack.platform.viabedrock.library_fix.FixedUnconnectedPingEncoder; -import de.florianmichael.viafabricplus.protocolhack.platform.viabedrock.library_fix.FixedUnconnectedPongDecoder; -import de.florianmichael.viafabricplus.protocolhack.platform.vialegacy.VFPPreNettyDecoder; -import de.florianmichael.viafabricplus.protocolhack.platform.vialegacy.VFPPreNettyEncoder; -import de.florianmichael.viafabricplus.protocolhack.replacement.ViaFabricPlusVLBViaDecodeHandler; +import de.florianmichael.viafabricplus.protocolhack.platform.viabedrock.RakNetClientConnection; import de.florianmichael.vialoadingbase.ViaLoadingBase; import de.florianmichael.vialoadingbase.event.PipelineReorderEvent; -import de.florianmichael.vialoadingbase.netty.NettyConstants; -import de.florianmichael.vialoadingbase.netty.VLBViaEncodeHandler; -import de.florianmichael.vialoadingbase.platform.InternalProtocolList; -import io.netty.bootstrap.Bootstrap; import io.netty.channel.*; -import io.netty.channel.epoll.Epoll; -import io.netty.channel.epoll.EpollDatagramChannel; -import io.netty.channel.epoll.EpollEventLoopGroup; -import io.netty.channel.epoll.EpollSocketChannel; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.SocketChannel; -import io.netty.channel.socket.nio.NioDatagramChannel; -import io.netty.channel.socket.nio.NioSocketChannel; -import io.netty.handler.timeout.ReadTimeoutHandler; import net.minecraft.network.ClientConnection; -import net.minecraft.network.NetworkSide; import net.minecraft.network.encryption.PacketDecryptor; import net.minecraft.network.encryption.PacketEncryptor; import net.minecraft.network.packet.Packet; @@ -58,19 +34,13 @@ import net.minecraft.text.Text; import net.minecraft.util.Lazy; import net.raphimc.viabedrock.api.BedrockProtocolVersion; import net.raphimc.viabedrock.netty.*; -import net.raphimc.viabedrock.protocol.BedrockBaseProtocol; import net.raphimc.vialegacy.api.LegacyProtocolVersion; -import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.baseprotocols.PreNettyBaseProtocol; -import org.cloudburstmc.netty.channel.raknet.RakChannelFactory; -import org.cloudburstmc.netty.channel.raknet.RakClientChannel; -import org.cloudburstmc.netty.channel.raknet.config.RakChannelOption; -import org.cloudburstmc.netty.handler.codec.raknet.common.UnconnectedPingEncoder; -import org.cloudburstmc.netty.handler.codec.raknet.common.UnconnectedPongDecoder; -import org.jetbrains.annotations.NotNull; import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import javax.crypto.Cipher; import javax.crypto.NoSuchPaddingException; @@ -79,7 +49,6 @@ import java.net.InetSocketAddress; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; -import java.util.concurrent.ThreadLocalRandom; @Mixin(ClientConnection.class) public abstract class MixinClientConnection extends SimpleChannelInboundHandler> implements IClientConnection { @@ -90,9 +59,6 @@ public abstract class MixinClientConnection extends SimpleChannelInboundHandler< @Shadow public abstract void channelActive(ChannelHandlerContext context) throws Exception; - @Shadow @Final public static Lazy EPOLL_CLIENT_IO_GROUP; - @Shadow @Final public static Lazy CLIENT_IO_GROUP; - @Unique private Cipher viafabricplus_decryptionCipher; @@ -119,107 +85,14 @@ public abstract class MixinClientConnection extends SimpleChannelInboundHandler< } } - /** - * @author Mojang, FlorianMichael as EnZaXD - * @reason Hack Netty Pipeline (do cursed shit) - */ - @Overwrite - public static ClientConnection connect(InetSocketAddress address, boolean useEpoll) { - final ClientConnection clientConnection = new ClientConnection(NetworkSide.CLIENTBOUND); + @Inject(method = "connect", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/Lazy;get()Ljava/lang/Object;", shift = At.Shift.BEFORE), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD) + private static void captureAddress(InetSocketAddress address, boolean useEpoll, CallbackInfoReturnable cir, final ClientConnection clientConnection, Class class_, Lazy lazy) { ((IClientConnection) clientConnection).viafabricplus_captureAddress(address); - final Class channelType = Epoll.isAvailable() && useEpoll ? EpollSocketChannel.class : NioSocketChannel.class; - final Lazy lazy = Epoll.isAvailable() && useEpoll ? EPOLL_CLIENT_IO_GROUP : CLIENT_IO_GROUP; - - final boolean rakNet = ProtocolHack.getForcedVersions().containsKey(address) ? - (ProtocolHack.getForcedVersions().get(address).getVersion() == BedrockProtocolVersion.bedrockLatest.getVersion()) : - ProtocolHack.getTargetVersion().isEqualTo(BedrockProtocolVersion.bedrockLatest); - - Bootstrap nettyBoostrap = new Bootstrap(); - nettyBoostrap = nettyBoostrap.group(lazy.get()); - nettyBoostrap = nettyBoostrap.handler(new ChannelInitializer<>() { - @Override - protected void initChannel(@NotNull Channel channel) throws Exception { - try { - if (rakNet) { - channel.config().setOption(RakChannelOption.RAK_PROTOCOL_VERSION, 11); - channel.config().setOption(RakChannelOption.RAK_CONNECT_TIMEOUT, 4_000L); - channel.config().setOption(RakChannelOption.RAK_SESSION_TIMEOUT, 30_000L); - channel.config().setOption(RakChannelOption.RAK_GUID, ThreadLocalRandom.current().nextLong()); - } else { - channel.config().setOption(ChannelOption.TCP_NODELAY, true); - } - } catch (Exception ignored) { - } - ChannelPipeline channelPipeline = channel.pipeline().addLast("timeout", new ReadTimeoutHandler(30)); - ClientConnection.addHandlers(channelPipeline, NetworkSide.CLIENTBOUND); - - channelPipeline.addLast("packet_handler", clientConnection); - - if (channel instanceof SocketChannel || rakNet) { - if (ProtocolHack.getForcedVersions().containsKey(address)) { - channel.attr(ProtocolHack.FORCED_VERSION).set(ProtocolHack.getForcedVersions().get(address)); - ProtocolHack.getForcedVersions().remove(address); - } - - final UserConnection user = new UserConnectionImpl(channel, true); - channel.attr(ProtocolHack.LOCAL_VIA_CONNECTION).set(user); - channel.attr(ProtocolHack.LOCAL_MINECRAFT_CONNECTION).set(clientConnection); - - new ProtocolPipelineImpl(user); - - channel.pipeline().addBefore("encoder", NettyConstants.HANDLER_ENCODER_NAME, new VLBViaEncodeHandler(user)); - channel.pipeline().addBefore("decoder", NettyConstants.HANDLER_DECODER_NAME, new ViaFabricPlusVLBViaDecodeHandler(user)); - - if (rakNet) { - user.getProtocolInfo().getPipeline().add(BedrockBaseProtocol.INSTANCE); - - channel.pipeline().replace("splitter", BedrockRakNetConstants.BATCH_LENGTH_HANDLER_NAME, new BatchLengthCodec()); - - channel.pipeline().addBefore(BedrockRakNetConstants.BATCH_LENGTH_HANDLER_NAME, BedrockRakNetConstants.DISCONNECT_HANDLER_NAME, new DisconnectHandler()); - channel.pipeline().addAfter(BedrockRakNetConstants.DISCONNECT_HANDLER_NAME, BedrockRakNetConstants.FRAME_ENCAPSULATION_HANDLER_NAME, new RakMessageEncapsulationCodec()); - channel.pipeline().addAfter(BedrockRakNetConstants.BATCH_LENGTH_HANDLER_NAME, BedrockRakNetConstants.PACKET_ENCAPSULATION_HANDLER_NAME, new PacketEncapsulationCodec()); - - channel.pipeline().remove("prepender"); - channel.pipeline().remove("timeout"); - - // Pinging in RakNet is something different - if (ProtocolHack.getRakNetPingSessions().contains(address)) { - { // Temporary fix for the ping encoder - final RakClientChannel rakChannel = (RakClientChannel) channel; - - rakChannel.parent().pipeline().replace(UnconnectedPingEncoder.NAME, UnconnectedPingEncoder.NAME, new FixedUnconnectedPingEncoder(rakChannel)); - rakChannel.parent().pipeline().replace(UnconnectedPongDecoder.NAME, UnconnectedPongDecoder.NAME, new FixedUnconnectedPongDecoder(rakChannel)); - } - - channel.pipeline().replace(BedrockRakNetConstants.FRAME_ENCAPSULATION_HANDLER_NAME, BedrockRakNetConstants.PING_ENCAPSULATION_HANDLER_NAME, new PingEncapsulationCodec(address)); - - channel.pipeline().remove(BedrockRakNetConstants.PACKET_ENCAPSULATION_HANDLER_NAME); - channel.pipeline().remove(BedrockRakNetConstants.BATCH_LENGTH_HANDLER_NAME); - } - } - - if (ProtocolHack.getTargetVersion(channel).isOlderThanOrEqualTo(LegacyProtocolVersion.r1_6_4)) { - user.getProtocolInfo().getPipeline().add(PreNettyBaseProtocol.INSTANCE); - - channel.pipeline().addBefore("prepender", PreNettyConstants.HANDLER_ENCODER_NAME, new VFPPreNettyEncoder(user)); - channel.pipeline().addBefore("splitter", PreNettyConstants.HANDLER_DECODER_NAME, new VFPPreNettyDecoder(user)); - } - } - } - }); - if (rakNet) { - nettyBoostrap = nettyBoostrap.channelFactory(channelType == EpollSocketChannel.class ? RakChannelFactory.client(EpollDatagramChannel.class) : RakChannelFactory.client(NioDatagramChannel.class)); - } else { - nettyBoostrap = nettyBoostrap.channel(channelType); + if (ProtocolHack.getForcedVersions().containsKey(address) ? (ProtocolHack.getForcedVersions().get(address).getVersion() == BedrockProtocolVersion.bedrockLatest.getVersion()) : ProtocolHack.getTargetVersion().isEqualTo(BedrockProtocolVersion.bedrockLatest)) { + RakNetClientConnection.connect(clientConnection, address, lazy, class_); + cir.setReturnValue(clientConnection); } - - if (ProtocolHack.getRakNetPingSessions().contains(address)) { - nettyBoostrap.bind(new InetSocketAddress(0)).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE).syncUninterruptibly(); - } else { - nettyBoostrap.connect(address.getAddress(), address.getPort()).syncUninterruptibly(); - } - return clientConnection; } @Override @@ -239,11 +112,15 @@ public abstract class MixinClientConnection extends SimpleChannelInboundHandler< @Override public void viafabricplus_setupPreNettyEncryption() { - this.encrypted = true; this.channel.pipeline().addBefore(PreNettyConstants.HANDLER_DECODER_NAME, "decrypt", new PacketDecryptor(this.viafabricplus_decryptionCipher)); this.channel.pipeline().addBefore(PreNettyConstants.HANDLER_ENCODER_NAME, "encrypt", new PacketEncryptor(this.viafabricplus_encryptionCipher)); } + @Override + public InetSocketAddress viafabricplus_capturedAddress() { + return viafabricplus_capturedAddress; + } + @Override public void viafabricplus_captureAddress(InetSocketAddress socketAddress) { viafabricplus_capturedAddress = socketAddress; diff --git a/src/main/java/de/florianmichael/viafabricplus/injection/mixin/base/MixinClientConnection_1.java b/src/main/java/de/florianmichael/viafabricplus/injection/mixin/base/MixinClientConnection_1.java new file mode 100644 index 00000000..f64d88db --- /dev/null +++ b/src/main/java/de/florianmichael/viafabricplus/injection/mixin/base/MixinClientConnection_1.java @@ -0,0 +1,45 @@ +/* + * This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus + * Copyright (C) 2021-2023 FlorianMichael/EnZaXD and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package de.florianmichael.viafabricplus.injection.mixin.base; + +import de.florianmichael.viafabricplus.injection.access.IClientConnection; +import de.florianmichael.viafabricplus.injection.reference.ClientConnectionReference; +import io.netty.channel.Channel; +import io.netty.channel.socket.SocketChannel; +import net.minecraft.network.ClientConnection; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(targets = "net.minecraft.network.ClientConnection$1") +public class MixinClientConnection_1 { + + @Final + @Shadow + ClientConnection field_11663; + + @Inject(method = "initChannel", at = @At("TAIL")) + public void hackNettyPipeline(Channel channel, CallbackInfo ci) { + if (channel instanceof SocketChannel) { + ClientConnectionReference.hackNettyPipeline(field_11663, channel, ((IClientConnection) field_11663).viafabricplus_capturedAddress()); + } + } +} diff --git a/src/main/java/de/florianmichael/viafabricplus/injection/reference/ClientConnectionReference.java b/src/main/java/de/florianmichael/viafabricplus/injection/reference/ClientConnectionReference.java new file mode 100644 index 00000000..ca309dfa --- /dev/null +++ b/src/main/java/de/florianmichael/viafabricplus/injection/reference/ClientConnectionReference.java @@ -0,0 +1,62 @@ +/* + * This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus + * Copyright (C) 2021-2023 FlorianMichael/EnZaXD and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package de.florianmichael.viafabricplus.injection.reference; + +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.connection.UserConnectionImpl; +import com.viaversion.viaversion.protocol.ProtocolPipelineImpl; +import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; +import de.florianmichael.viafabricplus.protocolhack.constants.PreNettyConstants; +import de.florianmichael.viafabricplus.protocolhack.platform.vialegacy.VFPPreNettyDecoder; +import de.florianmichael.viafabricplus.protocolhack.platform.vialegacy.VFPPreNettyEncoder; +import de.florianmichael.viafabricplus.protocolhack.replacement.ViaFabricPlusVLBViaDecodeHandler; +import de.florianmichael.vialoadingbase.netty.NettyConstants; +import de.florianmichael.vialoadingbase.netty.VLBViaEncodeHandler; +import io.netty.channel.Channel; +import net.minecraft.network.ClientConnection; +import net.raphimc.vialegacy.api.LegacyProtocolVersion; +import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.baseprotocols.PreNettyBaseProtocol; + +import java.net.InetSocketAddress; + +public class ClientConnectionReference { + + public static void hackNettyPipeline(final ClientConnection connection, final Channel channel, final InetSocketAddress address) { + if (ProtocolHack.getForcedVersions().containsKey(address)) { + channel.attr(ProtocolHack.FORCED_VERSION).set(ProtocolHack.getForcedVersions().get(address)); + ProtocolHack.getForcedVersions().remove(address); + } + final UserConnection user = new UserConnectionImpl(channel, true); + channel.attr(ProtocolHack.LOCAL_VIA_CONNECTION).set(user); + channel.attr(ProtocolHack.LOCAL_MINECRAFT_CONNECTION).set(connection); + + new ProtocolPipelineImpl(user); + + System.out.println("Hacking Netty Pipeline (ViaVersion)"); + + channel.pipeline().addBefore("encoder", NettyConstants.HANDLER_ENCODER_NAME, new VLBViaEncodeHandler(user)); + channel.pipeline().addBefore("decoder", NettyConstants.HANDLER_DECODER_NAME, new ViaFabricPlusVLBViaDecodeHandler(user)); + + if (ProtocolHack.getTargetVersion(channel).isOlderThanOrEqualTo(LegacyProtocolVersion.r1_6_4)) { + user.getProtocolInfo().getPipeline().add(PreNettyBaseProtocol.INSTANCE); + + channel.pipeline().addBefore("prepender", PreNettyConstants.HANDLER_ENCODER_NAME, new VFPPreNettyEncoder(user)); + channel.pipeline().addBefore("splitter", PreNettyConstants.HANDLER_DECODER_NAME, new VFPPreNettyDecoder(user)); + } + } +} diff --git a/src/main/java/de/florianmichael/viafabricplus/protocolhack/platform/viabedrock/RakNetClientConnection.java b/src/main/java/de/florianmichael/viafabricplus/protocolhack/platform/viabedrock/RakNetClientConnection.java new file mode 100644 index 00000000..3f768478 --- /dev/null +++ b/src/main/java/de/florianmichael/viafabricplus/protocolhack/platform/viabedrock/RakNetClientConnection.java @@ -0,0 +1,106 @@ +/* + * This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus + * Copyright (C) 2021-2023 FlorianMichael/EnZaXD and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package de.florianmichael.viafabricplus.protocolhack.platform.viabedrock; + +import com.viaversion.viaversion.api.connection.UserConnection; +import de.florianmichael.viafabricplus.injection.reference.ClientConnectionReference; +import de.florianmichael.viafabricplus.protocolhack.ProtocolHack; +import de.florianmichael.viafabricplus.protocolhack.constants.BedrockRakNetConstants; +import de.florianmichael.viafabricplus.protocolhack.platform.viabedrock.library_fix.FixedUnconnectedPingEncoder; +import de.florianmichael.viafabricplus.protocolhack.platform.viabedrock.library_fix.FixedUnconnectedPongDecoder; +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.*; +import io.netty.channel.epoll.EpollDatagramChannel; +import io.netty.channel.epoll.EpollSocketChannel; +import io.netty.channel.socket.nio.NioDatagramChannel; +import io.netty.handler.timeout.ReadTimeoutHandler; +import net.minecraft.network.ClientConnection; +import net.minecraft.network.NetworkSide; +import net.minecraft.util.Lazy; +import net.raphimc.viabedrock.netty.BatchLengthCodec; +import net.raphimc.viabedrock.netty.PacketEncapsulationCodec; +import net.raphimc.viabedrock.protocol.BedrockBaseProtocol; +import org.cloudburstmc.netty.channel.raknet.RakChannelFactory; +import org.cloudburstmc.netty.channel.raknet.RakClientChannel; +import org.cloudburstmc.netty.channel.raknet.config.RakChannelOption; +import org.cloudburstmc.netty.handler.codec.raknet.common.UnconnectedPingEncoder; +import org.cloudburstmc.netty.handler.codec.raknet.common.UnconnectedPongDecoder; +import org.jetbrains.annotations.NotNull; + +import java.net.InetSocketAddress; +import java.util.concurrent.ThreadLocalRandom; + +public class RakNetClientConnection { + + public static void connect(final ClientConnection clientConnection, final InetSocketAddress address, final Lazy lazy, final Class channelType) { + Bootstrap nettyBoostrap = new Bootstrap(); + nettyBoostrap = nettyBoostrap.group(lazy.get()); + nettyBoostrap = nettyBoostrap.handler(new ChannelInitializer<>() { + @Override + protected void initChannel(@NotNull Channel channel) throws Exception { + try { + channel.config().setOption(RakChannelOption.RAK_PROTOCOL_VERSION, 11); + channel.config().setOption(RakChannelOption.RAK_CONNECT_TIMEOUT, 4_000L); + channel.config().setOption(RakChannelOption.RAK_SESSION_TIMEOUT, 30_000L); + channel.config().setOption(RakChannelOption.RAK_GUID, ThreadLocalRandom.current().nextLong()); + } catch (Exception ignored) { + } + ChannelPipeline channelPipeline = channel.pipeline().addLast("timeout", new ReadTimeoutHandler(30)); + ClientConnection.addHandlers(channelPipeline, NetworkSide.CLIENTBOUND); + + channelPipeline.addLast("packet_handler", clientConnection); + + ClientConnectionReference.hackNettyPipeline(clientConnection, channel, address); + final UserConnection user = channel.attr(ProtocolHack.LOCAL_VIA_CONNECTION).get(); + + user.getProtocolInfo().getPipeline().add(BedrockBaseProtocol.INSTANCE); + + channel.pipeline().replace("splitter", BedrockRakNetConstants.BATCH_LENGTH_HANDLER_NAME, new BatchLengthCodec()); + + channel.pipeline().addBefore(BedrockRakNetConstants.BATCH_LENGTH_HANDLER_NAME, BedrockRakNetConstants.DISCONNECT_HANDLER_NAME, new DisconnectHandler()); + channel.pipeline().addAfter(BedrockRakNetConstants.DISCONNECT_HANDLER_NAME, BedrockRakNetConstants.FRAME_ENCAPSULATION_HANDLER_NAME, new RakMessageEncapsulationCodec()); + channel.pipeline().addAfter(BedrockRakNetConstants.BATCH_LENGTH_HANDLER_NAME, BedrockRakNetConstants.PACKET_ENCAPSULATION_HANDLER_NAME, new PacketEncapsulationCodec()); + + channel.pipeline().remove("prepender"); + channel.pipeline().remove("timeout"); + + // Pinging in RakNet is something different + if (ProtocolHack.getRakNetPingSessions().contains(address)) { + { // Temporary fix for the ping encoder + final RakClientChannel rakChannel = (RakClientChannel) channel; + + rakChannel.parent().pipeline().replace(UnconnectedPingEncoder.NAME, UnconnectedPingEncoder.NAME, new FixedUnconnectedPingEncoder(rakChannel)); + rakChannel.parent().pipeline().replace(UnconnectedPongDecoder.NAME, UnconnectedPongDecoder.NAME, new FixedUnconnectedPongDecoder(rakChannel)); + } + + channel.pipeline().replace(BedrockRakNetConstants.FRAME_ENCAPSULATION_HANDLER_NAME, BedrockRakNetConstants.PING_ENCAPSULATION_HANDLER_NAME, new PingEncapsulationCodec(address)); + + channel.pipeline().remove(BedrockRakNetConstants.PACKET_ENCAPSULATION_HANDLER_NAME); + channel.pipeline().remove(BedrockRakNetConstants.BATCH_LENGTH_HANDLER_NAME); + } + } + }); + nettyBoostrap = nettyBoostrap.channelFactory(channelType == EpollSocketChannel.class ? RakChannelFactory.client(EpollDatagramChannel.class) : RakChannelFactory.client(NioDatagramChannel.class)); + + if (ProtocolHack.getRakNetPingSessions().contains(address)) { + nettyBoostrap.bind(new InetSocketAddress(0)).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE).syncUninterruptibly(); + } else { + nettyBoostrap.connect(address.getAddress(), address.getPort()).syncUninterruptibly(); + } + } +} diff --git a/src/main/resources/viafabricplus.mixins.json b/src/main/resources/viafabricplus.mixins.json index ed1cff35..a1d59527 100644 --- a/src/main/resources/viafabricplus.mixins.json +++ b/src/main/resources/viafabricplus.mixins.json @@ -149,7 +149,8 @@ "fixes.viaversion.protocol1_9to1_8.MixinEntityTracker1_9", "fixes.viaversion.protocol1_9to1_8.MixinMetadataRewriter1_9To1_8", "fixes.viaversion.protocol1_9to1_8.MixinMovementTracker", - "fixes.viaversion.protocol1_9to1_8.MixinViaIdleThread" + "fixes.viaversion.protocol1_9to1_8.MixinViaIdleThread", + "base.MixinClientConnection_1" ], "injectors": { "defaultRequire": 1