From 643cf0b4ca242e9c1b323d99cec04a04d513b458 Mon Sep 17 00:00:00 2001 From: RaphiMC <50594595+RaphiMC@users.noreply.github.com> Date: Sun, 2 Apr 2023 21:21:50 +0200 Subject: [PATCH] Implemented abstracted netty pipeline --- README.md | 8 +- build.gradle | 18 +++- .../platform/ViaAprilFoolsPlatformImpl.java | 46 +++++++++ .../impl/platform/ViaBedrockPlatformImpl.java | 46 +++++++++ .../VPHMovementTransmitterProvider.java | 7 +- .../impl/viaversion/VPHInjector.java | 4 +- .../netty/CompressionReorderEvent.java | 27 +++++ .../netty/VPHDecodeHandler.java | 61 ------------ .../netty/VPHEncodeHandler.java | 61 ------------ .../viaprotocolhack/netty/VPHPipeline.java | 98 ++++++++++++++++++- .../viaprotocolhack/netty/ViaCodec.java | 96 ++++++++++++++++++ .../netty/viabedrock/DisconnectHandler.java | 38 +++++++ .../viabedrock/PingEncapsulationCodec.java | 64 ++++++++++++ .../RakMessageEncapsulationCodec.java | 61 ++++++++++++ 14 files changed, 497 insertions(+), 138 deletions(-) create mode 100644 src/main/java/net/raphimc/viaprotocolhack/impl/platform/ViaAprilFoolsPlatformImpl.java create mode 100644 src/main/java/net/raphimc/viaprotocolhack/impl/platform/ViaBedrockPlatformImpl.java create mode 100644 src/main/java/net/raphimc/viaprotocolhack/netty/CompressionReorderEvent.java delete mode 100644 src/main/java/net/raphimc/viaprotocolhack/netty/VPHDecodeHandler.java delete mode 100644 src/main/java/net/raphimc/viaprotocolhack/netty/VPHEncodeHandler.java create mode 100644 src/main/java/net/raphimc/viaprotocolhack/netty/ViaCodec.java create mode 100644 src/main/java/net/raphimc/viaprotocolhack/netty/viabedrock/DisconnectHandler.java create mode 100644 src/main/java/net/raphimc/viaprotocolhack/netty/viabedrock/PingEncapsulationCodec.java create mode 100644 src/main/java/net/raphimc/viaprotocolhack/netty/viabedrock/RakMessageEncapsulationCodec.java diff --git a/README.md b/README.md index 174e91c..b1ee507 100644 --- a/README.md +++ b/README.md @@ -36,14 +36,14 @@ To include ViaLegacy and ViaAprilFools, you can look at their READMEs: [ViaLegac Here is an example dependency configuration for all components: ```groovy -implementation "com.viaversion:viaversion:4.7.0-23w12a-SNAPSHOT" -implementation("com.viaversion:viabackwards-common:4.7.0-23w12a-SNAPSHOT") { +implementation "com.viaversion:viaversion:4.7.0-23w13a-SNAPSHOT" +implementation("com.viaversion:viabackwards-common:4.7.0-23w13a-SNAPSHOT") { exclude group: "com.viaversion", module: "viaversion" // Exclude transitive dependency. Include manually for more control exclude group: "io.netty", module: "netty-all" // Don't include the outdated netty version } implementation "com.viaversion:viarewind-core:2.0.4-SNAPSHOT" -implementation "net.raphimc:ViaLegacy:2.2.9" -implementation "net.raphimc:ViaAprilFools:2.0.5" +implementation "net.raphimc:ViaLegacy:2.2.11" +implementation "net.raphimc:ViaAprilFools:2.0.6" ``` ## Implementation diff --git a/build.gradle b/build.gradle index 684f59b..b6d4884 100644 --- a/build.gradle +++ b/build.gradle @@ -17,6 +17,18 @@ repositories { name = "Lenni0451" url "https://maven.lenni0451.net/releases" } + maven { + name = "Lenni0451 Snapshots" + url "https://maven.lenni0451.net/snapshots" + } + maven { + name = "OpenCollab Releases" + url = "https://repo.opencollab.dev/maven-releases/" + } + maven { + name = "OpenCollab Snapshots" + url = "https://repo.opencollab.dev/maven-snapshots/" + } maven { name = "ViaVersion" url "https://repo.viaversion.com" @@ -27,9 +39,13 @@ dependencies { compileOnly "com.viaversion:viaversion:4.7.0-23w12a-SNAPSHOT" compileOnly("com.viaversion:viabackwards-common:4.7.0-23w12a-SNAPSHOT") { exclude group: "com.viaversion", module: "viaversion" + exclude group: "io.netty", module: "netty-all" } compileOnly "com.viaversion:viarewind-core:2.0.4-SNAPSHOT" - compileOnly "net.raphimc:ViaLegacy:2.2.6" + compileOnly "net.raphimc:ViaLegacy:2.2.11" + compileOnly "net.raphimc:ViaAprilFools:2.0.6" + compileOnly "net.raphimc:ViaBedrock:0.0.1-SNAPSHOT" + compileOnly "org.cloudburstmc.netty:netty-transport-raknet:1.0.0.CR1-SNAPSHOT" api "org.slf4j:slf4j-api:2.0.7" api "org.yaml:snakeyaml:2.0" diff --git a/src/main/java/net/raphimc/viaprotocolhack/impl/platform/ViaAprilFoolsPlatformImpl.java b/src/main/java/net/raphimc/viaprotocolhack/impl/platform/ViaAprilFoolsPlatformImpl.java new file mode 100644 index 0000000..dde85df --- /dev/null +++ b/src/main/java/net/raphimc/viaprotocolhack/impl/platform/ViaAprilFoolsPlatformImpl.java @@ -0,0 +1,46 @@ +/* + * This file is part of ViaProtocolHack - https://github.com/RaphiMC/ViaProtocolHack + * Copyright (C) 2023 RK_01/RaphiMC 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 net.raphimc.viaprotocolhack.impl.platform; + +import com.viaversion.viaversion.api.Via; +import net.raphimc.viaaprilfools.platform.ViaAprilFoolsPlatform; +import net.raphimc.viaprotocolhack.util.JLoggerToSLF4J; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.logging.Logger; + +public class ViaAprilFoolsPlatformImpl implements ViaAprilFoolsPlatform { + + private static final Logger LOGGER = new JLoggerToSLF4J(LoggerFactory.getLogger("ViaAprilFools")); + + public ViaAprilFoolsPlatformImpl() { + this.init(this.getDataFolder()); + } + + @Override + public Logger getLogger() { + return LOGGER; + } + + @Override + public File getDataFolder() { + return Via.getPlatform().getDataFolder(); + } + +} diff --git a/src/main/java/net/raphimc/viaprotocolhack/impl/platform/ViaBedrockPlatformImpl.java b/src/main/java/net/raphimc/viaprotocolhack/impl/platform/ViaBedrockPlatformImpl.java new file mode 100644 index 0000000..f1dae18 --- /dev/null +++ b/src/main/java/net/raphimc/viaprotocolhack/impl/platform/ViaBedrockPlatformImpl.java @@ -0,0 +1,46 @@ +/* + * This file is part of ViaProtocolHack - https://github.com/RaphiMC/ViaProtocolHack + * Copyright (C) 2023 RK_01/RaphiMC 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 net.raphimc.viaprotocolhack.impl.platform; + +import com.viaversion.viaversion.api.Via; +import net.raphimc.viabedrock.platform.ViaBedrockPlatform; +import net.raphimc.viaprotocolhack.util.JLoggerToSLF4J; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.logging.Logger; + +public class ViaBedrockPlatformImpl implements ViaBedrockPlatform { + + private static final Logger LOGGER = new JLoggerToSLF4J(LoggerFactory.getLogger("ViaBedrock")); + + public ViaBedrockPlatformImpl() { + this.init(this.getDataFolder()); + } + + @Override + public Logger getLogger() { + return LOGGER; + } + + @Override + public File getDataFolder() { + return Via.getPlatform().getDataFolder(); + } + +} diff --git a/src/main/java/net/raphimc/viaprotocolhack/impl/providers/VPHMovementTransmitterProvider.java b/src/main/java/net/raphimc/viaprotocolhack/impl/providers/VPHMovementTransmitterProvider.java index 7fe21c5..b4a05e6 100644 --- a/src/main/java/net/raphimc/viaprotocolhack/impl/providers/VPHMovementTransmitterProvider.java +++ b/src/main/java/net/raphimc/viaprotocolhack/impl/providers/VPHMovementTransmitterProvider.java @@ -46,12 +46,11 @@ public class VPHMovementTransmitterProvider extends MovementTransmitterProvider final MovementTracker tracker = userConnection.get(MovementTracker.class); tracker.incrementIdlePacket(); - final PacketWrapper wrapper = PacketWrapper.create(ServerboundPackets1_8.PLAYER_MOVEMENT, userConnection); - wrapper.write(Type.BOOLEAN, tracker.isGround()); - userConnection.getChannel().eventLoop().submit(() -> { try { - wrapper.sendToServer(Protocol1_9To1_8.class); + final PacketWrapper playerMovement = PacketWrapper.create(ServerboundPackets1_8.PLAYER_MOVEMENT, userConnection); + playerMovement.write(Type.BOOLEAN, tracker.isGround()); + playerMovement.sendToServer(Protocol1_9To1_8.class); } catch (Throwable ignored) { } }); diff --git a/src/main/java/net/raphimc/viaprotocolhack/impl/viaversion/VPHInjector.java b/src/main/java/net/raphimc/viaprotocolhack/impl/viaversion/VPHInjector.java index 3773ceb..66f7281 100644 --- a/src/main/java/net/raphimc/viaprotocolhack/impl/viaversion/VPHInjector.java +++ b/src/main/java/net/raphimc/viaprotocolhack/impl/viaversion/VPHInjector.java @@ -50,12 +50,12 @@ public class VPHInjector implements ViaInjector { @Override public String getEncoderName() { - return VPHPipeline.ENCODER_HANDLER_NAME; + return VPHPipeline.VIA_CODEC_NAME; } @Override public String getDecoderName() { - return VPHPipeline.DECODER_HANDLER_NAME; + return VPHPipeline.VIA_CODEC_NAME; } @Override diff --git a/src/main/java/net/raphimc/viaprotocolhack/netty/CompressionReorderEvent.java b/src/main/java/net/raphimc/viaprotocolhack/netty/CompressionReorderEvent.java new file mode 100644 index 0000000..1923d47 --- /dev/null +++ b/src/main/java/net/raphimc/viaprotocolhack/netty/CompressionReorderEvent.java @@ -0,0 +1,27 @@ +/* + * This file is part of ViaProtocolHack - https://github.com/RaphiMC/ViaProtocolHack + * Copyright (C) 2023 RK_01/RaphiMC 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 net.raphimc.viaprotocolhack.netty; + +public class CompressionReorderEvent { + + public static final CompressionReorderEvent INSTANCE = new CompressionReorderEvent(); + + private CompressionReorderEvent() { + } + +} diff --git a/src/main/java/net/raphimc/viaprotocolhack/netty/VPHDecodeHandler.java b/src/main/java/net/raphimc/viaprotocolhack/netty/VPHDecodeHandler.java deleted file mode 100644 index cd5ca13..0000000 --- a/src/main/java/net/raphimc/viaprotocolhack/netty/VPHDecodeHandler.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * This file is part of ViaProtocolHack - https://github.com/RaphiMC/ViaProtocolHack - * Copyright (C) 2023 RK_01/RaphiMC 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 net.raphimc.viaprotocolhack.netty; - -import com.viaversion.viaversion.api.connection.UserConnection; -import com.viaversion.viaversion.exception.CancelCodecException; -import com.viaversion.viaversion.exception.CancelDecoderException; -import com.viaversion.viaversion.util.PipelineUtil; -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.MessageToMessageDecoder; - -import java.util.List; - -public class VPHDecodeHandler extends MessageToMessageDecoder { - - protected final UserConnection user; - - public VPHDecodeHandler(final UserConnection user) { - this.user = user; - } - - @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List out) throws Exception { - if (!user.checkIncomingPacket()) throw CancelDecoderException.generate(null); - if (!user.shouldTransformPacket()) { - out.add(bytebuf.retain()); - return; - } - - final ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf); - try { - user.transformIncoming(transformedBuf, CancelDecoderException::generate); - out.add(transformedBuf.retain()); - } finally { - transformedBuf.release(); - } - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - if (PipelineUtil.containsCause(cause, CancelCodecException.class)) return; - super.exceptionCaught(ctx, cause); - } - -} diff --git a/src/main/java/net/raphimc/viaprotocolhack/netty/VPHEncodeHandler.java b/src/main/java/net/raphimc/viaprotocolhack/netty/VPHEncodeHandler.java deleted file mode 100644 index 45fbf3d..0000000 --- a/src/main/java/net/raphimc/viaprotocolhack/netty/VPHEncodeHandler.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * This file is part of ViaProtocolHack - https://github.com/RaphiMC/ViaProtocolHack - * Copyright (C) 2023 RK_01/RaphiMC 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 net.raphimc.viaprotocolhack.netty; - -import com.viaversion.viaversion.api.connection.UserConnection; -import com.viaversion.viaversion.exception.CancelCodecException; -import com.viaversion.viaversion.exception.CancelEncoderException; -import com.viaversion.viaversion.util.PipelineUtil; -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.MessageToMessageEncoder; - -import java.util.List; - -public class VPHEncodeHandler extends MessageToMessageEncoder { - - protected final UserConnection user; - - public VPHEncodeHandler(final UserConnection user) { - this.user = user; - } - - @Override - protected void encode(ChannelHandlerContext ctx, ByteBuf bytebuf, List out) throws Exception { - if (!user.checkOutgoingPacket()) throw CancelEncoderException.generate(null); - if (!user.shouldTransformPacket()) { - out.add(bytebuf.retain()); - return; - } - - final ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf); - try { - user.transformOutgoing(transformedBuf, CancelEncoderException::generate); - out.add(transformedBuf.retain()); - } finally { - transformedBuf.release(); - } - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - if (PipelineUtil.containsCause(cause, CancelCodecException.class)) return; - super.exceptionCaught(ctx, cause); - } - -} diff --git a/src/main/java/net/raphimc/viaprotocolhack/netty/VPHPipeline.java b/src/main/java/net/raphimc/viaprotocolhack/netty/VPHPipeline.java index 220546c..7646af1 100644 --- a/src/main/java/net/raphimc/viaprotocolhack/netty/VPHPipeline.java +++ b/src/main/java/net/raphimc/viaprotocolhack/netty/VPHPipeline.java @@ -17,11 +17,99 @@ */ package net.raphimc.viaprotocolhack.netty; -public class VPHPipeline { +import com.viaversion.viaversion.api.connection.UserConnection; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.ChannelPipeline; +import net.raphimc.viabedrock.netty.BatchLengthCodec; +import net.raphimc.viabedrock.netty.PacketEncapsulationCodec; +import net.raphimc.viabedrock.protocol.BedrockBaseProtocol; +import net.raphimc.vialegacy.netty.PreNettyLengthCodec; +import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.baseprotocols.PreNettyBaseProtocol; +import net.raphimc.viaprotocolhack.netty.viabedrock.DisconnectHandler; +import net.raphimc.viaprotocolhack.netty.viabedrock.RakMessageEncapsulationCodec; +import net.raphimc.viaprotocolhack.util.VersionEnum; - public static final String DECODER_HANDLER_NAME = "via_decoder"; - public static final String ENCODER_HANDLER_NAME = "via_encoder"; - public static final String PRE_NETTY_ENCODER_HANDLER_NAME = "via-pre-netty_encoder"; - public static final String PRE_NETTY_DECODER_HANDLER_NAME = "via-pre-netty_decoder"; +public abstract class VPHPipeline extends ChannelInboundHandlerAdapter { + + public static final String VIA_CODEC_NAME = "via-codec"; + + public static final String VIALEGACY_PRE_NETTY_LENGTH_CODEC_NAME = "vialegacy-pre-netty-length-codec"; + + public static final String VIABEDROCK_DISCONNECT_HANDLER_NAME = "viabedrock-disconnect-handler"; + public static final String VIABEDROCK_FRAME_ENCAPSULATION_HANDLER_NAME = "viabedrock-frame-encapsulation"; + public static final String VIABEDROCK_PACKET_ENCAPSULATION_HANDLER_NAME = "viabedrock-packet-encapsulation"; + + protected final UserConnection user; + protected final VersionEnum version; + + public VPHPipeline(final UserConnection user, final VersionEnum version) { + this.user = user; + this.version = version; + } + + @Override + public void handlerAdded(ChannelHandlerContext ctx) { + ctx.pipeline().addBefore(this.packetCodecName(), VIA_CODEC_NAME, this.createViaCodec()); + + if (this.version.isOlderThanOrEqualTo(VersionEnum.r1_6_4)) { + this.user.getProtocolInfo().getPipeline().add(PreNettyBaseProtocol.INSTANCE); + ctx.pipeline().addBefore(this.lengthCodecName(), VIALEGACY_PRE_NETTY_LENGTH_CODEC_NAME, this.createViaLegacyPreNettyLengthCodec()); + } else if (this.version.equals(VersionEnum.bedrockLatest)) { + this.user.getProtocolInfo().getPipeline().add(BedrockBaseProtocol.INSTANCE); + ctx.pipeline().addBefore(this.lengthCodecName(), VIABEDROCK_DISCONNECT_HANDLER_NAME, this.createViaBedrockDisconnectHandler()); + ctx.pipeline().addBefore(this.lengthCodecName(), VIABEDROCK_FRAME_ENCAPSULATION_HANDLER_NAME, this.createViaBedrockFrameEncapsulationHandler()); + this.replaceLengthCodec(ctx, this.createViaBedrockBatchLengthCodec()); + ctx.pipeline().addBefore(VIA_CODEC_NAME, VIABEDROCK_PACKET_ENCAPSULATION_HANDLER_NAME, this.createViaBedrockPacketEncapsulationHandler()); + } + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (CompressionReorderEvent.INSTANCE.equals(evt)) { + final ChannelPipeline pipeline = ctx.pipeline(); + + if (pipeline.names().indexOf(this.compressionCodecName()) > pipeline.names().indexOf(VIA_CODEC_NAME)) { + pipeline.addAfter(this.compressionCodecName(), VIA_CODEC_NAME, pipeline.remove(VIA_CODEC_NAME)); + } + } + + super.userEventTriggered(ctx, evt); + } + + protected ChannelHandler createViaCodec() { + return new ViaCodec(this.user); + } + + protected ChannelHandler createViaLegacyPreNettyLengthCodec() { + return new PreNettyLengthCodec(this.user); + } + + protected ChannelHandler createViaBedrockDisconnectHandler() { + return new DisconnectHandler(); + } + + protected ChannelHandler createViaBedrockFrameEncapsulationHandler() { + return new RakMessageEncapsulationCodec(); + } + + protected ChannelHandler createViaBedrockBatchLengthCodec() { + return new BatchLengthCodec(); + } + + protected ChannelHandler createViaBedrockPacketEncapsulationHandler() { + return new PacketEncapsulationCodec(); + } + + protected void replaceLengthCodec(final ChannelHandlerContext ctx, final ChannelHandler handler) { + ctx.pipeline().replace(this.lengthCodecName(), this.lengthCodecName(), handler); + } + + protected abstract String compressionCodecName(); + + protected abstract String packetCodecName(); + + protected abstract String lengthCodecName(); } diff --git a/src/main/java/net/raphimc/viaprotocolhack/netty/ViaCodec.java b/src/main/java/net/raphimc/viaprotocolhack/netty/ViaCodec.java new file mode 100644 index 0000000..d4d9d8e --- /dev/null +++ b/src/main/java/net/raphimc/viaprotocolhack/netty/ViaCodec.java @@ -0,0 +1,96 @@ +/* + * This file is part of ViaProtocolHack - https://github.com/RaphiMC/ViaProtocolHack + * Copyright (C) 2023 RK_01/RaphiMC 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 net.raphimc.viaprotocolhack.netty; + +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.exception.CancelCodecException; +import com.viaversion.viaversion.exception.CancelDecoderException; +import com.viaversion.viaversion.exception.CancelEncoderException; +import com.viaversion.viaversion.util.PipelineUtil; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPromise; +import io.netty.handler.codec.ByteToMessageCodec; + +import java.util.List; + +public class ViaCodec extends ByteToMessageCodec { + + protected final UserConnection user; + + public ViaCodec(final UserConnection user) { + this.user = user; + } + + @Override + protected void encode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception { + if (!this.user.checkOutgoingPacket()) throw CancelEncoderException.generate(null); + + out.writeBytes(in); + if (this.user.shouldTransformPacket()) { + this.user.transformOutgoing(out, CancelEncoderException::generate); + } + } + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + if (!this.user.checkIncomingPacket()) throw CancelDecoderException.generate(null); + + final ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(in); + try { + if (this.user.shouldTransformPacket()) { + this.user.transformIncoming(transformedBuf, CancelDecoderException::generate); + } + out.add(transformedBuf.retain()); + } finally { + transformedBuf.release(); + } + } + + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + try { + super.write(ctx, msg, promise); + } catch (Throwable e) { + if (!PipelineUtil.containsCause(e, CancelCodecException.class)) { + throw e; + } else { + promise.setSuccess(); + } + } + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + try { + super.channelRead(ctx, msg); + } catch (Throwable e) { + if (!PipelineUtil.containsCause(e, CancelCodecException.class)) { + throw e; + } + } + } + + @Override + public boolean isSharable() { + // Netty doesn't allow codecs to be shared, but we need it to be shared because of the pipeline reordering. + // The check if it is sharable is done in the constructor and can be bypassed by returning false during that check. + return this.user != null; + } + +} diff --git a/src/main/java/net/raphimc/viaprotocolhack/netty/viabedrock/DisconnectHandler.java b/src/main/java/net/raphimc/viaprotocolhack/netty/viabedrock/DisconnectHandler.java new file mode 100644 index 0000000..71a9140 --- /dev/null +++ b/src/main/java/net/raphimc/viaprotocolhack/netty/viabedrock/DisconnectHandler.java @@ -0,0 +1,38 @@ +/* + * This file is part of ViaProtocolHack - https://github.com/RaphiMC/ViaProtocolHack + * Copyright (C) 2023 RK_01/RaphiMC 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 net.raphimc.viaprotocolhack.netty.viabedrock; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelOutboundHandlerAdapter; +import io.netty.channel.ChannelPromise; + +public class DisconnectHandler extends ChannelOutboundHandlerAdapter { + + private boolean calledDisconnect = false; + + @Override + public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { + if (ctx.channel().isActive() && !this.calledDisconnect) { + this.calledDisconnect = true; + ctx.disconnect(promise); // Send disconnect notification to the server and close the channel + } else { + super.close(ctx, promise); + } + } + +} diff --git a/src/main/java/net/raphimc/viaprotocolhack/netty/viabedrock/PingEncapsulationCodec.java b/src/main/java/net/raphimc/viaprotocolhack/netty/viabedrock/PingEncapsulationCodec.java new file mode 100644 index 0000000..50ab4e0 --- /dev/null +++ b/src/main/java/net/raphimc/viaprotocolhack/netty/viabedrock/PingEncapsulationCodec.java @@ -0,0 +1,64 @@ +/* + * This file is part of ViaProtocolHack - https://github.com/RaphiMC/ViaProtocolHack + * Copyright (C) 2023 RK_01/RaphiMC 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 net.raphimc.viaprotocolhack.netty.viabedrock; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageCodec; +import org.cloudburstmc.netty.channel.raknet.RakConstants; +import org.cloudburstmc.netty.channel.raknet.RakPing; +import org.cloudburstmc.netty.channel.raknet.RakPong; + +import java.net.InetSocketAddress; +import java.util.List; + +public class PingEncapsulationCodec extends MessageToMessageCodec { + + private final InetSocketAddress remoteAddress; + + public PingEncapsulationCodec(final InetSocketAddress remoteAddress) { + this.remoteAddress = remoteAddress; + } + + @Override + protected void encode(ChannelHandlerContext ctx, ByteBuf in, List out) { + final int packetId = in.readUnsignedByte(); + + if (packetId == RakConstants.ID_UNCONNECTED_PING) { + out.add(new RakPing(in.readLong(), this.remoteAddress)); + } else { + ctx.close(); + throw new IllegalStateException("Unexpected packet ID: " + packetId); + } + } + + @Override + protected void decode(ChannelHandlerContext ctx, RakPong in, List out) { + if (!this.remoteAddress.equals(in.getSender())) { + ctx.close(); + throw new IllegalStateException("Received pong from unexpected address: " + in.getSender()); + } + + final ByteBuf buf = ctx.alloc().buffer(); + buf.writeByte(RakConstants.ID_UNCONNECTED_PONG); + buf.writeLong(in.getPingTime()); + buf.writeBytes(in.getPongData()); + out.add(buf); + } + +} diff --git a/src/main/java/net/raphimc/viaprotocolhack/netty/viabedrock/RakMessageEncapsulationCodec.java b/src/main/java/net/raphimc/viaprotocolhack/netty/viabedrock/RakMessageEncapsulationCodec.java new file mode 100644 index 0000000..c731bcf --- /dev/null +++ b/src/main/java/net/raphimc/viaprotocolhack/netty/viabedrock/RakMessageEncapsulationCodec.java @@ -0,0 +1,61 @@ +/* + * This file is part of ViaProtocolHack - https://github.com/RaphiMC/ViaProtocolHack + * Copyright (C) 2023 RK_01/RaphiMC 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 net.raphimc.viaprotocolhack.netty.viabedrock; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.CompositeByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageCodec; +import org.cloudburstmc.netty.channel.raknet.RakReliability; +import org.cloudburstmc.netty.channel.raknet.packet.RakMessage; + +import java.util.List; + +public class RakMessageEncapsulationCodec extends MessageToMessageCodec { + + private static final int FRAME_ID = 0xFE; + + @Override + protected void encode(ChannelHandlerContext ctx, ByteBuf msg, List out) { + final CompositeByteBuf buf = ctx.alloc().compositeBuffer(2); + try { + buf.addComponent(true, ctx.alloc().ioBuffer(1).writeByte(FRAME_ID)); + buf.addComponent(true, msg.retainedSlice()); + out.add(buf.retain()); + } finally { + buf.release(); + } + } + + @Override + protected void decode(ChannelHandlerContext ctx, RakMessage msg, List out) { + if (msg.channel() != 0 && msg.reliability() != RakReliability.RELIABLE_ORDERED) { + return; + } + final ByteBuf in = msg.content(); + if (!in.isReadable()) { + return; + } + final int id = in.readUnsignedByte(); + if (id != FRAME_ID) { + throw new IllegalStateException("Invalid frame ID: " + id); + } + out.add(in.readRetainedSlice(in.readableBytes())); + } + +}