From 4e73f261cf2aa65c7c006898ac1566c898eb1a00 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 03:12:23 -0600 Subject: [PATCH 01/71] ConnectionBridge now has a helper method for querying the protocol phase, and the decoder acquires the connection object from the netty pipeline --- .../forwarding/modern/ConnectionBridge.java | 6 +++ .../forwarding/modern/ModernForwarding.java | 6 +-- .../pcf/forwarding/modern/PacketDecoder.java | 16 ++++---- .../forwarding/modern/ConnectionMixin.java | 4 +- .../forwarding/modern/ConnectionMixin.java | 10 +++++ .../forwarding/modern/ConnectionMixin.java | 17 +++++++++ .../forwarding/modern/ConnectionMixin.java | 15 ++++++++ .../forwarding/modern/ConnectionMixin.java | 38 +++++++++++++++++++ .../resources/pcf.mixins.v19_2.forge.json | 1 + .../forwarding/modern/ConnectionMixin.java | 13 +++++++ 10 files changed, 113 insertions(+), 13 deletions(-) create mode 100644 modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ConnectionMixin.java diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ConnectionBridge.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ConnectionBridge.java index e99e7007..2ccf1ee3 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ConnectionBridge.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ConnectionBridge.java @@ -1,5 +1,7 @@ package org.adde0109.pcf.forwarding.modern; +import dev.neuralnexus.taterapi.network.Protocol; + import io.netty.channel.Channel; import org.jspecify.annotations.NonNull; @@ -8,6 +10,8 @@ import java.net.InetSocketAddress; public interface ConnectionBridge { + String PACKET_HANDLER = "packet_handler"; + @NonNull InetSocketAddress bridge$address(); void bridge$address(final @NonNull InetSocketAddress address); @@ -16,6 +20,8 @@ public interface ConnectionBridge { @Nullable Object bridge$getPacketListener(); + @Nullable Protocol bridge$protocol(); + default void bridge$send(final @NonNull Object packet) { this.bridge$channel().writeAndFlush(packet).addListener(ModernForwarding::errorListener); } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index 717c4666..59aeb11a 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -60,11 +60,9 @@ public final class ModernForwarding { /** * Injects the packet encoder and decoder into the pipeline to handle login query packets * - * @param connection the connection * @param ctx the channel handler context */ - public static void injectIntoPipeline( - final @NonNull ConnectionBridge connection, final @NonNull ChannelHandlerContext ctx) { + public static void injectIntoPipeline(final @NonNull ChannelHandlerContext ctx) { if (ctx.pipeline().get(PacketDecoder.NAME) != null || ctx.pipeline().get(PacketEncoder.NAME) != null) { return; @@ -73,7 +71,7 @@ public static void injectIntoPipeline( "Injecting packet handlers into pipeline of " + ctx.channel().remoteAddress()); ctx.channel() .pipeline() - .addAfter(HANDLER_SPLITTER, PacketDecoder.NAME, new PacketDecoder(connection)) + .addAfter(HANDLER_SPLITTER, PacketDecoder.NAME, new PacketDecoder()) .addAfter(HANDLER_PREPENDER, PacketEncoder.NAME, new PacketEncoder()); } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/PacketDecoder.java index d569e47c..208fe23c 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/PacketDecoder.java @@ -1,8 +1,10 @@ package org.adde0109.pcf.forwarding.modern; +import static org.adde0109.pcf.forwarding.modern.ConnectionBridge.PACKET_HANDLER; import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleCustomQueryPacket; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; +import dev.neuralnexus.taterapi.network.Protocol; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; import dev.neuralnexus.taterapi.network.protocol.login.ServerboundCustomQueryAnswerPacket; @@ -18,12 +20,6 @@ public final class PacketDecoder extends MessageToMessageDecoder { public static final String NAME = "pcf-decoder"; - private final ConnectionBridge connection; - - public PacketDecoder(final @NonNull ConnectionBridge connection) { - this.connection = connection; - } - @SuppressWarnings("RedundantThrows") @Override protected void decode( @@ -34,7 +30,13 @@ protected void decode( if (!msg.isReadable()) { return; } - if (!(this.connection.bridge$getPacketListener() + final ConnectionBridge connection = + ((ConnectionBridge) ctx.channel().pipeline().get(PACKET_HANDLER)); + if (!(connection.bridge$protocol() == Protocol.LOGIN)) { + out.add(msg.retain()); + return; + } + if (!(connection.bridge$getPacketListener() instanceof ServerLoginPacketListenerBridge slpl)) { out.add(msg.retain()); return; diff --git a/common/src/main/java/org/adde0109/pcf/mixin/common/forwarding/modern/ConnectionMixin.java b/common/src/main/java/org/adde0109/pcf/mixin/common/forwarding/modern/ConnectionMixin.java index 238fd4da..7c0415c3 100644 --- a/common/src/main/java/org/adde0109/pcf/mixin/common/forwarding/modern/ConnectionMixin.java +++ b/common/src/main/java/org/adde0109/pcf/mixin/common/forwarding/modern/ConnectionMixin.java @@ -41,7 +41,7 @@ public abstract static class Mojang implements ConnectionBridge { @Inject(method = "channelActive", at = @At("TAIL"), remap = false) private void onChannelActive( final @NonNull ChannelHandlerContext ctx, final @NonNull CallbackInfo ci) { - injectIntoPipeline(this, ctx); + injectIntoPipeline(ctx); } } @@ -61,7 +61,7 @@ public abstract static class Searge implements ConnectionBridge { @Inject(method = "channelActive", at = @At("TAIL"), remap = false) private void onChannelActive( final @NonNull ChannelHandlerContext ctx, final @NonNull CallbackInfo ci) { - injectIntoPipeline(this, ctx); + injectIntoPipeline(ctx); } } } diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ConnectionMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ConnectionMixin.java index 42c8e95c..a48744f8 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ConnectionMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ConnectionMixin.java @@ -2,6 +2,7 @@ import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; +import dev.neuralnexus.taterapi.network.Protocol; import net.minecraft.network.Connection; import net.minecraft.network.PacketListener; @@ -37,4 +38,13 @@ public abstract class ConnectionMixin implements ConnectionBridge { public @Nullable Object bridge$getPacketListener() { return this.shadow$getPacketListener(); } + + @Override + public Protocol bridge$protocol() { + final PacketListener listener = this.shadow$getPacketListener(); + if (listener == null) { + return null; + } + return Protocol.fromId(listener.protocol().id()); + } } diff --git a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ConnectionMixin.java b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ConnectionMixin.java index 1e73dd28..c9dff544 100644 --- a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ConnectionMixin.java +++ b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ConnectionMixin.java @@ -4,13 +4,18 @@ import dev.neuralnexus.taterapi.meta.anno.AConstraint; import dev.neuralnexus.taterapi.meta.anno.Versions; import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; +import dev.neuralnexus.taterapi.network.Protocol; +import io.netty.util.AttributeKey; + +import net.minecraft.network.EnumConnectionState; import net.minecraft.network.INetHandler; import net.minecraft.network.NetworkManager; import org.adde0109.pcf.forwarding.modern.ConnectionBridge; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -27,6 +32,8 @@ public abstract class ConnectionMixin implements ConnectionBridge { @Shadow public abstract INetHandler shadow$getNetHandler(); // spotless:on + @Shadow @Final public static AttributeKey PROTOCOL_ATTRIBUTE_KEY; + @Override public @NonNull InetSocketAddress bridge$address() { return (InetSocketAddress) this.socketAddress; @@ -41,4 +48,14 @@ public abstract class ConnectionMixin implements ConnectionBridge { public @Nullable Object bridge$getPacketListener() { return this.shadow$getNetHandler(); } + + @Override + public Protocol bridge$protocol() { + final INetHandler listener = this.shadow$getNetHandler(); + if (listener == null) { + return null; + } + return Protocol.fromLegacyId( + this.bridge$channel().attr(PROTOCOL_ATTRIBUTE_KEY).get().getId()); + } } diff --git a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ConnectionMixin.java b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ConnectionMixin.java index f4263bc3..50f89d62 100644 --- a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ConnectionMixin.java +++ b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ConnectionMixin.java @@ -4,13 +4,18 @@ import dev.neuralnexus.taterapi.meta.anno.AConstraint; import dev.neuralnexus.taterapi.meta.anno.Versions; import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; +import dev.neuralnexus.taterapi.network.Protocol; + +import io.netty.util.AttributeKey; import net.minecraft.network.Connection; +import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.PacketListener; import org.adde0109.pcf.forwarding.modern.ConnectionBridge; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -24,6 +29,7 @@ public abstract class ConnectionMixin implements ConnectionBridge { // spotless:off @Shadow private SocketAddress address; + @Shadow @Final public static AttributeKey ATTRIBUTE_PROTOCOL; @Shadow public abstract PacketListener shadow$getPacketListener(); // spotless:on @@ -41,4 +47,13 @@ public abstract class ConnectionMixin implements ConnectionBridge { public @Nullable Object bridge$getPacketListener() { return this.shadow$getPacketListener(); } + + @Override + public Protocol bridge$protocol() { + final PacketListener listener = this.shadow$getPacketListener(); + if (listener == null) { + return null; + } + return Protocol.fromLegacyId(this.bridge$channel().attr(ATTRIBUTE_PROTOCOL).get().getId()); + } } diff --git a/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ConnectionMixin.java b/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ConnectionMixin.java new file mode 100644 index 00000000..f2b7cca5 --- /dev/null +++ b/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ConnectionMixin.java @@ -0,0 +1,38 @@ +package org.adde0109.pcf.mixin.v19_2.forge.forwarding.modern; + +import dev.neuralnexus.taterapi.meta.Mappings; +import dev.neuralnexus.taterapi.meta.anno.AConstraint; +import dev.neuralnexus.taterapi.meta.anno.Versions; +import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; +import dev.neuralnexus.taterapi.network.Protocol; + +import io.netty.util.AttributeKey; + +import net.minecraft.network.Connection; +import net.minecraft.network.ConnectionProtocol; +import net.minecraft.network.PacketListener; + +import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@AConstraint( + mappings = Mappings.SEARGE, + version = @Versions(min = MinecraftVersion.V17, max = MinecraftVersion.V20_1)) +@Mixin(Connection.class) +public abstract class ConnectionMixin implements ConnectionBridge { + // spotless:off + @Shadow @Final public static AttributeKey ATTRIBUTE_PROTOCOL; + @Shadow public abstract PacketListener shadow$getPacketListener(); + // spotless:on + + @Override + public Protocol bridge$protocol() { + final PacketListener listener = this.shadow$getPacketListener(); + if (listener == null) { + return null; + } + return Protocol.fromLegacyId(this.bridge$channel().attr(ATTRIBUTE_PROTOCOL).get().getId()); + } +} diff --git a/modern/v19_2/src/forge/resources/pcf.mixins.v19_2.forge.json b/modern/v19_2/src/forge/resources/pcf.mixins.v19_2.forge.json index 69f323bf..61ff1a19 100644 --- a/modern/v19_2/src/forge/resources/pcf.mixins.v19_2.forge.json +++ b/modern/v19_2/src/forge/resources/pcf.mixins.v19_2.forge.json @@ -8,6 +8,7 @@ "plugin": "org.adde0109.pcf.mixin.plugin.PCFMixinPlugin", "package": "org.adde0109.pcf.mixin", "server": [ + "v19_2.forge.forwarding.modern.ConnectionMixin", "v19_2.forge.forwarding.modern.LastSeenMessagesValidatorMixin", "v19_2.forge.forwarding.modern.PlayerChatMessageMixin", "v19_2.forge.forwarding.modern.ServerLoginPacketListenerImplKeyV1Mixin", diff --git a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ConnectionMixin.java b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ConnectionMixin.java index b286edd2..c1b0d945 100644 --- a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ConnectionMixin.java +++ b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ConnectionMixin.java @@ -4,6 +4,7 @@ import dev.neuralnexus.taterapi.meta.anno.AConstraint; import dev.neuralnexus.taterapi.meta.anno.Versions; import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; +import dev.neuralnexus.taterapi.network.Protocol; import net.minecraft.network.Connection; import net.minecraft.network.PacketListener; @@ -41,4 +42,16 @@ public abstract class ConnectionMixin implements ConnectionBridge { public @Nullable Object bridge$getPacketListener() { return this.shadow$getPacketListener(); } + + @AConstraint( + mappings = Mappings.SEARGE, + version = @Versions(min = MinecraftVersion.V20_2, max = MinecraftVersion.V20_4)) + @Override + public Protocol bridge$protocol() { + final PacketListener listener = this.shadow$getPacketListener(); + if (listener == null) { + return null; + } + return Protocol.fromId(listener.protocol().id()); + } } From 37946ba3dfd58095fe9ad0cfd48e351f6df1ba7d Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 03:12:31 -0600 Subject: [PATCH 02/71] Version bump --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 1510d618..d4d7dd3c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ mod_id=pcf mod_name=ProxyCompatibleForge description=Bring modern forwarding to Neo/Forge servers, requires the Ambassador plugin on Velocity for 1.13-1.20.1, should work standalone on 1.20.2+ group=org.adde0109.pcf -version=1.2.5 +version=1.2.6-SNAPSHOT license=LGPL-2.1 authors=adde0109,JT122406,p0t4t0sandwich java_version=25 From ff7aed11ef46a6dce0b5866e8dcc3c6a545daf5f Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 03:16:32 -0600 Subject: [PATCH 03/71] Beginnings of legacy forwarding support --- .../org/adde0109/pcf/forwarding/Mode.java | 3 + .../legacy/ConnectionBridgeLegacy.java | 17 +++ .../forwarding/modern/ReflectionUtils.java | 2 +- .../legacy/ClientIntentionPacketMixin.java | 20 +++ .../legacy/ConnectionLegacyMixin.java | 88 ++++++++++++++ ...erverHandshakePacketListenerImplMixin.java | 115 ++++++++++++++++++ ...rverLoginPacketListenerImplHelloMixin.java | 84 +++++++++++++ .../src/main/resources/pcf.mixins.v26_1.json | 4 + 8 files changed, 332 insertions(+), 1 deletion(-) create mode 100644 common/src/main/java/org/adde0109/pcf/forwarding/legacy/ConnectionBridgeLegacy.java create mode 100644 deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ClientIntentionPacketMixin.java create mode 100644 deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ConnectionLegacyMixin.java create mode 100644 deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerHandshakePacketListenerImplMixin.java create mode 100644 deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/Mode.java b/common/src/main/java/org/adde0109/pcf/forwarding/Mode.java index be35157f..3cf087d8 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/Mode.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/Mode.java @@ -2,5 +2,8 @@ /** Forwarding types supported by PCF */ public enum Mode { + NONE, + LEGACY, + BUNGEEGUARD, MODERN } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/ConnectionBridgeLegacy.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/ConnectionBridgeLegacy.java new file mode 100644 index 00000000..79e415a4 --- /dev/null +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/ConnectionBridgeLegacy.java @@ -0,0 +1,17 @@ +package org.adde0109.pcf.forwarding.legacy; + +import com.mojang.authlib.properties.Property; + +import org.jspecify.annotations.NonNull; + +import java.util.UUID; + +public interface ConnectionBridgeLegacy { + UUID bridge$spoofedUUID(); + + void bridge$spoofedUUID(final @NonNull UUID uuid); + + Property[] bridge$spoofedProfile(); + + void bridge$spoofedProfile(final @NonNull Property[] properties); +} diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ReflectionUtils.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ReflectionUtils.java index 69bf85cc..7618448f 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ReflectionUtils.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ReflectionUtils.java @@ -47,7 +47,7 @@ private ReflectionUtils() {} * @param profile the profile * @return the properties */ - static @NonNull PropertyMap getProperties(final @NonNull GameProfile profile) { + public static @NonNull PropertyMap getProperties(final @NonNull GameProfile profile) { try { return (PropertyMap) profilePropertiesHandle.invokeExact(profile); } catch (final Throwable e) { diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ClientIntentionPacketMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ClientIntentionPacketMixin.java new file mode 100644 index 00000000..5e568590 --- /dev/null +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ClientIntentionPacketMixin.java @@ -0,0 +1,20 @@ +package org.adde0109.pcf.mixin.v26_1.forwarding.legacy; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.handshake.ClientIntentionPacket; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +// https://github.com/caunt/BungeeForge/blob/1.20.2/src/main/java/ua/caunt/bungeeforge/mixin/network/protocol/handshake/ClientIntentionPacket.java#L28 +@Mixin(ClientIntentionPacket.class) +public final class ClientIntentionPacketMixin { + // spotless:off + @Redirect(method = "(Lnet/minecraft/network/FriendlyByteBuf;)V", at = @At(value = "INVOKE", + target = "Lnet/minecraft/network/FriendlyByteBuf;readUtf(I)Ljava/lang/String;")) + // spotless:on + private static String onConstruct(final FriendlyByteBuf input, int length) { + return input.readUtf(Short.MAX_VALUE); + } +} diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ConnectionLegacyMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ConnectionLegacyMixin.java new file mode 100644 index 00000000..074f3ff5 --- /dev/null +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ConnectionLegacyMixin.java @@ -0,0 +1,88 @@ +package org.adde0109.pcf.mixin.v26_1.forwarding.legacy; + +import com.mojang.authlib.properties.Property; + +import dev.neuralnexus.taterapi.meta.Mappings; +import dev.neuralnexus.taterapi.meta.anno.AConstraint; +import dev.neuralnexus.taterapi.network.Protocol; + +import io.netty.channel.Channel; + +import net.minecraft.network.Connection; +import net.minecraft.network.PacketListener; + +import org.adde0109.pcf.forwarding.legacy.ConnectionBridgeLegacy; +import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.UUID; + +@AConstraint(mappings = Mappings.MOJANG) +@Mixin(Connection.class) +public abstract class ConnectionLegacyMixin implements ConnectionBridge, ConnectionBridgeLegacy { + // spotless:off + @Shadow private SocketAddress address; + @Shadow public abstract PacketListener shadow$getPacketListener(); + @Shadow public abstract Channel channel(); + // spotless:on + + @Override + public @NonNull InetSocketAddress bridge$address() { + return (InetSocketAddress) this.address; + } + + @Override + public void bridge$address(final @NonNull InetSocketAddress address) { + this.address = address; + } + + @Override + public @NonNull Channel bridge$channel() { + return this.channel(); + } + + @Override + public @Nullable Object bridge$getPacketListener() { + return this.shadow$getPacketListener(); + } + + @Override + public Protocol bridge$protocol() { + final PacketListener listener = this.shadow$getPacketListener(); + if (listener == null) { + return null; + } + return Protocol.fromId(listener.protocol().id()); + } + + // spotless:off + @Unique private UUID pcf$spoofedUUID = null; + @Unique private Property[] pcf$spoofedProfile = null; + // spotless:on + + @Override + public UUID bridge$spoofedUUID() { + return this.pcf$spoofedUUID; + } + + @Override + public void bridge$spoofedUUID(final @NonNull UUID uuid) { + this.pcf$spoofedUUID = uuid; + } + + @Override + public Property[] bridge$spoofedProfile() { + return this.pcf$spoofedProfile; + } + + @Override + public void bridge$spoofedProfile(final @NonNull Property[] properties) { + this.pcf$spoofedProfile = properties; + } +} diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerHandshakePacketListenerImplMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerHandshakePacketListenerImplMixin.java new file mode 100644 index 00000000..88c20171 --- /dev/null +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerHandshakePacketListenerImplMixin.java @@ -0,0 +1,115 @@ +package org.adde0109.pcf.mixin.v26_1.forwarding.legacy; + +import static dev.neuralnexus.taterapi.network.chat.Component.literal; + +import com.google.common.net.InetAddresses; +import com.google.gson.Gson; +import com.mojang.authlib.properties.Property; + +import net.minecraft.network.Connection; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.handshake.ClientIntentionPacket; +import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket; +import net.minecraft.server.network.ServerHandshakePacketListenerImpl; + +import org.adde0109.pcf.PCF; +import org.adde0109.pcf.forwarding.Mode; +import org.adde0109.pcf.forwarding.legacy.ConnectionBridgeLegacy; +import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.net.InetSocketAddress; +import java.util.Objects; +import java.util.UUID; +import java.util.regex.Pattern; + +// https://hub.spigotmc.org/stash/projects/SPIGOT/repos/spigot/browse/CraftBukkit-Patches/0024-BungeeCord-Support.patch +@Mixin(ServerHandshakePacketListenerImpl.class) +public abstract class ServerHandshakePacketListenerImplMixin { + // spotless:off + @Shadow @Final private Connection connection; + + @Unique private static final char pcf$LEGACY_SEPARATOR = '\0'; + @Unique private static final String pcf$BUNGEE_GUARD_TOKEN_PROPERTY_NAME = "bungeeguard-token"; + + @Unique private static final Gson pcf$gson = new Gson(); + @Unique private static final Pattern pcf$HOST_PATTERN = Pattern.compile("[0-9a-f.:]{0,45}"); + + @Unique private static final Object pcf$DIRECT_CONNECT_ERR = // TODO: Consider two different messages + literal("This server requires you to connect with Velocity or BungeeCord."); + @Unique private static final Object pcf$BG_CONFIG_ERR = + literal("This server requires the proxy to be configured for BungeeGuard forwarding."); + + @Inject(method = "beginLogin", cancellable = true, at = @At(value = "RETURN", + target = "Lnet/minecraft/network/Connection;setupInboundProtocol(Lnet/minecraft/network/ProtocolInfo;Lnet/minecraft/network/PacketListener;)V")) + // spotless:on + private void onBeginLogin( + final ClientIntentionPacket packet, final boolean transfer, final CallbackInfo ci) { + if (PCF.instance().forwarding().mode() != Mode.LEGACY + && PCF.instance().forwarding().mode() != Mode.BUNGEEGUARD) return; + + // Spigot Start + // TODO: Stick this in a packet listener and extract it there and add to the + // ConnectionBridgeLegacy + // Then replace the original serverAddress used for the regular login flow + // Do not forget Forge markers if present + final String[] split = packet.hostName().split("\00"); + PCF.logger.info( + "Received handshake with " + + split.length + + " parts: " + + String.join("\n ", split)); + if ((split.length < 3) || !(pcf$HOST_PATTERN.matcher(split[1]).matches())) { + this.pcf$disconnect(pcf$DIRECT_CONNECT_ERR); + return; + } + if ((split.length < 4) && PCF.instance().forwarding().mode() != Mode.BUNGEEGUARD) { + this.pcf$disconnect(pcf$BG_CONFIG_ERR); + return; + } + + final String originalAddress = split[1]; + final UUID uuid = pcf$fromStringLenient(split[2]); + PCF.logger.info( + "Player " + uuid + " is connecting with original address " + originalAddress); + + // Update the proxied address + final int port = ((ConnectionBridge) this.connection).bridge$address().getPort(); + final InetSocketAddress address = + new InetSocketAddress(InetAddresses.forString(originalAddress), port); + ((ConnectionBridge) this.connection).bridge$address(address); + + // Save the UUID + ((ConnectionBridgeLegacy) this.connection).bridge$spoofedUUID(uuid); + + // Save the properties if present + if (split.length == 4) { // TODO: Enforce if BungeeGuard forwarding + final String profileJSON = split[3]; + ((ConnectionBridgeLegacy) this.connection) + .bridge$spoofedProfile(pcf$gson.fromJson(profileJSON, Property[].class)); + } + // Spigot End + } + + @Unique public void pcf$disconnect(Object component) { + this.connection.send(new ClientboundLoginDisconnectPacket((Component) component)); + this.connection.disconnect((Component) component); + } + + @Unique private static UUID pcf$fromStringLenient(final String string) { + return UUID.fromString( + string.replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5")); + } + + // https://github.com/caunt/BungeeForge/blob/1.20.2/src/main/java/ua/caunt/bungeeforge/mixin/network/protocol/handshake/ClientIntentionPacket.java#L51-L54 + @Unique private static boolean pcf$isFmlMarker(Property property) { + return Objects.equals(property.name(), "extraData") + && property.value().startsWith("\u0001FORGE"); + } +} diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java new file mode 100644 index 00000000..f67d72ce --- /dev/null +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java @@ -0,0 +1,84 @@ +package org.adde0109.pcf.mixin.v26_1.forwarding.legacy; + +import static org.adde0109.pcf.forwarding.modern.ReflectionUtils.getProperties; + +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; + +import dev.neuralnexus.taterapi.meta.Mappings; +import dev.neuralnexus.taterapi.meta.anno.AConstraint; +import dev.neuralnexus.taterapi.meta.anno.Versions; +import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; + +import net.minecraft.network.Connection; +import net.minecraft.network.protocol.login.ServerboundHelloPacket; +import net.minecraft.server.network.ServerLoginPacketListenerImpl; + +import org.adde0109.pcf.forwarding.legacy.ConnectionBridgeLegacy; +import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.jspecify.annotations.NonNull; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.nio.charset.StandardCharsets; +import java.util.UUID; +import java.util.regex.Pattern; + +// https://hub.spigotmc.org/stash/projects/SPIGOT/repos/spigot/browse/CraftBukkit-Patches/0024-BungeeCord-Support.patch +@Mixin(ServerLoginPacketListenerImpl.class) +public abstract class ServerLoginPacketListenerImplHelloMixin + implements ServerLoginPacketListenerBridge { + // spotless:off + @Shadow @Final private Connection connection; + + @Shadow protected abstract void startClientVerification(GameProfile profile); + + @Unique private static final Pattern pcf$PROP_PATTERN = Pattern.compile("\\w{0,16}"); + + @AConstraint(mappings = Mappings.MOJANG, version = @Versions(min = MinecraftVersion.V20_2)) + @Inject(method = "handleHello", cancellable = true, at = @At(value = "INVOKE", ordinal = 1, + target = "Lnet/minecraft/server/network/ServerLoginPacketListenerImpl;startClientVerification(Lcom/mojang/authlib/GameProfile;)V")) + // spotless:on + private void onHandleHello_20_M( + final ServerboundHelloPacket packet, final @NonNull CallbackInfo ci) { + ConnectionBridgeLegacy conn = (ConnectionBridgeLegacy) this.connection; + if (conn.bridge$spoofedProfile() == null) { + return; // TODO: Provide client-bound disconnect error + } + + // TODO: PostProcessors + this.startClientVerification(this.pcf$createOfflineProfile(packet.name())); + ci.cancel(); + } + + // Spigot start + @Unique protected GameProfile pcf$createOfflineProfile(String name) { + final UUID uuid; + if (((ConnectionBridgeLegacy) this.connection).bridge$spoofedUUID() != null) { + uuid = ((ConnectionBridgeLegacy) this.connection).bridge$spoofedUUID(); + } else { + uuid = + UUID.nameUUIDFromBytes( + ("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8)); + } + + // TODO: Add 1.21.9 support + final GameProfile profile = new GameProfile(uuid, name); + final PropertyMap propertiesMap = getProperties(profile); + if (((ConnectionBridgeLegacy) this.connection).bridge$spoofedProfile() != null) { + for (final Property property : + ((ConnectionBridgeLegacy) this.connection).bridge$spoofedProfile()) { + if (!pcf$PROP_PATTERN.matcher(property.name()).matches()) continue; + propertiesMap.put(property.name(), property); + } + } + return profile; + } + // Spigot end +} diff --git a/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json b/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json index b59a9619..7bec5b0e 100644 --- a/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json +++ b/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json @@ -10,6 +10,10 @@ "server": [ "v26_1.crossstich.ArgumentNodeStubMixin", "v26_1.crossstich.ArgumentTypeInfoMixin", + "v26_1.forwarding.legacy.ClientIntentionPacketMixin", + "v26_1.forwarding.legacy.ConnectionLegacyMixin", + "v26_1.forwarding.legacy.ServerHandshakePacketListenerImplMixin", + "v26_1.forwarding.legacy.ServerLoginPacketListenerImplHelloMixin", "v26_1.forwarding.modern.ConnectionMixin", "v26_1.forwarding.modern.ServerLoginPacketListenerImplHelloHybridMixin", "v26_1.forwarding.modern.ServerLoginPacketListenerImplHelloMixin", From 23be5208971c88c4b4ebf603c367630dd867a782 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 03:20:23 -0600 Subject: [PATCH 04/71] Relocated ConnectionBridge and PacketEncoder/Decoder --- .../pcf/forwarding/ConnectionBridge.java | 51 +++++++++++++++++++ .../{modern => }/PacketDecoder.java | 7 +-- .../{modern => }/PacketEncoder.java | 2 +- .../forwarding/modern/ConnectionBridge.java | 28 ---------- .../forwarding/modern/ModernForwarding.java | 22 -------- .../ServerLoginPacketListenerBridge.java | 1 + .../{modern => }/ConnectionMixin.java | 10 ++-- .../{modern => }/ConnectionMixin.java | 4 +- .../legacy/ConnectionLegacyMixin.java | 2 +- ...erverHandshakePacketListenerImplMixin.java | 2 +- .../ServerLoginPacketListenerImplMixin.java | 2 +- .../src/main/resources/pcf.mixins.v26_1.json | 2 +- .../{modern => }/ConnectionMixin.java | 4 +- .../ServerLoginPacketListenerImplMixin.java | 2 +- .../resources/pcf.mixins.v12_2.forge.json | 2 +- .../ServerLoginPacketListenerImplMixin.java | 2 +- .../{modern => }/ConnectionMixin.java | 4 +- .../ServerLoginPacketListenerImplMixin.java | 2 +- .../resources/pcf.mixins.v16_5.forge.json | 2 +- .../{modern => }/ConnectionMixin.java | 4 +- .../resources/pcf.mixins.v19_2.forge.json | 2 +- .../{modern => }/ConnectionMixin.java | 4 +- .../ServerLoginPacketListenerImplMixin.java | 2 +- .../resources/pcf.mixins.v20_4.forge.json | 2 +- 24 files changed, 83 insertions(+), 82 deletions(-) create mode 100644 common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java rename common/src/main/java/org/adde0109/pcf/forwarding/{modern => }/PacketDecoder.java (93%) rename common/src/main/java/org/adde0109/pcf/forwarding/{modern => }/PacketEncoder.java (96%) delete mode 100644 common/src/main/java/org/adde0109/pcf/forwarding/modern/ConnectionBridge.java rename common/src/main/java/org/adde0109/pcf/mixin/common/forwarding/{modern => }/ConnectionMixin.java (88%) rename deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/{modern => }/ConnectionMixin.java (92%) rename legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/{modern => }/ConnectionMixin.java (93%) rename modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/{modern => }/ConnectionMixin.java (93%) rename modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/{modern => }/ConnectionMixin.java (91%) rename modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/{modern => }/ConnectionMixin.java (93%) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java b/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java new file mode 100644 index 00000000..8e40c1b6 --- /dev/null +++ b/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java @@ -0,0 +1,51 @@ +package org.adde0109.pcf.forwarding; + +import dev.neuralnexus.taterapi.network.Protocol; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; + +import org.adde0109.pcf.PCF; +import org.adde0109.pcf.forwarding.modern.ModernForwarding; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +import java.net.InetSocketAddress; + +public interface ConnectionBridge { + String HANDLER_PACKET = "packet_handler"; + String HANDLER_SPLITTER = "splitter"; + String HANDLER_PREPENDER = "prepender"; + + @NonNull InetSocketAddress bridge$address(); + + void bridge$address(final @NonNull InetSocketAddress address); + + @NonNull Channel bridge$channel(); + + @Nullable Object bridge$getPacketListener(); + + @Nullable Protocol bridge$protocol(); + + default void bridge$send(final @NonNull Object packet) { + this.bridge$channel().writeAndFlush(packet).addListener(ModernForwarding::errorListener); + } + + /** + * Injects the packet encoder and decoder into the pipeline to handle login query packets + * + * @param ctx the channel handler context + */ + static void injectIntoPipeline(final @NonNull ChannelHandlerContext ctx) { + if (ctx.pipeline().get(PacketDecoder.NAME) != null + || ctx.pipeline().get(PacketEncoder.NAME) != null) { + return; + } + PCF.logger.debug( + "Injecting packet handlers into pipeline of " + ctx.channel().remoteAddress()); + ctx.channel() + .pipeline() + .addAfter(HANDLER_SPLITTER, PacketDecoder.NAME, new PacketDecoder()) + .addAfter(HANDLER_PREPENDER, PacketEncoder.NAME, new PacketEncoder()); + } +} diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java similarity index 93% rename from common/src/main/java/org/adde0109/pcf/forwarding/modern/PacketDecoder.java rename to common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 208fe23c..9cb1c2e5 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -1,6 +1,6 @@ -package org.adde0109.pcf.forwarding.modern; +package org.adde0109.pcf.forwarding; -import static org.adde0109.pcf.forwarding.modern.ConnectionBridge.PACKET_HANDLER; +import static org.adde0109.pcf.forwarding.ConnectionBridge.HANDLER_PACKET; import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleCustomQueryPacket; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; @@ -13,6 +13,7 @@ import io.netty.handler.codec.MessageToMessageDecoder; import org.adde0109.pcf.PCF; +import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import java.util.List; @@ -31,7 +32,7 @@ protected void decode( return; } final ConnectionBridge connection = - ((ConnectionBridge) ctx.channel().pipeline().get(PACKET_HANDLER)); + ((ConnectionBridge) ctx.channel().pipeline().get(HANDLER_PACKET)); if (!(connection.bridge$protocol() == Protocol.LOGIN)) { out.add(msg.retain()); return; diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/PacketEncoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketEncoder.java similarity index 96% rename from common/src/main/java/org/adde0109/pcf/forwarding/modern/PacketEncoder.java rename to common/src/main/java/org/adde0109/pcf/forwarding/PacketEncoder.java index 1de935fe..0097013b 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/PacketEncoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketEncoder.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.forwarding.modern; +package org.adde0109.pcf.forwarding; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; import dev.neuralnexus.taterapi.network.protocol.login.ClientboundCustomQueryPacket; diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ConnectionBridge.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ConnectionBridge.java deleted file mode 100644 index 2ccf1ee3..00000000 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ConnectionBridge.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.adde0109.pcf.forwarding.modern; - -import dev.neuralnexus.taterapi.network.Protocol; - -import io.netty.channel.Channel; - -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -import java.net.InetSocketAddress; - -public interface ConnectionBridge { - String PACKET_HANDLER = "packet_handler"; - - @NonNull InetSocketAddress bridge$address(); - - void bridge$address(final @NonNull InetSocketAddress address); - - @NonNull Channel bridge$channel(); - - @Nullable Object bridge$getPacketListener(); - - @Nullable Protocol bridge$protocol(); - - default void bridge$send(final @NonNull Object packet) { - this.bridge$channel().writeAndFlush(packet).addListener(ModernForwarding::errorListener); - } -} diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index 59aeb11a..27a5366f 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -19,7 +19,6 @@ import dev.neuralnexus.taterapi.network.protocol.login.ServerboundCustomQueryAnswerPacket; import dev.neuralnexus.taterapi.network.protocol.login.custom.CustomQueryAnswerPayload; -import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.DecoderException; import io.netty.util.concurrent.Future; @@ -54,27 +53,6 @@ public final class ModernForwarding { private static final Object REJECTED_PROXY_ERR = literal("Unapproved proxy host."); - private static final String HANDLER_SPLITTER = "splitter"; - private static final String HANDLER_PREPENDER = "prepender"; - - /** - * Injects the packet encoder and decoder into the pipeline to handle login query packets - * - * @param ctx the channel handler context - */ - public static void injectIntoPipeline(final @NonNull ChannelHandlerContext ctx) { - if (ctx.pipeline().get(PacketDecoder.NAME) != null - || ctx.pipeline().get(PacketEncoder.NAME) != null) { - return; - } - PCF.logger.debug( - "Injecting packet handlers into pipeline of " + ctx.channel().remoteAddress()); - ctx.channel() - .pipeline() - .addAfter(HANDLER_SPLITTER, PacketDecoder.NAME, new PacketDecoder()) - .addAfter(HANDLER_PREPENDER, PacketEncoder.NAME, new PacketEncoder()); - } - /** * Listener for logging errors during packet handling * diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ServerLoginPacketListenerBridge.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ServerLoginPacketListenerBridge.java index 0de20f66..0686d116 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ServerLoginPacketListenerBridge.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ServerLoginPacketListenerBridge.java @@ -4,6 +4,7 @@ import dev.neuralnexus.taterapi.mc.world.entity.player.ProfilePublicKey; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; diff --git a/common/src/main/java/org/adde0109/pcf/mixin/common/forwarding/modern/ConnectionMixin.java b/common/src/main/java/org/adde0109/pcf/mixin/common/forwarding/ConnectionMixin.java similarity index 88% rename from common/src/main/java/org/adde0109/pcf/mixin/common/forwarding/modern/ConnectionMixin.java rename to common/src/main/java/org/adde0109/pcf/mixin/common/forwarding/ConnectionMixin.java index 7c0415c3..e0d8fd6b 100644 --- a/common/src/main/java/org/adde0109/pcf/mixin/common/forwarding/modern/ConnectionMixin.java +++ b/common/src/main/java/org/adde0109/pcf/mixin/common/forwarding/ConnectionMixin.java @@ -1,6 +1,4 @@ -package org.adde0109.pcf.mixin.common.forwarding.modern; - -import static org.adde0109.pcf.forwarding.modern.ModernForwarding.injectIntoPipeline; +package org.adde0109.pcf.mixin.common.forwarding; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; @@ -11,7 +9,7 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -41,7 +39,7 @@ public abstract static class Mojang implements ConnectionBridge { @Inject(method = "channelActive", at = @At("TAIL"), remap = false) private void onChannelActive( final @NonNull ChannelHandlerContext ctx, final @NonNull CallbackInfo ci) { - injectIntoPipeline(ctx); + ConnectionBridge.injectIntoPipeline(ctx); } } @@ -61,7 +59,7 @@ public abstract static class Searge implements ConnectionBridge { @Inject(method = "channelActive", at = @At("TAIL"), remap = false) private void onChannelActive( final @NonNull ChannelHandlerContext ctx, final @NonNull CallbackInfo ci) { - injectIntoPipeline(ctx); + ConnectionBridge.injectIntoPipeline(ctx); } } } diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ConnectionMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ConnectionMixin.java similarity index 92% rename from deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ConnectionMixin.java rename to deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ConnectionMixin.java index a48744f8..0a96af26 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ConnectionMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ConnectionMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v26_1.forwarding.modern; +package org.adde0109.pcf.mixin.v26_1.forwarding; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; @@ -7,7 +7,7 @@ import net.minecraft.network.Connection; import net.minecraft.network.PacketListener; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ConnectionLegacyMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ConnectionLegacyMixin.java index 074f3ff5..01c77d59 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ConnectionLegacyMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ConnectionLegacyMixin.java @@ -11,8 +11,8 @@ import net.minecraft.network.Connection; import net.minecraft.network.PacketListener; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.legacy.ConnectionBridgeLegacy; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerHandshakePacketListenerImplMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerHandshakePacketListenerImplMixin.java index 88c20171..e3bbb437 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerHandshakePacketListenerImplMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerHandshakePacketListenerImplMixin.java @@ -13,9 +13,9 @@ import net.minecraft.server.network.ServerHandshakePacketListenerImpl; import org.adde0109.pcf.PCF; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.Mode; import org.adde0109.pcf.forwarding.legacy.ConnectionBridgeLegacy; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplMixin.java index f1592689..840ec438 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplMixin.java @@ -11,7 +11,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.server.network.ServerLoginPacketListenerImpl; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import org.slf4j.Logger; diff --git a/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json b/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json index 7bec5b0e..af4961cd 100644 --- a/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json +++ b/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json @@ -10,11 +10,11 @@ "server": [ "v26_1.crossstich.ArgumentNodeStubMixin", "v26_1.crossstich.ArgumentTypeInfoMixin", + "v26_1.forwarding.ConnectionMixin", "v26_1.forwarding.legacy.ClientIntentionPacketMixin", "v26_1.forwarding.legacy.ConnectionLegacyMixin", "v26_1.forwarding.legacy.ServerHandshakePacketListenerImplMixin", "v26_1.forwarding.legacy.ServerLoginPacketListenerImplHelloMixin", - "v26_1.forwarding.modern.ConnectionMixin", "v26_1.forwarding.modern.ServerLoginPacketListenerImplHelloHybridMixin", "v26_1.forwarding.modern.ServerLoginPacketListenerImplHelloMixin", "v26_1.forwarding.modern.ServerLoginPacketListenerImplMixin" diff --git a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ConnectionMixin.java b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ConnectionMixin.java similarity index 93% rename from legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ConnectionMixin.java rename to legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ConnectionMixin.java index c9dff544..84609d2e 100644 --- a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ConnectionMixin.java +++ b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ConnectionMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v12_2.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v12_2.forge.forwarding; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; @@ -12,7 +12,7 @@ import net.minecraft.network.INetHandler; import net.minecraft.network.NetworkManager; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.Final; diff --git a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java index a407f474..6a6cc92e 100644 --- a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java @@ -11,7 +11,7 @@ import net.minecraft.server.network.NetHandlerLoginServer; import net.minecraft.util.text.ITextComponent; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; import org.apache.logging.log4j.Logger; import org.jspecify.annotations.NonNull; diff --git a/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json b/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json index d6446391..ee3cc450 100644 --- a/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json +++ b/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json @@ -8,7 +8,7 @@ "plugin": "org.adde0109.pcf.mixin.plugin.PCFMixinPlugin", "package": "org.adde0109.pcf.mixin", "server": [ - "v12_2.forge.forwarding.modern.ConnectionMixin", + "v12_2.forge.forwarding.ConnectionMixin", "v12_2.forge.forwarding.modern.ServerLoginPacketListenerImplHelloMixin", "v12_2.forge.forwarding.modern.ServerLoginPacketListenerImplMixin", "v12_2.forge.forwarding.modern.ServerLoginPacketListenerImplMixin$SLPLIMixin_12" diff --git a/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java index 4638354b..4a746826 100644 --- a/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java @@ -13,7 +13,7 @@ import net.minecraft.network.NetworkManager; import net.minecraft.util.text.ITextComponent; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; import org.apache.logging.log4j.Logger; import org.jspecify.annotations.NonNull; diff --git a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ConnectionMixin.java b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ConnectionMixin.java similarity index 93% rename from modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ConnectionMixin.java rename to modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ConnectionMixin.java index 50f89d62..246fe622 100644 --- a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ConnectionMixin.java +++ b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ConnectionMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v16_5.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v16_5.forge.forwarding; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; @@ -12,7 +12,7 @@ import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.PacketListener; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.Final; diff --git a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java index 1f94b4c1..03178fc8 100644 --- a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java @@ -14,7 +14,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.server.network.ServerLoginPacketListenerImpl; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; import org.apache.commons.lang3.Validate; import org.apache.logging.log4j.Logger; diff --git a/modern/v16_5/src/forge/resources/pcf.mixins.v16_5.forge.json b/modern/v16_5/src/forge/resources/pcf.mixins.v16_5.forge.json index 8250d302..1b3365fe 100644 --- a/modern/v16_5/src/forge/resources/pcf.mixins.v16_5.forge.json +++ b/modern/v16_5/src/forge/resources/pcf.mixins.v16_5.forge.json @@ -11,7 +11,7 @@ "v16_5.forge.crossstitch.ArgumentTypesAccessor", "v16_5.forge.crossstitch.ArgumentTypesEntryMixin", "v16_5.forge.crossstitch.CommandsPacketMixin", - "v16_5.forge.forwarding.modern.ConnectionMixin", + "v16_5.forge.forwarding.ConnectionMixin", "v16_5.forge.forwarding.modern.ServerLoginPacketListenerImplMixin" ] } diff --git a/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ConnectionMixin.java b/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/ConnectionMixin.java similarity index 91% rename from modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ConnectionMixin.java rename to modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/ConnectionMixin.java index f2b7cca5..6791bd75 100644 --- a/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ConnectionMixin.java +++ b/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/ConnectionMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v19_2.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v19_2.forge.forwarding; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; @@ -12,7 +12,7 @@ import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.PacketListener; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; diff --git a/modern/v19_2/src/forge/resources/pcf.mixins.v19_2.forge.json b/modern/v19_2/src/forge/resources/pcf.mixins.v19_2.forge.json index 61ff1a19..133aed07 100644 --- a/modern/v19_2/src/forge/resources/pcf.mixins.v19_2.forge.json +++ b/modern/v19_2/src/forge/resources/pcf.mixins.v19_2.forge.json @@ -8,7 +8,7 @@ "plugin": "org.adde0109.pcf.mixin.plugin.PCFMixinPlugin", "package": "org.adde0109.pcf.mixin", "server": [ - "v19_2.forge.forwarding.modern.ConnectionMixin", + "v19_2.forge.forwarding.ConnectionMixin", "v19_2.forge.forwarding.modern.LastSeenMessagesValidatorMixin", "v19_2.forge.forwarding.modern.PlayerChatMessageMixin", "v19_2.forge.forwarding.modern.ServerLoginPacketListenerImplKeyV1Mixin", diff --git a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ConnectionMixin.java b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ConnectionMixin.java similarity index 93% rename from modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ConnectionMixin.java rename to modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ConnectionMixin.java index c1b0d945..e4d2e8bb 100644 --- a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ConnectionMixin.java +++ b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ConnectionMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v20_4.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v20_4.forge.forwarding; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; @@ -9,7 +9,7 @@ import net.minecraft.network.Connection; import net.minecraft.network.PacketListener; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; diff --git a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java index ceee182b..6772624c 100644 --- a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java @@ -11,7 +11,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.server.network.ServerLoginPacketListenerImpl; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; diff --git a/modern/v20_4/src/forge/resources/pcf.mixins.v20_4.forge.json b/modern/v20_4/src/forge/resources/pcf.mixins.v20_4.forge.json index f444e6e2..b404d10e 100644 --- a/modern/v20_4/src/forge/resources/pcf.mixins.v20_4.forge.json +++ b/modern/v20_4/src/forge/resources/pcf.mixins.v20_4.forge.json @@ -10,7 +10,7 @@ "server": [ "v20_4.forge.crossstitch.ArgumentNodeStubMixin", "v20_4.forge.crossstitch.ArgumentTypeInfoMixin", - "v20_4.forge.forwarding.modern.ConnectionMixin", + "v20_4.forge.forwarding.ConnectionMixin", "v20_4.forge.forwarding.modern.ServerLoginPacketListenerImplLoggerMixin", "v20_4.forge.forwarding.modern.ServerLoginPacketListenerImplMixin" ] From 65656229459e24a5e0f81cdda25cc44b362d9a2d Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 03:27:16 -0600 Subject: [PATCH 05/71] Disable mixins in the forwarding.legacy package if the mode is not LEGACY --- .../java/org/adde0109/pcf/mixin/plugin/PCFMixinPlugin.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common/src/main/java/org/adde0109/pcf/mixin/plugin/PCFMixinPlugin.java b/common/src/main/java/org/adde0109/pcf/mixin/plugin/PCFMixinPlugin.java index 2c0cb1fd..234aaec8 100644 --- a/common/src/main/java/org/adde0109/pcf/mixin/plugin/PCFMixinPlugin.java +++ b/common/src/main/java/org/adde0109/pcf/mixin/plugin/PCFMixinPlugin.java @@ -86,6 +86,10 @@ private static boolean shouldApplyMixin( PCF.logger.debug("Skipping mixin " + m + " because forwarding mode is not MODERN."); return false; } + if (forwarding.mode() != Mode.LEGACY && m.contains(".forwarding.legacy.")) { + PCF.logger.debug("Skipping mixin " + m + " because forwarding mode is not LEGACY."); + return false; + } if (advanced.modernForwardingVersion() != NO_OVERRIDE && Constraint.builder().version(MinecraftVersions.V19).result() && advanced.modernForwardingVersion() != MODERN_FORWARDING_WITH_KEY From 4dbdfc8af469f42ee41a159ebdf4725e611cd3d0 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 03:38:36 -0600 Subject: [PATCH 06/71] Missed a package change --- common/src/main/resources/pcf.mixins.common.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/main/resources/pcf.mixins.common.json b/common/src/main/resources/pcf.mixins.common.json index 204d63a5..f4833e26 100644 --- a/common/src/main/resources/pcf.mixins.common.json +++ b/common/src/main/resources/pcf.mixins.common.json @@ -8,7 +8,7 @@ "plugin": "org.adde0109.pcf.mixin.plugin.PCFMixinPlugin", "package": "org.adde0109.pcf.mixin", "server": [ - "common.forwarding.modern.ConnectionMixin$Mojang", - "common.forwarding.modern.ConnectionMixin$Searge" + "common.forwarding.ConnectionMixin$Mojang", + "common.forwarding.ConnectionMixin$Searge" ] } From 7e51f457cbd989b72abc34a50c00a3d44d42d740 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 06:22:24 -0600 Subject: [PATCH 07/71] Moved intention packet handling into the decoder --- common/build.gradle.kts | 1 + .../pcf/forwarding/PacketDecoder.java | 119 +++++++++++------ .../legacy/ConnectionBridgeLegacy.java | 17 --- .../forwarding/legacy/LegacyForwarding.java | 123 ++++++++++++++++++ .../legacy/ClientIntentionPacketMixin.java | 20 --- .../legacy/ConnectionLegacyMixin.java | 88 ------------- ...erverHandshakePacketListenerImplMixin.java | 115 ---------------- ...rverLoginPacketListenerImplHelloMixin.java | 20 +-- .../src/main/resources/pcf.mixins.v26_1.json | 3 - gradle/libs.versions.toml | 1 + 10 files changed, 218 insertions(+), 289 deletions(-) delete mode 100644 common/src/main/java/org/adde0109/pcf/forwarding/legacy/ConnectionBridgeLegacy.java create mode 100644 common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java delete mode 100644 deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ClientIntentionPacketMixin.java delete mode 100644 deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ConnectionLegacyMixin.java delete mode 100644 deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerHandshakePacketListenerImplMixin.java diff --git a/common/build.gradle.kts b/common/build.gradle.kts index b6e37cb0..2c2272d8 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -23,6 +23,7 @@ dependencies { compileOnly(libs.annotations) compileOnly(libs.mojang.authlib) compileOnly(libs.mojang.brigadier) + compileOnly(libs.gson) compileOnly(libs.guava) compileOnly(libs.jspecify) compileOnly(libs.mixin) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 9cb1c2e5..0e21ae7d 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -1,10 +1,10 @@ package org.adde0109.pcf.forwarding; import static org.adde0109.pcf.forwarding.ConnectionBridge.HANDLER_PACKET; +import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.handleClientIntentionPacket; import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleCustomQueryPacket; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; -import dev.neuralnexus.taterapi.network.Protocol; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; import dev.neuralnexus.taterapi.network.protocol.login.ServerboundCustomQueryAnswerPacket; @@ -33,50 +33,93 @@ protected void decode( } final ConnectionBridge connection = ((ConnectionBridge) ctx.channel().pipeline().get(HANDLER_PACKET)); - if (!(connection.bridge$protocol() == Protocol.LOGIN)) { - out.add(msg.retain()); - return; - } - if (!(connection.bridge$getPacketListener() - instanceof ServerLoginPacketListenerBridge slpl)) { - out.add(msg.retain()); - return; - } - final int readerIndex = msg.readerIndex(); - final FriendlyByteBuf data = new FriendlyByteBuf(msg); - final int id = data.readVarInt(); - PCF.logger.debug( - "Received packet with ID 0x" - + Integer.toHexString(id) - + " from " - + ctx.channel().remoteAddress()); - - //noinspection SwitchStatementWithTooFewBranches - switch (id) { - case 0x02 -> { - final ServerboundCustomQueryAnswerPacket packet = - ServerboundCustomQueryAnswerPacket.STREAM_CODEC.decode(data); - - // Check if the packet should be handled - if (packet.transactionId() != slpl.bridge$velocityLoginMessageId()) { - msg.readerIndex(readerIndex); - break; + switch (connection.bridge$protocol()) { + case null -> {} + case HANDSHAKING -> { + if (PCF.instance().forwarding().mode() != Mode.LEGACY + && PCF.instance().forwarding().mode() != Mode.BUNGEEGUARD) { + out.add(msg.retain()); + return; + } + + final int readerIndex = msg.readerIndex(); + final FriendlyByteBuf data = new FriendlyByteBuf(msg); + final int id = data.readVarInt(); + PCF.logger.debug( + "Received packet with ID 0x" + + Integer.toHexString(id) + + " from " + + ctx.channel().remoteAddress()); + + //noinspection SwitchStatementWithTooFewBranches + switch (id) { + case 0x00 -> { + PCF.logger.debug( + "Handling ClientIntentionPacket from " + + ctx.channel().remoteAddress()); + + try { + handleClientIntentionPacket(connection, data); + } catch (final ThrowingComponent e) { + throw e; + // connection.bridge$disconnect(e.getComponent()); + } finally { + // Reset reader index and pass it along + msg.readerIndex(readerIndex); + } + } + // Reset reader index for unhandled packets + default -> msg.readerIndex(readerIndex); + } + } + case LOGIN -> { + if (!(connection.bridge$getPacketListener() + instanceof ServerLoginPacketListenerBridge slpl)) { + out.add(msg.retain()); + return; } + + final int readerIndex = msg.readerIndex(); + final FriendlyByteBuf data = new FriendlyByteBuf(msg); + final int id = data.readVarInt(); PCF.logger.debug( - "Handling ServerboundCustomQueryAnswerPacket from " + "Received packet with ID 0x" + + Integer.toHexString(id) + + " from " + ctx.channel().remoteAddress()); - try { - handleCustomQueryPacket(slpl, packet); - } catch (final ThrowingComponent e) { - slpl.bridge$disconnect(e.getComponent()); - } finally { - msg.clear(); + //noinspection SwitchStatementWithTooFewBranches + switch (id) { + case 0x02 -> { + final ServerboundCustomQueryAnswerPacket packet = + ServerboundCustomQueryAnswerPacket.STREAM_CODEC.decode(data); + + // Check if the packet should be handled + if (packet.transactionId() != slpl.bridge$velocityLoginMessageId()) { + msg.readerIndex(readerIndex); + break; + } + PCF.logger.debug( + "Handling ServerboundCustomQueryAnswerPacket from " + + ctx.channel().remoteAddress()); + + try { + handleCustomQueryPacket(slpl, packet); + } catch (final ThrowingComponent e) { + slpl.bridge$disconnect(e.getComponent()); + } finally { + msg.clear(); + } + } + // Reset reader index for unhandled packets + default -> msg.readerIndex(readerIndex); } } - // Reset reader index for unhandled packets - default -> msg.readerIndex(readerIndex); + default -> { + out.add(msg.retain()); + return; + } } if (msg.isReadable()) { diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/ConnectionBridgeLegacy.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/ConnectionBridgeLegacy.java deleted file mode 100644 index 79e415a4..00000000 --- a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/ConnectionBridgeLegacy.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.adde0109.pcf.forwarding.legacy; - -import com.mojang.authlib.properties.Property; - -import org.jspecify.annotations.NonNull; - -import java.util.UUID; - -public interface ConnectionBridgeLegacy { - UUID bridge$spoofedUUID(); - - void bridge$spoofedUUID(final @NonNull UUID uuid); - - Property[] bridge$spoofedProfile(); - - void bridge$spoofedProfile(final @NonNull Property[] properties); -} diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java new file mode 100644 index 00000000..40ad081d --- /dev/null +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java @@ -0,0 +1,123 @@ +package org.adde0109.pcf.forwarding.legacy; + +import static dev.neuralnexus.taterapi.network.chat.Component.literal; + +import com.google.common.net.InetAddresses; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.mojang.authlib.properties.Property; + +import dev.neuralnexus.taterapi.network.FriendlyByteBuf; +import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; +import dev.neuralnexus.taterapi.network.protocol.handshake.ClientIntent; +import dev.neuralnexus.taterapi.network.protocol.handshake.ClientIntentionPacket; + +import io.netty.util.AttributeKey; + +import org.adde0109.pcf.PCF; +import org.adde0109.pcf.forwarding.ConnectionBridge; +import org.adde0109.pcf.forwarding.Mode; +import org.jspecify.annotations.NonNull; + +import java.net.InetSocketAddress; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.regex.Pattern; + +public final class LegacyForwarding { + public static final AttributeKey SPOOFED_UUID = AttributeKey.valueOf("pcf-spoofed-uuid"); + public static final AttributeKey> SPOOFED_PROFILE = + AttributeKey.valueOf("pcf-spoofed-profile"); + + private static final char LEGACY_SEPARATOR = '\0'; + private static final String BUNGEE_GUARD_TOKEN_PROPERTY_NAME = "bungeeguard-token"; + + private static final Gson GSON = new GsonBuilder().create(); + private static final TypeToken> profileTypeToken = new TypeToken<>() {}; + + private static final Pattern HOST_PATTERN = Pattern.compile("[0-9a-f.:]{0,45}"); + + private static final Object DIRECT_CONNECT_ERR = // TODO: Consider two different messages + literal("This server requires you to connect with Velocity or BungeeCord."); + private static final Object BG_CONFIG_ERR = + literal("This server requires the proxy to be configured for BungeeGuard forwarding."); + + // https://hub.spigotmc.org/stash/projects/SPIGOT/repos/spigot/browse/CraftBukkit-Patches/0024-BungeeCord-Support.patch + // https://github.com/caunt/BungeeForge/blob/1.20.2/src/main/java/ua/caunt/bungeeforge/mixin/network/protocol/handshake/ClientIntentionPacket.java#L51-L54 + public static void handleClientIntentionPacket( + final @NonNull ConnectionBridge connection, final @NonNull FriendlyByteBuf data) { + final int protocolVersion = data.readVarInt(); + final String hostName = data.readUtf(Short.MAX_VALUE); + final int _ = data.readUnsignedShort(); + final ClientIntent intention = ClientIntent.byId(data.readVarInt()); + if (intention != ClientIntent.LOGIN) { + return; + } + + final String[] split = hostName.split("\00"); + if ((split.length < 3) || !(HOST_PATTERN.matcher(split[1]).matches())) { + throw new ThrowingComponent(DIRECT_CONNECT_ERR); + } + if (PCF.instance().forwarding().mode() != Mode.BUNGEEGUARD && (split.length < 4)) { + throw new ThrowingComponent(BG_CONFIG_ERR); + } + + final String originalHost = split[0]; + final String forwardedAddress = split[1]; + final UUID uuid = fromStringLenient(split[2]); + PCF.logger.debug( + "Player " + uuid + " is connecting with forwarded address " + forwardedAddress); + + // Update the proxied address + final int port = connection.bridge$address().getPort(); + final InetSocketAddress address = + new InetSocketAddress(InetAddresses.forString(forwardedAddress), port); + connection.bridge$address(address); + + // Save the UUID + connection.bridge$channel().attr(SPOOFED_UUID).set(uuid); + + // Save the properties if present + final Optional fmlMarker; + if (split.length == 4) { + final String profileJSON = split[3]; + final List properties = GSON.fromJson(profileJSON, profileTypeToken); + + // Pop out the FML marker if present + fmlMarker = properties.stream().filter(LegacyForwarding::isFmlMarker).findFirst(); + properties.removeIf(LegacyForwarding::isFmlMarker); + connection.bridge$channel().attr(SPOOFED_PROFILE).set(properties); + } else { + fmlMarker = Optional.empty(); + } + + // spotless:off + final String host = fmlMarker.map(property -> originalHost + + LEGACY_SEPARATOR + + property.value().split("\u0001")[1] + + LEGACY_SEPARATOR).orElse(originalHost); + // spotless:on + + // Write the original address back into packet + final ClientIntentionPacket newPacket = + new ClientIntentionPacket(protocolVersion, host, port, intention); + data.clear(); + data.writeVarInt(0x00); + ClientIntentionPacket.STREAM_CODEC.encode(data, newPacket); + } + + private static @NonNull UUID fromStringLenient(final @NonNull String string) { + return UUID.fromString( + string.replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5")); + } + + // https://github.com/caunt/BungeeForge/blob/1.20.2/src/main/java/ua/caunt/bungeeforge/mixin/network/protocol/handshake/ClientIntentionPacket.java#L51-L54 + private static boolean isFmlMarker(final @NonNull Property property) { + return Objects.equals(property.name(), "extraData") + && property.value().startsWith("\u0001FORGE"); + } +} diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ClientIntentionPacketMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ClientIntentionPacketMixin.java deleted file mode 100644 index 5e568590..00000000 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ClientIntentionPacketMixin.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.adde0109.pcf.mixin.v26_1.forwarding.legacy; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.protocol.handshake.ClientIntentionPacket; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -// https://github.com/caunt/BungeeForge/blob/1.20.2/src/main/java/ua/caunt/bungeeforge/mixin/network/protocol/handshake/ClientIntentionPacket.java#L28 -@Mixin(ClientIntentionPacket.class) -public final class ClientIntentionPacketMixin { - // spotless:off - @Redirect(method = "(Lnet/minecraft/network/FriendlyByteBuf;)V", at = @At(value = "INVOKE", - target = "Lnet/minecraft/network/FriendlyByteBuf;readUtf(I)Ljava/lang/String;")) - // spotless:on - private static String onConstruct(final FriendlyByteBuf input, int length) { - return input.readUtf(Short.MAX_VALUE); - } -} diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ConnectionLegacyMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ConnectionLegacyMixin.java deleted file mode 100644 index 01c77d59..00000000 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ConnectionLegacyMixin.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.adde0109.pcf.mixin.v26_1.forwarding.legacy; - -import com.mojang.authlib.properties.Property; - -import dev.neuralnexus.taterapi.meta.Mappings; -import dev.neuralnexus.taterapi.meta.anno.AConstraint; -import dev.neuralnexus.taterapi.network.Protocol; - -import io.netty.channel.Channel; - -import net.minecraft.network.Connection; -import net.minecraft.network.PacketListener; - -import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.adde0109.pcf.forwarding.legacy.ConnectionBridgeLegacy; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; - -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.util.UUID; - -@AConstraint(mappings = Mappings.MOJANG) -@Mixin(Connection.class) -public abstract class ConnectionLegacyMixin implements ConnectionBridge, ConnectionBridgeLegacy { - // spotless:off - @Shadow private SocketAddress address; - @Shadow public abstract PacketListener shadow$getPacketListener(); - @Shadow public abstract Channel channel(); - // spotless:on - - @Override - public @NonNull InetSocketAddress bridge$address() { - return (InetSocketAddress) this.address; - } - - @Override - public void bridge$address(final @NonNull InetSocketAddress address) { - this.address = address; - } - - @Override - public @NonNull Channel bridge$channel() { - return this.channel(); - } - - @Override - public @Nullable Object bridge$getPacketListener() { - return this.shadow$getPacketListener(); - } - - @Override - public Protocol bridge$protocol() { - final PacketListener listener = this.shadow$getPacketListener(); - if (listener == null) { - return null; - } - return Protocol.fromId(listener.protocol().id()); - } - - // spotless:off - @Unique private UUID pcf$spoofedUUID = null; - @Unique private Property[] pcf$spoofedProfile = null; - // spotless:on - - @Override - public UUID bridge$spoofedUUID() { - return this.pcf$spoofedUUID; - } - - @Override - public void bridge$spoofedUUID(final @NonNull UUID uuid) { - this.pcf$spoofedUUID = uuid; - } - - @Override - public Property[] bridge$spoofedProfile() { - return this.pcf$spoofedProfile; - } - - @Override - public void bridge$spoofedProfile(final @NonNull Property[] properties) { - this.pcf$spoofedProfile = properties; - } -} diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerHandshakePacketListenerImplMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerHandshakePacketListenerImplMixin.java deleted file mode 100644 index e3bbb437..00000000 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerHandshakePacketListenerImplMixin.java +++ /dev/null @@ -1,115 +0,0 @@ -package org.adde0109.pcf.mixin.v26_1.forwarding.legacy; - -import static dev.neuralnexus.taterapi.network.chat.Component.literal; - -import com.google.common.net.InetAddresses; -import com.google.gson.Gson; -import com.mojang.authlib.properties.Property; - -import net.minecraft.network.Connection; -import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.handshake.ClientIntentionPacket; -import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket; -import net.minecraft.server.network.ServerHandshakePacketListenerImpl; - -import org.adde0109.pcf.PCF; -import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.adde0109.pcf.forwarding.Mode; -import org.adde0109.pcf.forwarding.legacy.ConnectionBridgeLegacy; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.net.InetSocketAddress; -import java.util.Objects; -import java.util.UUID; -import java.util.regex.Pattern; - -// https://hub.spigotmc.org/stash/projects/SPIGOT/repos/spigot/browse/CraftBukkit-Patches/0024-BungeeCord-Support.patch -@Mixin(ServerHandshakePacketListenerImpl.class) -public abstract class ServerHandshakePacketListenerImplMixin { - // spotless:off - @Shadow @Final private Connection connection; - - @Unique private static final char pcf$LEGACY_SEPARATOR = '\0'; - @Unique private static final String pcf$BUNGEE_GUARD_TOKEN_PROPERTY_NAME = "bungeeguard-token"; - - @Unique private static final Gson pcf$gson = new Gson(); - @Unique private static final Pattern pcf$HOST_PATTERN = Pattern.compile("[0-9a-f.:]{0,45}"); - - @Unique private static final Object pcf$DIRECT_CONNECT_ERR = // TODO: Consider two different messages - literal("This server requires you to connect with Velocity or BungeeCord."); - @Unique private static final Object pcf$BG_CONFIG_ERR = - literal("This server requires the proxy to be configured for BungeeGuard forwarding."); - - @Inject(method = "beginLogin", cancellable = true, at = @At(value = "RETURN", - target = "Lnet/minecraft/network/Connection;setupInboundProtocol(Lnet/minecraft/network/ProtocolInfo;Lnet/minecraft/network/PacketListener;)V")) - // spotless:on - private void onBeginLogin( - final ClientIntentionPacket packet, final boolean transfer, final CallbackInfo ci) { - if (PCF.instance().forwarding().mode() != Mode.LEGACY - && PCF.instance().forwarding().mode() != Mode.BUNGEEGUARD) return; - - // Spigot Start - // TODO: Stick this in a packet listener and extract it there and add to the - // ConnectionBridgeLegacy - // Then replace the original serverAddress used for the regular login flow - // Do not forget Forge markers if present - final String[] split = packet.hostName().split("\00"); - PCF.logger.info( - "Received handshake with " - + split.length - + " parts: " - + String.join("\n ", split)); - if ((split.length < 3) || !(pcf$HOST_PATTERN.matcher(split[1]).matches())) { - this.pcf$disconnect(pcf$DIRECT_CONNECT_ERR); - return; - } - if ((split.length < 4) && PCF.instance().forwarding().mode() != Mode.BUNGEEGUARD) { - this.pcf$disconnect(pcf$BG_CONFIG_ERR); - return; - } - - final String originalAddress = split[1]; - final UUID uuid = pcf$fromStringLenient(split[2]); - PCF.logger.info( - "Player " + uuid + " is connecting with original address " + originalAddress); - - // Update the proxied address - final int port = ((ConnectionBridge) this.connection).bridge$address().getPort(); - final InetSocketAddress address = - new InetSocketAddress(InetAddresses.forString(originalAddress), port); - ((ConnectionBridge) this.connection).bridge$address(address); - - // Save the UUID - ((ConnectionBridgeLegacy) this.connection).bridge$spoofedUUID(uuid); - - // Save the properties if present - if (split.length == 4) { // TODO: Enforce if BungeeGuard forwarding - final String profileJSON = split[3]; - ((ConnectionBridgeLegacy) this.connection) - .bridge$spoofedProfile(pcf$gson.fromJson(profileJSON, Property[].class)); - } - // Spigot End - } - - @Unique public void pcf$disconnect(Object component) { - this.connection.send(new ClientboundLoginDisconnectPacket((Component) component)); - this.connection.disconnect((Component) component); - } - - @Unique private static UUID pcf$fromStringLenient(final String string) { - return UUID.fromString( - string.replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5")); - } - - // https://github.com/caunt/BungeeForge/blob/1.20.2/src/main/java/ua/caunt/bungeeforge/mixin/network/protocol/handshake/ClientIntentionPacket.java#L51-L54 - @Unique private static boolean pcf$isFmlMarker(Property property) { - return Objects.equals(property.name(), "extraData") - && property.value().startsWith("\u0001FORGE"); - } -} diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java index f67d72ce..3414ec7e 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java @@ -1,5 +1,7 @@ package org.adde0109.pcf.mixin.v26_1.forwarding.legacy; +import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.SPOOFED_PROFILE; +import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.SPOOFED_UUID; import static org.adde0109.pcf.forwarding.modern.ReflectionUtils.getProperties; import com.mojang.authlib.GameProfile; @@ -15,7 +17,7 @@ import net.minecraft.network.protocol.login.ServerboundHelloPacket; import net.minecraft.server.network.ServerLoginPacketListenerImpl; -import org.adde0109.pcf.forwarding.legacy.ConnectionBridgeLegacy; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.Final; @@ -47,8 +49,9 @@ public abstract class ServerLoginPacketListenerImplHelloMixin // spotless:on private void onHandleHello_20_M( final ServerboundHelloPacket packet, final @NonNull CallbackInfo ci) { - ConnectionBridgeLegacy conn = (ConnectionBridgeLegacy) this.connection; - if (conn.bridge$spoofedProfile() == null) { + final ConnectionBridge conn = (ConnectionBridge) this.connection; + + if (conn.bridge$channel().attr(SPOOFED_UUID).get() == null) { return; // TODO: Provide client-bound disconnect error } @@ -59,9 +62,11 @@ private void onHandleHello_20_M( // Spigot start @Unique protected GameProfile pcf$createOfflineProfile(String name) { + final ConnectionBridge conn = (ConnectionBridge) this.connection; + final UUID uuid; - if (((ConnectionBridgeLegacy) this.connection).bridge$spoofedUUID() != null) { - uuid = ((ConnectionBridgeLegacy) this.connection).bridge$spoofedUUID(); + if (conn.bridge$channel().attr(SPOOFED_UUID).get() != null) { + uuid = conn.bridge$channel().attr(SPOOFED_UUID).get(); } else { uuid = UUID.nameUUIDFromBytes( @@ -71,9 +76,8 @@ private void onHandleHello_20_M( // TODO: Add 1.21.9 support final GameProfile profile = new GameProfile(uuid, name); final PropertyMap propertiesMap = getProperties(profile); - if (((ConnectionBridgeLegacy) this.connection).bridge$spoofedProfile() != null) { - for (final Property property : - ((ConnectionBridgeLegacy) this.connection).bridge$spoofedProfile()) { + if (conn.bridge$channel().attr(SPOOFED_PROFILE).get() != null) { + for (final Property property : conn.bridge$channel().attr(SPOOFED_PROFILE).get()) { if (!pcf$PROP_PATTERN.matcher(property.name()).matches()) continue; propertiesMap.put(property.name(), property); } diff --git a/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json b/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json index af4961cd..ce16ba82 100644 --- a/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json +++ b/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json @@ -11,9 +11,6 @@ "v26_1.crossstich.ArgumentNodeStubMixin", "v26_1.crossstich.ArgumentTypeInfoMixin", "v26_1.forwarding.ConnectionMixin", - "v26_1.forwarding.legacy.ClientIntentionPacketMixin", - "v26_1.forwarding.legacy.ConnectionLegacyMixin", - "v26_1.forwarding.legacy.ServerHandshakePacketListenerImplMixin", "v26_1.forwarding.legacy.ServerLoginPacketListenerImplHelloMixin", "v26_1.forwarding.modern.ServerLoginPacketListenerImplHelloHybridMixin", "v26_1.forwarding.modern.ServerLoginPacketListenerImplHelloMixin", diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0757bac7..3366302c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,6 +11,7 @@ unimined = "1.3.16-SNAPSHOT" annotations = { group = "org.jetbrains", name = "annotations", version = "26.0.2" } asm-tree = { group = "org.ow2.asm", name = "asm-tree", version = "6.2" } entrypoint-spoof = { group = "dev.neuralnexus", name = "entrypoint-spoof", version = "0.1.30" } +gson = { group = "com.google.code.gson", name = "gson", version = "2.13.2" } guava = { group = "com.google.guava", name = "guava", version = "33.3.1-jre" } jspecify = { group = "org.jspecify", name = "jspecify", version = "1.0.0" } mixin = { group = "org.spongepowered", name = "mixin", version = "0.8.5-SNAPSHOT" } From cf2bf1bcba2e729c889d01dc110b053e5052fdf3 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 07:01:08 -0600 Subject: [PATCH 08/71] Switch to using a Netty attribute for modern forwarding login message ids --- .../adde0109/pcf/forwarding/PacketDecoder.java | 15 ++++++++++++--- .../pcf/forwarding/modern/ModernForwarding.java | 16 ++++++++++------ .../modern/ServerLoginPacketListenerBridge.java | 4 ---- .../ServerLoginPacketListenerImplMixin.java | 12 ------------ .../ServerLoginPacketListenerImplMixin.java | 12 ------------ .../ServerLoginPacketListenerImplMixin.java | 12 ------------ .../ServerLoginPacketListenerImplMixin.java | 12 ------------ .../ServerLoginPacketListenerImplMixin.java | 13 ------------- 8 files changed, 22 insertions(+), 74 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 0e21ae7d..655dfac7 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -2,6 +2,7 @@ import static org.adde0109.pcf.forwarding.ConnectionBridge.HANDLER_PACKET; import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.handleClientIntentionPacket; +import static org.adde0109.pcf.forwarding.modern.ModernForwarding.LOGIN_MESSAGE_ID; import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleCustomQueryPacket; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; @@ -37,8 +38,9 @@ protected void decode( switch (connection.bridge$protocol()) { case null -> {} case HANDSHAKING -> { - if (PCF.instance().forwarding().mode() != Mode.LEGACY - && PCF.instance().forwarding().mode() != Mode.BUNGEEGUARD) { + if (!PCF.instance().forwarding().enabled() + || (PCF.instance().forwarding().mode() != Mode.LEGACY + && PCF.instance().forwarding().mode() != Mode.BUNGEEGUARD)) { out.add(msg.retain()); return; } @@ -74,6 +76,12 @@ protected void decode( } } case LOGIN -> { + if (!PCF.instance().forwarding().enabled() + || !PCF.instance().forwarding().mode().equals(Mode.MODERN)) { + out.add(msg.retain()); + return; + } + if (!(connection.bridge$getPacketListener() instanceof ServerLoginPacketListenerBridge slpl)) { out.add(msg.retain()); @@ -96,7 +104,8 @@ protected void decode( ServerboundCustomQueryAnswerPacket.STREAM_CODEC.decode(data); // Check if the packet should be handled - if (packet.transactionId() != slpl.bridge$velocityLoginMessageId()) { + if (packet.transactionId() + != connection.bridge$channel().attr(LOGIN_MESSAGE_ID).get()) { msg.readerIndex(readerIndex); break; } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index 27a5366f..9bda8de7 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -20,9 +20,11 @@ import dev.neuralnexus.taterapi.network.protocol.login.custom.CustomQueryAnswerPayload; import io.netty.handler.codec.DecoderException; +import io.netty.util.AttributeKey; import io.netty.util.concurrent.Future; import org.adde0109.pcf.PCF; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.Mode; import org.jetbrains.annotations.ApiStatus; import org.jspecify.annotations.NonNull; @@ -51,6 +53,9 @@ * 1.20.x */ public final class ModernForwarding { + public static final AttributeKey LOGIN_MESSAGE_ID = + AttributeKey.valueOf("pcf-login-message-id"); + private static final Object REJECTED_PROXY_ERR = literal("Unapproved proxy host."); /** @@ -76,10 +81,11 @@ public static void handleHello( || !PCF.instance().forwarding().mode().equals(Mode.MODERN)) { return; } + final ConnectionBridge connection = slpl.bridge$connection(); final List approved = PCF.instance().forwarding().approvedProxyHosts(); if (!approved.isEmpty()) { - final InetSocketAddress address = slpl.bridge$connection().bridge$address(); + final InetSocketAddress address = connection.bridge$address(); final String host = address.getHostString(); final String ip = address.getAddress().getHostAddress(); if (!approved.contains(host) && !approved.contains(ip)) { @@ -95,11 +101,9 @@ public static void handleHello( } } - slpl.bridge$setVelocityLoginMessageId(ThreadLocalRandom.current().nextInt()); - slpl.bridge$connection() - .bridge$send( - new ClientboundCustomQueryPacket( - slpl.bridge$velocityLoginMessageId(), PLAYER_INFO_PAYLOAD)); + final int messageId = ThreadLocalRandom.current().nextInt(); + connection.bridge$channel().attr(LOGIN_MESSAGE_ID).set(messageId); + connection.bridge$send(new ClientboundCustomQueryPacket(messageId, PLAYER_INFO_PAYLOAD)); PCF.logger.debug("Sent Forward Request"); ci.cancel(); } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ServerLoginPacketListenerBridge.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ServerLoginPacketListenerBridge.java index 0686d116..f9af4a60 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ServerLoginPacketListenerBridge.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ServerLoginPacketListenerBridge.java @@ -11,10 +11,6 @@ import java.util.UUID; public interface ServerLoginPacketListenerBridge { - int bridge$velocityLoginMessageId(); - - void bridge$setVelocityLoginMessageId(final int id); - @NonNull ConnectionBridge bridge$connection(); void bridge$disconnect(final @NonNull Object reason); diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplMixin.java index 840ec438..2dde090a 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplMixin.java @@ -18,7 +18,6 @@ import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; @AConstraint(mappings = Mappings.MOJANG, version = @Versions(min = MinecraftVersion.V20_2)) @Mixin(ServerLoginPacketListenerImpl.class) @@ -30,19 +29,8 @@ public abstract class ServerLoginPacketListenerImplMixin @Shadow public abstract void shadow$disconnect(Component details); @Shadow protected abstract void shadow$startClientVerification(GameProfile profile); @Shadow private GameProfile authenticatedProfile; - @Unique private int pcf$velocityLoginMessageId = -1; // spotless:on - @Override - public int bridge$velocityLoginMessageId() { - return this.pcf$velocityLoginMessageId; - } - - @Override - public void bridge$setVelocityLoginMessageId(final int id) { - this.pcf$velocityLoginMessageId = id; - } - @Override public @NonNull ConnectionBridge bridge$connection() { return (ConnectionBridge) this.connection; diff --git a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java index 6a6cc92e..e05d71c9 100644 --- a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java @@ -18,7 +18,6 @@ import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; @AConstraint( mappings = Mappings.SEARGE, @@ -30,19 +29,8 @@ public abstract class ServerLoginPacketListenerImplMixin @Shadow @Final public NetworkManager networkManager; @Shadow private GameProfile loginGameProfile; @Shadow private NetHandlerLoginServer.LoginState currentLoginState; - @Unique private int pcf$velocityLoginMessageId = -1; // spotless:on - @Override - public int bridge$velocityLoginMessageId() { - return this.pcf$velocityLoginMessageId; - } - - @Override - public void bridge$setVelocityLoginMessageId(final int id) { - this.pcf$velocityLoginMessageId = id; - } - @Override public @NonNull ConnectionBridge bridge$connection() { return (ConnectionBridge) this.networkManager; diff --git a/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java index 4a746826..ce099e55 100644 --- a/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java @@ -22,7 +22,6 @@ import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -39,7 +38,6 @@ public abstract class ServerLoginPacketListenerImplMixin @Shadow private NetHandlerLoginServer.LoginState currentLoginState; @Shadow @Final private static Logger LOGGER; @Shadow public abstract void shadow$disconnect(ITextComponent reason); - @Unique private int pcf$velocityLoginMessageId = -1; // spotless:on // spotless:off @@ -50,16 +48,6 @@ private void onHandleHello(final @NonNull CallbackInfo ci) { handleHello(this, ci); } - @Override - public int bridge$velocityLoginMessageId() { - return this.pcf$velocityLoginMessageId; - } - - @Override - public void bridge$setVelocityLoginMessageId(final int id) { - this.pcf$velocityLoginMessageId = id; - } - @Override public @NonNull ConnectionBridge bridge$connection() { return (ConnectionBridge) this.networkManager; diff --git a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java index 03178fc8..2d979d9c 100644 --- a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java @@ -24,7 +24,6 @@ import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -41,7 +40,6 @@ public abstract class ServerLoginPacketListenerImplMixin @Shadow private ServerLoginPacketListenerImpl.State state; @Shadow @Final private static Logger LOGGER; @Shadow public abstract void shadow$disconnect(Component reason); - @Unique private int pcf$velocityLoginMessageId = -1; // spotless:on // spotless:off @@ -67,16 +65,6 @@ private void onHandleHelloHybrid(final @NonNull CallbackInfo ci) { handleHello(this, ci); } - @Override - public int bridge$velocityLoginMessageId() { - return this.pcf$velocityLoginMessageId; - } - - @Override - public void bridge$setVelocityLoginMessageId(final int id) { - this.pcf$velocityLoginMessageId = id; - } - @Override public @NonNull ConnectionBridge bridge$connection() { return (ConnectionBridge) this.connection; diff --git a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java index 6772624c..3e290c3c 100644 --- a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java @@ -18,7 +18,6 @@ import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; @AConstraint(mappings = Mappings.SEARGE, version = @Versions(min = MinecraftVersion.V17)) @Mixin(ServerLoginPacketListenerImpl.class) @@ -33,20 +32,8 @@ public abstract class ServerLoginPacketListenerImplMixin @AConstraint(version = @Versions(min = MinecraftVersion.V20_2)) @Shadow private @Nullable GameProfile authenticatedProfile; - - @Unique private int pcf$velocityLoginMessageId = -1; // spotless:on - @Override - public int bridge$velocityLoginMessageId() { - return this.pcf$velocityLoginMessageId; - } - - @Override - public void bridge$setVelocityLoginMessageId(final int id) { - this.pcf$velocityLoginMessageId = id; - } - @Override public @NonNull ConnectionBridge bridge$connection() { return (ConnectionBridge) this.connection; From 07a6a79b771f5020b23e56b43fb263fa39b8153f Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 07:20:08 -0600 Subject: [PATCH 09/71] Move SLPL impl mixins into the common forwarding package --- .../pcf/forwarding/PacketDecoder.java | 1 - .../ServerLoginPacketListenerBridge.java | 3 +- .../prelogin/ArclightPreLogin.java | 2 +- .../prelogin/MohistPreLogin.java | 2 +- .../prelogin/SpigotPreLogin.java | 2 +- .../prelogin/SpongePreLogin.java | 2 +- .../forwarding/modern/ModernForwarding.java | 1 + .../ServerLoginPacketListenerImplMixin.java | 4 +- ...rverLoginPacketListenerImplHelloMixin.java | 2 +- ...ginPacketListenerImplHelloHybridMixin.java | 2 +- ...rverLoginPacketListenerImplHelloMixin.java | 2 +- .../src/main/resources/pcf.mixins.v26_1.json | 4 +- .../ServerLoginPacketListenerImplMixin.java | 4 +- ...rverLoginPacketListenerImplHelloMixin.java | 2 +- .../resources/pcf.mixins.v12_2.forge.json | 6 +- .../{modern => }/MessageSerializerMixin.java | 2 +- .../ServerLoginPacketListenerImplMixin.java | 4 +- .../resources/pcf.mixins.v7_10.forge.json | 4 +- .../ServerLoginPacketListenerImplMixin.java | 4 +- .../resources/pcf.mixins.v13_2.forge.json | 2 +- .../ServerLoginPacketListenerImplMixin.java | 67 +++++++++++++++++++ ...verLoginPacketListenerImplHelloMixin.java} | 49 +------------- .../resources/pcf.mixins.v16_5.forge.json | 3 +- ...verLoginPacketListenerImplLoggerMixin.java | 2 +- ...tenerImplStartClientVerificationMixin.java | 4 +- ...rverLoginPacketListenerImplKeyV1Mixin.java | 2 +- ...rverLoginPacketListenerImplKeyV2Mixin.java | 2 +- .../resources/pcf.mixins.v19_2.forge.json | 2 +- ...verLoginPacketListenerImplLoggerMixin.java | 4 +- .../ServerLoginPacketListenerImplMixin.java | 4 +- .../resources/pcf.mixins.v20_4.forge.json | 4 +- 31 files changed, 110 insertions(+), 88 deletions(-) rename common/src/main/java/org/adde0109/pcf/forwarding/{modern => }/ServerLoginPacketListenerBridge.java (92%) rename deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/{modern => }/ServerLoginPacketListenerImplMixin.java (94%) rename legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/{modern => }/ServerLoginPacketListenerImplMixin.java (95%) rename legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/{modern => }/MessageSerializerMixin.java (93%) rename legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/{modern => }/ServerLoginPacketListenerImplMixin.java (91%) rename modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/{modern => }/ServerLoginPacketListenerImplMixin.java (95%) create mode 100644 modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ServerLoginPacketListenerImplMixin.java rename modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/{ServerLoginPacketListenerImplMixin.java => ServerLoginPacketListenerImplHelloMixin.java} (58%) rename modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/{modern => }/ServerLoginPacketListenerImplStartClientVerificationMixin.java (90%) rename modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/{modern => }/ServerLoginPacketListenerImplLoggerMixin.java (88%) rename modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/{modern => }/ServerLoginPacketListenerImplMixin.java (93%) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 655dfac7..8bdac86f 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -14,7 +14,6 @@ import io.netty.handler.codec.MessageToMessageDecoder; import org.adde0109.pcf.PCF; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import java.util.List; diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ServerLoginPacketListenerBridge.java b/common/src/main/java/org/adde0109/pcf/forwarding/ServerLoginPacketListenerBridge.java similarity index 92% rename from common/src/main/java/org/adde0109/pcf/forwarding/modern/ServerLoginPacketListenerBridge.java rename to common/src/main/java/org/adde0109/pcf/forwarding/ServerLoginPacketListenerBridge.java index f9af4a60..6eb1677c 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ServerLoginPacketListenerBridge.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/ServerLoginPacketListenerBridge.java @@ -1,10 +1,9 @@ -package org.adde0109.pcf.forwarding.modern; +package org.adde0109.pcf.forwarding; import com.mojang.authlib.GameProfile; import dev.neuralnexus.taterapi.mc.world.entity.player.ProfilePublicKey; -import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/ArclightPreLogin.java b/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/ArclightPreLogin.java index f2d8c4c8..97522e27 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/ArclightPreLogin.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/ArclightPreLogin.java @@ -2,7 +2,7 @@ import com.mojang.authlib.GameProfile; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import java.lang.invoke.MethodHandle; diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/MohistPreLogin.java b/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/MohistPreLogin.java index 230a7eaa..f225417a 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/MohistPreLogin.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/MohistPreLogin.java @@ -2,7 +2,7 @@ import com.mojang.authlib.GameProfile; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import java.lang.invoke.MethodHandle; diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/SpigotPreLogin.java b/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/SpigotPreLogin.java index 789b374c..dd427260 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/SpigotPreLogin.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/SpigotPreLogin.java @@ -2,7 +2,7 @@ import com.mojang.authlib.GameProfile; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import java.lang.invoke.MethodHandle; diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/SpongePreLogin.java b/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/SpongePreLogin.java index 6f2bec3a..f16ac0c7 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/SpongePreLogin.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/SpongePreLogin.java @@ -1,6 +1,6 @@ package org.adde0109.pcf.forwarding.compatibility.prelogin; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jetbrains.annotations.NotNull; import java.lang.invoke.MethodHandle; diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index 9bda8de7..3ecf92e2 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -26,6 +26,7 @@ import org.adde0109.pcf.PCF; import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.Mode; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jetbrains.annotations.ApiStatus; import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ServerLoginPacketListenerImplMixin.java similarity index 94% rename from deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplMixin.java rename to deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ServerLoginPacketListenerImplMixin.java index 2dde090a..46338c28 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ServerLoginPacketListenerImplMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v26_1.forwarding.modern; +package org.adde0109.pcf.mixin.v26_1.forwarding; import com.mojang.authlib.GameProfile; @@ -12,7 +12,7 @@ import net.minecraft.server.network.ServerLoginPacketListenerImpl; import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import org.slf4j.Logger; import org.spongepowered.asm.mixin.Final; diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java index 3414ec7e..86c6dbc6 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java @@ -18,7 +18,7 @@ import net.minecraft.server.network.ServerLoginPacketListenerImpl; import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloHybridMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloHybridMixin.java index b2a682bf..a0b0fc3d 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloHybridMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloHybridMixin.java @@ -10,7 +10,7 @@ import net.minecraft.server.network.ServerLoginPacketListenerImpl; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.apache.commons.lang3.Validate; import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.Mixin; diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java index 77b9dc98..0e19a4ff 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java @@ -9,7 +9,7 @@ import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; import dev.neuralnexus.taterapi.meta.enums.Platform; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Mixin; diff --git a/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json b/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json index ce16ba82..9a4c345a 100644 --- a/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json +++ b/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json @@ -11,9 +11,9 @@ "v26_1.crossstich.ArgumentNodeStubMixin", "v26_1.crossstich.ArgumentTypeInfoMixin", "v26_1.forwarding.ConnectionMixin", + "v26_1.forwarding.ServerLoginPacketListenerImplMixin", "v26_1.forwarding.legacy.ServerLoginPacketListenerImplHelloMixin", "v26_1.forwarding.modern.ServerLoginPacketListenerImplHelloHybridMixin", - "v26_1.forwarding.modern.ServerLoginPacketListenerImplHelloMixin", - "v26_1.forwarding.modern.ServerLoginPacketListenerImplMixin" + "v26_1.forwarding.modern.ServerLoginPacketListenerImplHelloMixin" ] } diff --git a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ServerLoginPacketListenerImplMixin.java similarity index 95% rename from legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java rename to legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ServerLoginPacketListenerImplMixin.java index e05d71c9..3a82fe05 100644 --- a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ServerLoginPacketListenerImplMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v12_2.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v12_2.forge.forwarding; import com.mojang.authlib.GameProfile; @@ -12,7 +12,7 @@ import net.minecraft.util.text.ITextComponent; import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.apache.logging.log4j.Logger; import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.Final; diff --git a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java index 232dbb0a..568299df 100644 --- a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java +++ b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java @@ -9,7 +9,7 @@ import net.minecraft.server.network.NetHandlerLoginServer; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Mixin; diff --git a/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json b/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json index ee3cc450..e85722f5 100644 --- a/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json +++ b/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json @@ -9,8 +9,8 @@ "package": "org.adde0109.pcf.mixin", "server": [ "v12_2.forge.forwarding.ConnectionMixin", - "v12_2.forge.forwarding.modern.ServerLoginPacketListenerImplHelloMixin", - "v12_2.forge.forwarding.modern.ServerLoginPacketListenerImplMixin", - "v12_2.forge.forwarding.modern.ServerLoginPacketListenerImplMixin$SLPLIMixin_12" + "v12_2.forge.forwarding.ServerLoginPacketListenerImplMixin", + "v12_2.forge.forwarding.ServerLoginPacketListenerImplMixin$SLPLIMixin_12", + "v12_2.forge.forwarding.modern.ServerLoginPacketListenerImplHelloMixin" ] } diff --git a/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/modern/MessageSerializerMixin.java b/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/MessageSerializerMixin.java similarity index 93% rename from legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/modern/MessageSerializerMixin.java rename to legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/MessageSerializerMixin.java index 0b2597e4..54068f17 100644 --- a/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/modern/MessageSerializerMixin.java +++ b/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/MessageSerializerMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v7_10.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v7_10.forge.forwarding; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; diff --git a/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ServerLoginPacketListenerImplMixin.java similarity index 91% rename from legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java rename to legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ServerLoginPacketListenerImplMixin.java index 536c7612..9702fc88 100644 --- a/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ServerLoginPacketListenerImplMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v7_10.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v7_10.forge.forwarding; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; @@ -8,7 +8,7 @@ import net.minecraft.server.network.NetHandlerLoginServer; import net.minecraft.util.IChatComponent; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.apache.logging.log4j.Logger; import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.Final; diff --git a/legacy/v7_10/src/forge/resources/pcf.mixins.v7_10.forge.json b/legacy/v7_10/src/forge/resources/pcf.mixins.v7_10.forge.json index 8d99e8c9..9a947598 100644 --- a/legacy/v7_10/src/forge/resources/pcf.mixins.v7_10.forge.json +++ b/legacy/v7_10/src/forge/resources/pcf.mixins.v7_10.forge.json @@ -8,7 +8,7 @@ "plugin": "org.adde0109.pcf.mixin.plugin.PCFMixinPlugin", "package": "org.adde0109.pcf.mixin", "server": [ - "v7_10.forge.forwarding.modern.MessageSerializerMixin", - "v7_10.forge.forwarding.modern.ServerLoginPacketListenerImplMixin" + "v7_10.forge.forwarding.MessageSerializerMixin", + "v7_10.forge.forwarding.ServerLoginPacketListenerImplMixin" ] } diff --git a/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ServerLoginPacketListenerImplMixin.java similarity index 95% rename from modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java rename to modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ServerLoginPacketListenerImplMixin.java index ce099e55..21bdd1af 100644 --- a/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ServerLoginPacketListenerImplMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v13_2.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v13_2.forge.forwarding; import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleHello; @@ -14,7 +14,7 @@ import net.minecraft.util.text.ITextComponent; import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.apache.logging.log4j.Logger; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; diff --git a/modern/v13_2/src/forge/resources/pcf.mixins.v13_2.forge.json b/modern/v13_2/src/forge/resources/pcf.mixins.v13_2.forge.json index dbf496cb..ecf6f0a0 100644 --- a/modern/v13_2/src/forge/resources/pcf.mixins.v13_2.forge.json +++ b/modern/v13_2/src/forge/resources/pcf.mixins.v13_2.forge.json @@ -9,6 +9,6 @@ "package": "org.adde0109.pcf.mixin", "server": [ "v13_2.forge.crossstitch.CommandsPacketMixin", - "v13_2.forge.forwarding.modern.ServerLoginPacketListenerImplMixin" + "v13_2.forge.forwarding.ServerLoginPacketListenerImplMixin" ] } diff --git a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ServerLoginPacketListenerImplMixin.java b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ServerLoginPacketListenerImplMixin.java new file mode 100644 index 00000000..98c1d7e9 --- /dev/null +++ b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ServerLoginPacketListenerImplMixin.java @@ -0,0 +1,67 @@ +package org.adde0109.pcf.mixin.v16_5.forge.forwarding; + +import com.mojang.authlib.GameProfile; + +import dev.neuralnexus.taterapi.meta.Mappings; +import dev.neuralnexus.taterapi.meta.anno.AConstraint; +import dev.neuralnexus.taterapi.meta.anno.Versions; +import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; + +import net.minecraft.network.Connection; +import net.minecraft.network.chat.Component; +import net.minecraft.server.network.ServerLoginPacketListenerImpl; + +import org.adde0109.pcf.forwarding.ConnectionBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; +import org.apache.logging.log4j.Logger; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@AConstraint( + mappings = Mappings.SEARGE, + version = @Versions(min = MinecraftVersion.V14, max = MinecraftVersion.V16_5)) +@Mixin(ServerLoginPacketListenerImpl.class) +public abstract class ServerLoginPacketListenerImplMixin + implements ServerLoginPacketListenerBridge { + // spotless:off + @Shadow @Final public Connection connection; + @Shadow @Nullable private GameProfile gameProfile; + @Shadow private ServerLoginPacketListenerImpl.State state; + @Shadow @Final private static Logger LOGGER; + @Shadow public abstract void shadow$disconnect(Component reason); + // spotless:on + + @Override + public @NonNull ConnectionBridge bridge$connection() { + return (ConnectionBridge) this.connection; + } + + @Override + public void bridge$disconnect(final @NonNull Object reason) { + this.shadow$disconnect((Component) reason); + } + + @Override + public void bridge$setGameProfile(final @NonNull GameProfile profile) { + this.gameProfile = profile; + } + + @Override + public void bridge$startClientVerification(final @NonNull GameProfile profile) { + this.gameProfile = profile; + this.state = ServerLoginPacketListenerImpl.State.NEGOTIATING; + } + + @Override + public void bridge$logger_info(final @NonNull String text, final Object... params) { + LOGGER.info(text, params); + } + + @Override + public void bridge$logger_error(final @NonNull String text, final Object... params) { + LOGGER.error(text, params); + } +} diff --git a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java similarity index 58% rename from modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java rename to modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java index 2d979d9c..172f9e6c 100644 --- a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java @@ -2,26 +2,18 @@ import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleHello; -import com.mojang.authlib.GameProfile; - import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; import dev.neuralnexus.taterapi.meta.anno.Versions; import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; import dev.neuralnexus.taterapi.meta.enums.Platform; -import net.minecraft.network.Connection; -import net.minecraft.network.chat.Component; import net.minecraft.server.network.ServerLoginPacketListenerImpl; -import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.apache.commons.lang3.Validate; -import org.apache.logging.log4j.Logger; import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; import org.objectweb.asm.Opcodes; -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; @@ -32,17 +24,11 @@ mappings = Mappings.SEARGE, version = @Versions(min = MinecraftVersion.V14, max = MinecraftVersion.V16_5)) @Mixin(ServerLoginPacketListenerImpl.class) -public abstract class ServerLoginPacketListenerImplMixin +public abstract class ServerLoginPacketListenerImplHelloMixin implements ServerLoginPacketListenerBridge { // spotless:off - @Shadow @Final public Connection connection; - @Shadow @Nullable private GameProfile gameProfile; @Shadow private ServerLoginPacketListenerImpl.State state; - @Shadow @Final private static Logger LOGGER; - @Shadow public abstract void shadow$disconnect(Component reason); - // spotless:on - // spotless:off @AConstraint( platform = {Platform.ARCLIGHT, Platform.CATSERVER, Platform.MAGMA, Platform.MOHIST}, invert = true) @Inject(method = "handleHello", cancellable = true, at = @At(value = "FIELD", opcode = Opcodes.PUTFIELD, ordinal = 1, @@ -64,35 +50,4 @@ private void onHandleHelloHybrid(final @NonNull CallbackInfo ci) { this.state == ServerLoginPacketListenerImpl.State.HELLO, "Unexpected hello packet"); handleHello(this, ci); } - - @Override - public @NonNull ConnectionBridge bridge$connection() { - return (ConnectionBridge) this.connection; - } - - @Override - public void bridge$disconnect(final @NonNull Object reason) { - this.shadow$disconnect((Component) reason); - } - - @Override - public void bridge$setGameProfile(final @NonNull GameProfile profile) { - this.gameProfile = profile; - } - - @Override - public void bridge$startClientVerification(final @NonNull GameProfile profile) { - this.gameProfile = profile; - this.state = ServerLoginPacketListenerImpl.State.NEGOTIATING; - } - - @Override - public void bridge$logger_info(final @NonNull String text, final Object... params) { - LOGGER.info(text, params); - } - - @Override - public void bridge$logger_error(final @NonNull String text, final Object... params) { - LOGGER.error(text, params); - } } diff --git a/modern/v16_5/src/forge/resources/pcf.mixins.v16_5.forge.json b/modern/v16_5/src/forge/resources/pcf.mixins.v16_5.forge.json index 1b3365fe..22288958 100644 --- a/modern/v16_5/src/forge/resources/pcf.mixins.v16_5.forge.json +++ b/modern/v16_5/src/forge/resources/pcf.mixins.v16_5.forge.json @@ -12,6 +12,7 @@ "v16_5.forge.crossstitch.ArgumentTypesEntryMixin", "v16_5.forge.crossstitch.CommandsPacketMixin", "v16_5.forge.forwarding.ConnectionMixin", - "v16_5.forge.forwarding.modern.ServerLoginPacketListenerImplMixin" + "v16_5.forge.forwarding.ServerLoginPacketListenerImplMixin", + "v16_5.forge.forwarding.modern.ServerLoginPacketListenerImplHelloMixin" ] } diff --git a/modern/v17_1/src/forge/java/org/adde0109/pcf/mixin/v17_1/forge/forwarding/modern/ServerLoginPacketListenerImplLoggerMixin.java b/modern/v17_1/src/forge/java/org/adde0109/pcf/mixin/v17_1/forge/forwarding/modern/ServerLoginPacketListenerImplLoggerMixin.java index 77ca441c..a3c595dd 100644 --- a/modern/v17_1/src/forge/java/org/adde0109/pcf/mixin/v17_1/forge/forwarding/modern/ServerLoginPacketListenerImplLoggerMixin.java +++ b/modern/v17_1/src/forge/java/org/adde0109/pcf/mixin/v17_1/forge/forwarding/modern/ServerLoginPacketListenerImplLoggerMixin.java @@ -7,7 +7,7 @@ import net.minecraft.server.network.ServerLoginPacketListenerImpl; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.apache.logging.log4j.Logger; import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.Final; diff --git a/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ServerLoginPacketListenerImplStartClientVerificationMixin.java b/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/ServerLoginPacketListenerImplStartClientVerificationMixin.java similarity index 90% rename from modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ServerLoginPacketListenerImplStartClientVerificationMixin.java rename to modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/ServerLoginPacketListenerImplStartClientVerificationMixin.java index b8aa4ad7..b00b5c3a 100644 --- a/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ServerLoginPacketListenerImplStartClientVerificationMixin.java +++ b/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/ServerLoginPacketListenerImplStartClientVerificationMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v19_2.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v19_2.forge.forwarding; import com.mojang.authlib.GameProfile; @@ -9,7 +9,7 @@ import net.minecraft.server.network.ServerLoginPacketListenerImpl; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; diff --git a/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ServerLoginPacketListenerImplKeyV1Mixin.java b/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ServerLoginPacketListenerImplKeyV1Mixin.java index 088db0f2..3652bc8b 100644 --- a/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ServerLoginPacketListenerImplKeyV1Mixin.java +++ b/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ServerLoginPacketListenerImplKeyV1Mixin.java @@ -10,7 +10,7 @@ import net.minecraft.server.network.ServerLoginPacketListenerImpl; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; diff --git a/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ServerLoginPacketListenerImplKeyV2Mixin.java b/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ServerLoginPacketListenerImplKeyV2Mixin.java index 24b08bfc..13f67cdd 100644 --- a/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ServerLoginPacketListenerImplKeyV2Mixin.java +++ b/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ServerLoginPacketListenerImplKeyV2Mixin.java @@ -13,7 +13,7 @@ import net.minecraft.server.network.ServerLoginPacketListenerImpl; import net.minecraft.util.SignatureValidator; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; diff --git a/modern/v19_2/src/forge/resources/pcf.mixins.v19_2.forge.json b/modern/v19_2/src/forge/resources/pcf.mixins.v19_2.forge.json index 133aed07..4bbd6f8a 100644 --- a/modern/v19_2/src/forge/resources/pcf.mixins.v19_2.forge.json +++ b/modern/v19_2/src/forge/resources/pcf.mixins.v19_2.forge.json @@ -9,11 +9,11 @@ "package": "org.adde0109.pcf.mixin", "server": [ "v19_2.forge.forwarding.ConnectionMixin", + "v19_2.forge.forwarding.ServerLoginPacketListenerImplStartClientVerificationMixin", "v19_2.forge.forwarding.modern.LastSeenMessagesValidatorMixin", "v19_2.forge.forwarding.modern.PlayerChatMessageMixin", "v19_2.forge.forwarding.modern.ServerLoginPacketListenerImplKeyV1Mixin", "v19_2.forge.forwarding.modern.ServerLoginPacketListenerImplKeyV2Mixin", - "v19_2.forge.forwarding.modern.ServerLoginPacketListenerImplStartClientVerificationMixin", "v19_2.forge.forwarding.modern.SignedMessageChainMixin" ] } diff --git a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplLoggerMixin.java b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ServerLoginPacketListenerImplLoggerMixin.java similarity index 88% rename from modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplLoggerMixin.java rename to modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ServerLoginPacketListenerImplLoggerMixin.java index b62f2076..3cf5a308 100644 --- a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplLoggerMixin.java +++ b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ServerLoginPacketListenerImplLoggerMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v20_4.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v20_4.forge.forwarding; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; @@ -7,7 +7,7 @@ import net.minecraft.server.network.ServerLoginPacketListenerImpl; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import org.slf4j.Logger; import org.spongepowered.asm.mixin.Final; diff --git a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ServerLoginPacketListenerImplMixin.java similarity index 93% rename from modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java rename to modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ServerLoginPacketListenerImplMixin.java index 3e290c3c..7c4986e1 100644 --- a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ServerLoginPacketListenerImplMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v20_4.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v20_4.forge.forwarding; import com.mojang.authlib.GameProfile; @@ -12,7 +12,7 @@ import net.minecraft.server.network.ServerLoginPacketListenerImpl; import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.Final; diff --git a/modern/v20_4/src/forge/resources/pcf.mixins.v20_4.forge.json b/modern/v20_4/src/forge/resources/pcf.mixins.v20_4.forge.json index b404d10e..ab27487d 100644 --- a/modern/v20_4/src/forge/resources/pcf.mixins.v20_4.forge.json +++ b/modern/v20_4/src/forge/resources/pcf.mixins.v20_4.forge.json @@ -11,7 +11,7 @@ "v20_4.forge.crossstitch.ArgumentNodeStubMixin", "v20_4.forge.crossstitch.ArgumentTypeInfoMixin", "v20_4.forge.forwarding.ConnectionMixin", - "v20_4.forge.forwarding.modern.ServerLoginPacketListenerImplLoggerMixin", - "v20_4.forge.forwarding.modern.ServerLoginPacketListenerImplMixin" + "v20_4.forge.forwarding.ServerLoginPacketListenerImplLoggerMixin", + "v20_4.forge.forwarding.ServerLoginPacketListenerImplMixin" ] } From 202021a4226c27c5313b58aab57a5b671d6c3b38 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 07:37:11 -0600 Subject: [PATCH 10/71] Pulled profile parsing and util methods into LegacyForwarding --- .../{modern => }/ReflectionUtils.java | 4 +- .../forwarding/legacy/LegacyForwarding.java | 42 ++++++++++++++++ .../forwarding/modern/ModernForwarding.java | 2 +- .../pcf/forwarding/modern/VelocityProxy.java | 2 +- ...rverLoginPacketListenerImplHelloMixin.java | 49 ++----------------- 5 files changed, 49 insertions(+), 50 deletions(-) rename common/src/main/java/org/adde0109/pcf/forwarding/{modern => }/ReflectionUtils.java (97%) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ReflectionUtils.java b/common/src/main/java/org/adde0109/pcf/forwarding/ReflectionUtils.java similarity index 97% rename from common/src/main/java/org/adde0109/pcf/forwarding/modern/ReflectionUtils.java rename to common/src/main/java/org/adde0109/pcf/forwarding/ReflectionUtils.java index 7618448f..9a4cf828 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ReflectionUtils.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/ReflectionUtils.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.forwarding.modern; +package org.adde0109.pcf.forwarding; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.PropertyMap; @@ -77,7 +77,7 @@ private ReflectionUtils() {} ENFORCE_SECURE_PROFILE = enforceSecureProfileHandle; } - static boolean enforceSecureProfile() { + public static boolean enforceSecureProfile() { if (ENFORCE_SECURE_PROFILE == null) { return false; } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java index 40ad081d..2a0062d7 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java @@ -2,12 +2,19 @@ import static dev.neuralnexus.taterapi.network.chat.Component.literal; +import static org.adde0109.pcf.forwarding.ReflectionUtils.getProperties; + +import com.google.common.collect.ImmutableMultimap; import com.google.common.net.InetAddresses; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; +import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; +import dev.neuralnexus.taterapi.meta.Constraint; +import dev.neuralnexus.taterapi.meta.MinecraftVersions; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; import dev.neuralnexus.taterapi.network.protocol.handshake.ClientIntent; @@ -45,6 +52,7 @@ public final class LegacyForwarding { literal("This server requires you to connect with Velocity or BungeeCord."); private static final Object BG_CONFIG_ERR = literal("This server requires the proxy to be configured for BungeeGuard forwarding."); + private static final Object PLAYER_INFO_ERR = literal("Unable to verify player details."); // https://hub.spigotmc.org/stash/projects/SPIGOT/repos/spigot/browse/CraftBukkit-Patches/0024-BungeeCord-Support.patch // https://github.com/caunt/BungeeForge/blob/1.20.2/src/main/java/ua/caunt/bungeeforge/mixin/network/protocol/handshake/ClientIntentionPacket.java#L51-L54 @@ -120,4 +128,38 @@ private static boolean isFmlMarker(final @NonNull Property property) { return Objects.equals(property.name(), "extraData") && property.value().startsWith("\u0001FORGE"); } + + private static final Pattern PROP_PATTERN = Pattern.compile("\\w{0,16}"); + + public static GameProfile createProfile( + final @NonNull ConnectionBridge conn, final @NonNull String name) { + final UUID uuid; + if (conn.bridge$channel().attr(SPOOFED_UUID).get() != null) { + uuid = conn.bridge$channel().attr(SPOOFED_UUID).get(); + } else { + throw new ThrowingComponent(PLAYER_INFO_ERR); + } + + final Collection properties = conn.bridge$channel().attr(SPOOFED_PROFILE).get(); + if (properties == null) { + return new GameProfile(uuid, name); + // com.mojang:authlib:7.0.0 or newer + } else if (Constraint.noLessThan(MinecraftVersions.V21_9).result()) { + final ImmutableMultimap.Builder propertiesBuilder = + ImmutableMultimap.builder(); + for (final Property property : properties) { + if (!PROP_PATTERN.matcher(property.name()).matches()) continue; + propertiesBuilder.put(property.name(), property); + } + return new GameProfile(uuid, name, new PropertyMap(propertiesBuilder.build())); + } else { + final GameProfile profile = new GameProfile(uuid, name); + final PropertyMap propertiesMap = getProperties(profile); + for (final Property property : properties) { + if (!PROP_PATTERN.matcher(property.name()).matches()) continue; + propertiesMap.put(property.name(), property); + } + return profile; + } + } } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index 3ecf92e2..1a2fe090 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -3,7 +3,7 @@ import static dev.neuralnexus.taterapi.network.chat.Component.literal; import static dev.neuralnexus.taterapi.network.chat.Component.translatable; -import static org.adde0109.pcf.forwarding.modern.ReflectionUtils.enforceSecureProfile; +import static org.adde0109.pcf.forwarding.ReflectionUtils.enforceSecureProfile; import static org.adde0109.pcf.forwarding.modern.VelocityProxy.MODERN_MAX_VERSION; import static org.adde0109.pcf.forwarding.modern.VelocityProxy.PLAYER_INFO_PAYLOAD; import static org.adde0109.pcf.forwarding.modern.VelocityProxy.checkIntegrity; diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/VelocityProxy.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/VelocityProxy.java index b5f8be1a..b82ce9d9 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/VelocityProxy.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/VelocityProxy.java @@ -2,7 +2,7 @@ import static dev.neuralnexus.taterapi.resources.Identifier.identifier; -import static org.adde0109.pcf.forwarding.modern.ReflectionUtils.getProperties; +import static org.adde0109.pcf.forwarding.ReflectionUtils.getProperties; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.Multimap; diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java index 86c6dbc6..b6c686fd 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java @@ -1,12 +1,8 @@ package org.adde0109.pcf.mixin.v26_1.forwarding.legacy; -import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.SPOOFED_PROFILE; -import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.SPOOFED_UUID; -import static org.adde0109.pcf.forwarding.modern.ReflectionUtils.getProperties; +import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.createProfile; import com.mojang.authlib.GameProfile; -import com.mojang.authlib.properties.Property; -import com.mojang.authlib.properties.PropertyMap; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; @@ -23,66 +19,27 @@ import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.nio.charset.StandardCharsets; -import java.util.UUID; -import java.util.regex.Pattern; - // https://hub.spigotmc.org/stash/projects/SPIGOT/repos/spigot/browse/CraftBukkit-Patches/0024-BungeeCord-Support.patch @Mixin(ServerLoginPacketListenerImpl.class) public abstract class ServerLoginPacketListenerImplHelloMixin implements ServerLoginPacketListenerBridge { // spotless:off @Shadow @Final private Connection connection; - @Shadow protected abstract void startClientVerification(GameProfile profile); - @Unique private static final Pattern pcf$PROP_PATTERN = Pattern.compile("\\w{0,16}"); - @AConstraint(mappings = Mappings.MOJANG, version = @Versions(min = MinecraftVersion.V20_2)) @Inject(method = "handleHello", cancellable = true, at = @At(value = "INVOKE", ordinal = 1, target = "Lnet/minecraft/server/network/ServerLoginPacketListenerImpl;startClientVerification(Lcom/mojang/authlib/GameProfile;)V")) // spotless:on private void onHandleHello_20_M( final ServerboundHelloPacket packet, final @NonNull CallbackInfo ci) { - final ConnectionBridge conn = (ConnectionBridge) this.connection; - - if (conn.bridge$channel().attr(SPOOFED_UUID).get() == null) { - return; // TODO: Provide client-bound disconnect error - } - // TODO: PostProcessors - this.startClientVerification(this.pcf$createOfflineProfile(packet.name())); + this.startClientVerification( + createProfile((ConnectionBridge) this.connection, packet.name())); ci.cancel(); } - - // Spigot start - @Unique protected GameProfile pcf$createOfflineProfile(String name) { - final ConnectionBridge conn = (ConnectionBridge) this.connection; - - final UUID uuid; - if (conn.bridge$channel().attr(SPOOFED_UUID).get() != null) { - uuid = conn.bridge$channel().attr(SPOOFED_UUID).get(); - } else { - uuid = - UUID.nameUUIDFromBytes( - ("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8)); - } - - // TODO: Add 1.21.9 support - final GameProfile profile = new GameProfile(uuid, name); - final PropertyMap propertiesMap = getProperties(profile); - if (conn.bridge$channel().attr(SPOOFED_PROFILE).get() != null) { - for (final Property property : conn.bridge$channel().attr(SPOOFED_PROFILE).get()) { - if (!pcf$PROP_PATTERN.matcher(property.name()).matches()) continue; - propertiesMap.put(property.name(), property); - } - } - return profile; - } - // Spigot end } From 578fe3cac7b52b05dd4c69d4076b4c6c57d138c7 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 20:46:19 -0600 Subject: [PATCH 11/71] Move error future listener to ConnectionBridge --- .../adde0109/pcf/forwarding/ConnectionBridge.java | 15 +++++++++++++-- .../pcf/forwarding/modern/ModernForwarding.java | 12 ------------ 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java b/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java index 8e40c1b6..7df41abf 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java @@ -4,9 +4,9 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; +import io.netty.util.concurrent.Future; import org.adde0109.pcf.PCF; -import org.adde0109.pcf.forwarding.modern.ModernForwarding; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; @@ -28,7 +28,7 @@ public interface ConnectionBridge { @Nullable Protocol bridge$protocol(); default void bridge$send(final @NonNull Object packet) { - this.bridge$channel().writeAndFlush(packet).addListener(ModernForwarding::errorListener); + this.bridge$channel().writeAndFlush(packet).addListener(ConnectionBridge::errorListener); } /** @@ -48,4 +48,15 @@ static void injectIntoPipeline(final @NonNull ChannelHandlerContext ctx) { .addAfter(HANDLER_SPLITTER, PacketDecoder.NAME, new PacketDecoder()) .addAfter(HANDLER_PREPENDER, PacketEncoder.NAME, new PacketEncoder()); } + + /** + * Listener for logging errors during packet handling + * + * @param future the future to check for success or failure + */ + static void errorListener(Future future) { + if (!future.isSuccess()) { + PCF.logger.error("An error occurred during packet handling", future.cause()); + } + } } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index 1a2fe090..4f590473 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -21,7 +21,6 @@ import io.netty.handler.codec.DecoderException; import io.netty.util.AttributeKey; -import io.netty.util.concurrent.Future; import org.adde0109.pcf.PCF; import org.adde0109.pcf.forwarding.ConnectionBridge; @@ -59,17 +58,6 @@ public final class ModernForwarding { private static final Object REJECTED_PROXY_ERR = literal("Unapproved proxy host."); - /** - * Listener for logging errors during packet handling - * - * @param future the future to check for success or failure - */ - public static void errorListener(Future future) { - if (!future.isSuccess()) { - PCF.logger.error("An error occurred during packet handling", future.cause()); - } - } - /** * Abstract implementation of the hello packet handler * From 2ab842b940cac77e9ee97a0f5641f5bd9f37ffb7 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 21:07:10 -0600 Subject: [PATCH 12/71] Removed forwarding mode NONE, as it's somewhat redundant on the backend --- common/src/main/java/org/adde0109/pcf/forwarding/Mode.java | 1 - 1 file changed, 1 deletion(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/Mode.java b/common/src/main/java/org/adde0109/pcf/forwarding/Mode.java index 3cf087d8..cabd387b 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/Mode.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/Mode.java @@ -2,7 +2,6 @@ /** Forwarding types supported by PCF */ public enum Mode { - NONE, LEGACY, BUNGEEGUARD, MODERN From 48f9e4473b27588f165eebcf2a49f46e10eb2d50 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 21:08:55 -0600 Subject: [PATCH 13/71] Renamed PostProcessor to PreLoginHandler to better describe its purpose and relocated it for common usage --- .../src/main/java/org/adde0109/pcf/PCF.java | 55 ++++++++++--------- .../pcf/forwarding/PreLoginHandler.java | 39 +++++++++++++ .../forwarding/modern/ModernForwarding.java | 37 +------------ 3 files changed, 70 insertions(+), 61 deletions(-) create mode 100644 common/src/main/java/org/adde0109/pcf/forwarding/PreLoginHandler.java diff --git a/common/src/main/java/org/adde0109/pcf/PCF.java b/common/src/main/java/org/adde0109/pcf/PCF.java index db5200d3..3dfd148e 100644 --- a/common/src/main/java/org/adde0109/pcf/PCF.java +++ b/common/src/main/java/org/adde0109/pcf/PCF.java @@ -2,6 +2,8 @@ import static dev.neuralnexus.taterapi.network.Protocol.map; +import static org.adde0109.pcf.forwarding.PreLoginHandler.HANDLERS; + import dev.neuralnexus.taterapi.loader.EntrypointLoader; import dev.neuralnexus.taterapi.meta.Constraint; import dev.neuralnexus.taterapi.meta.Constraints; @@ -19,7 +21,6 @@ import org.adde0109.pcf.forwarding.compatibility.prelogin.MohistPreLogin; import org.adde0109.pcf.forwarding.compatibility.prelogin.SpigotPreLogin; import org.adde0109.pcf.forwarding.compatibility.prelogin.SpongePreLogin; -import org.adde0109.pcf.forwarding.modern.ModernForwarding; import org.adde0109.pcf.forwarding.modern.PlayerInfoQueryPayload; import org.adde0109.pcf.forwarding.modern.VelocityProxy; import org.jetbrains.annotations.ApiStatus; @@ -79,37 +80,40 @@ void onInit() { loader.onInit(); // Modern forwarding init - if (this.forwarding().enabled() && this.forwarding().mode().equals(Mode.MODERN)) { + if (this.forwarding().enabled() && this.forwarding().mode() == Mode.MODERN) { PayloadRegistry.register( PlayerInfoQueryPayload.TYPE, map(PlayerInfoQueryPayload.IDENTIFIER, MinecraftVersions.V7_2)); + } + // Forwarding init + if (this.forwarding().enabled()) { if (Constraint.builder().platform(Platforms.ARCLIGHT).result()) { logger.debug("Arclight detected, applying pre-login post processor"); if (Constraint.range(MinecraftVersions.V14, MinecraftVersions.V20_1).result()) { - ModernForwarding.postProcessors.removeFirst(); - ModernForwarding.postProcessors.add( - (slpl, profile, c) -> { + HANDLERS.removeFirst(); + HANDLERS.add( + (slpl, profile, _) -> { slpl.bridge$setGameProfile(profile); ArclightPreLogin.V14.preLogin(slpl); }); } else if (Constraint.builder().version(MinecraftVersions.V20_2).result()) { - ModernForwarding.postProcessors.removeFirst(); - ModernForwarding.postProcessors.add( - (slpl, profile, c) -> ArclightPreLogin.V20_2.preLogin(slpl, profile)); + HANDLERS.removeFirst(); + HANDLERS.add( + (slpl, profile, _) -> ArclightPreLogin.V20_2.preLogin(slpl, profile)); } else if (Constraint.noLessThan(MinecraftVersions.V20_3).result()) { - ModernForwarding.postProcessors.removeFirst(); - ModernForwarding.postProcessors.add( - (slpl, profile, c) -> ArclightPreLogin.V20_4.preLogin(slpl, profile)); + HANDLERS.removeFirst(); + HANDLERS.add( + (slpl, profile, _) -> ArclightPreLogin.V20_4.preLogin(slpl, profile)); } } else if (Constraint.builder() .platform(Platforms.MOHIST) .version(MinecraftVersions.V20_1) .result()) { logger.debug("Mohist detected, applying pre-login post processor"); - ModernForwarding.postProcessors.removeFirst(); - ModernForwarding.postProcessors.add( - (slpl, profile, c) -> { + HANDLERS.removeFirst(); + HANDLERS.add( + (slpl, profile, _) -> { slpl.bridge$setGameProfile(profile); MohistPreLogin.V20_1.fireEvents(slpl); }); @@ -118,9 +122,9 @@ void onInit() { .version(MinecraftVersions.V21_1) .result()) { logger.debug("Youer detected, applying pre-login post processor"); - ModernForwarding.postProcessors.removeFirst(); - ModernForwarding.postProcessors.add( - (slpl, profile, c) -> { + HANDLERS.removeFirst(); + HANDLERS.add( + (slpl, profile, _) -> { MohistPreLogin.Youer.fireEvents(slpl, profile); slpl.bridge$startClientVerification(profile); }); @@ -136,9 +140,9 @@ void onInit() { .version(MinecraftVersions.V20_1)) .result()) { logger.debug("Forge+Bukkit hybrid detected, applying pre-login post processor"); - ModernForwarding.postProcessors.removeFirst(); - ModernForwarding.postProcessors.add( - (slpl, profile, c) -> { + HANDLERS.removeFirst(); + HANDLERS.add( + (slpl, profile, _) -> { slpl.bridge$setGameProfile(profile); SpigotPreLogin.Legacy.fireEvents(slpl); }); @@ -152,9 +156,8 @@ void onInit() { .result()) { logger.debug( "[Neo]Forge+Bukkit hybrid detected, applying pre-login post processor"); - ModernForwarding.postProcessors.removeFirst(); - ModernForwarding.postProcessors.add( - (slpl, profile, c) -> SpigotPreLogin.V20_2.fireEvents(slpl, profile)); + HANDLERS.removeFirst(); + HANDLERS.add((slpl, profile, _) -> SpigotPreLogin.V20_2.fireEvents(slpl, profile)); } else if (Constraints.builder() .or( Constraint.builder() @@ -171,8 +174,8 @@ void onInit() { .result()) { logger.debug( "[Neo]Forge+Bukkit hybrid detected, applying pre-login post processor"); - ModernForwarding.postProcessors.addFirst( - (slpl, profile, c) -> + HANDLERS.addFirst( + (slpl, profile, _) -> SpigotPreLogin.V20_5.callPlayerPreLoginEvents(slpl, profile)); } @@ -180,7 +183,7 @@ void onInit() { .platform(Platforms.SPONGE) .result()) { logger.debug("SpongeAPI 8 or 9 detected, applying pre-login post processor"); - ModernForwarding.postProcessors.addFirst( + HANDLERS.addFirst( (slpl, profile, c) -> { slpl.bridge$setGameProfile(profile); c.setCancelled(SpongePreLogin.API8.fireAuthEvent(slpl)); diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PreLoginHandler.java b/common/src/main/java/org/adde0109/pcf/forwarding/PreLoginHandler.java new file mode 100644 index 00000000..c3c5b2d8 --- /dev/null +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PreLoginHandler.java @@ -0,0 +1,39 @@ +package org.adde0109.pcf.forwarding; + +import com.mojang.authlib.GameProfile; + +import dev.neuralnexus.taterapi.event.Cancellable; +import dev.neuralnexus.taterapi.mc.server.players.NameAndId; + +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NonNull; + +import java.util.ArrayList; +import java.util.List; + +@ApiStatus.Internal +@FunctionalInterface +public interface PreLoginHandler { + PreLoginHandler DEFAULT_HANDLER = + (slpl, profile, _) -> { + final NameAndId nameAndId = new NameAndId(profile); + slpl.bridge$logger_info( + "UUID of player {} is {}", nameAndId.name(), nameAndId.id()); + slpl.bridge$startClientVerification(profile); + }; + @ApiStatus.Internal List HANDLERS = new ArrayList<>(List.of(DEFAULT_HANDLER)); + + /** + * Process the forwarded profile + * + * @param slpl the ServerLoginPacketListener + * @param profile the forwarded GameProfile + * @param c the cancellable wrapper + * @throws Exception if an error occurs + */ + void process( + final @NonNull ServerLoginPacketListenerBridge slpl, + final @NonNull GameProfile profile, + final @NonNull Cancellable c) + throws Exception; +} diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index 4f590473..0bc2194e 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -8,8 +8,6 @@ import static org.adde0109.pcf.forwarding.modern.VelocityProxy.PLAYER_INFO_PAYLOAD; import static org.adde0109.pcf.forwarding.modern.VelocityProxy.checkIntegrity; -import com.mojang.authlib.GameProfile; - import dev.neuralnexus.taterapi.event.Cancellable; import dev.neuralnexus.taterapi.mc.server.players.NameAndId; import dev.neuralnexus.taterapi.meta.Constraint; @@ -25,14 +23,13 @@ import org.adde0109.pcf.PCF; import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.Mode; +import org.adde0109.pcf.forwarding.PreLoginHandler; import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; -import org.jetbrains.annotations.ApiStatus; import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.net.InetSocketAddress; import java.security.InvalidKeyException; -import java.util.ArrayList; import java.util.List; import java.util.concurrent.ThreadLocalRandom; @@ -97,36 +94,6 @@ public static void handleHello( ci.cancel(); } - @ApiStatus.Internal - @FunctionalInterface - public interface PostProcessor { - /** - * Process the forwarded profile - * - * @param slpl the ServerLoginPacketListener - * @param profile the forwarded GameProfile - * @param c the cancellable wrapper - * @throws Exception if an error occurs - */ - void process( - final @NonNull ServerLoginPacketListenerBridge slpl, - final @NonNull GameProfile profile, - final @NonNull Cancellable c) - throws Exception; - } - - private static final PostProcessor DEFAULT_POST_PROCESSOR = - (slpl, profile, _) -> { - final NameAndId nameAndId = new NameAndId(profile); - slpl.bridge$logger_info( - "UUID of player {} is {}", nameAndId.name(), nameAndId.id()); - slpl.bridge$startClientVerification(profile); - }; - - @ApiStatus.Internal - public static final List postProcessors = - new ArrayList<>(List.of(DEFAULT_POST_PROCESSOR)); - private static final Object DIRECT_CONNECT_ERR = literal("This server requires you to connect with Velocity."); private static final Object EMPTY_PAYLOAD_ERR = @@ -246,7 +213,7 @@ public static void handleCustomQueryPacket( // Proceed with login try { final Cancellable cancellable = Cancellable.simple(); - for (final PostProcessor processor : postProcessors) { + for (final PreLoginHandler processor : PreLoginHandler.HANDLERS) { processor.process(slpl, payload.profile(), cancellable); if (cancellable.cancelled()) { break; From bf87a73c7b8bf275c77460134cef62b7a0428784 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 21:16:40 -0600 Subject: [PATCH 14/71] Added helper methods to Mode to aid with differentiating between Legacy and Modern forwarding types --- common/src/main/java/org/adde0109/pcf/PCF.java | 2 +- .../main/java/org/adde0109/pcf/forwarding/Mode.java | 10 +++++++++- .../org/adde0109/pcf/forwarding/PacketDecoder.java | 7 +++---- .../pcf/forwarding/modern/ModernForwarding.java | 5 ++--- .../org/adde0109/pcf/mixin/plugin/PCFMixinPlugin.java | 10 ++++++---- 5 files changed, 21 insertions(+), 13 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/PCF.java b/common/src/main/java/org/adde0109/pcf/PCF.java index 3dfd148e..0ebff583 100644 --- a/common/src/main/java/org/adde0109/pcf/PCF.java +++ b/common/src/main/java/org/adde0109/pcf/PCF.java @@ -80,7 +80,7 @@ void onInit() { loader.onInit(); // Modern forwarding init - if (this.forwarding().enabled() && this.forwarding().mode() == Mode.MODERN) { + if (this.forwarding().enabled() && this.forwarding().mode().isModern()) { PayloadRegistry.register( PlayerInfoQueryPayload.TYPE, map(PlayerInfoQueryPayload.IDENTIFIER, MinecraftVersions.V7_2)); diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/Mode.java b/common/src/main/java/org/adde0109/pcf/forwarding/Mode.java index cabd387b..7f2c7478 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/Mode.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/Mode.java @@ -4,5 +4,13 @@ public enum Mode { LEGACY, BUNGEEGUARD, - MODERN + MODERN; + + public boolean isLegacy() { + return this == LEGACY || this == BUNGEEGUARD; + } + + public boolean isModern() { + return this == MODERN; + } } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 8bdac86f..92460449 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -37,9 +37,8 @@ protected void decode( switch (connection.bridge$protocol()) { case null -> {} case HANDSHAKING -> { - if (!PCF.instance().forwarding().enabled() - || (PCF.instance().forwarding().mode() != Mode.LEGACY - && PCF.instance().forwarding().mode() != Mode.BUNGEEGUARD)) { + if (!(PCF.instance().forwarding().enabled() + && PCF.instance().forwarding().mode().isLegacy())) { out.add(msg.retain()); return; } @@ -76,7 +75,7 @@ protected void decode( } case LOGIN -> { if (!PCF.instance().forwarding().enabled() - || !PCF.instance().forwarding().mode().equals(Mode.MODERN)) { + || !PCF.instance().forwarding().mode().isModern()) { out.add(msg.retain()); return; } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index 0bc2194e..ede7208a 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -22,7 +22,6 @@ import org.adde0109.pcf.PCF; import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.adde0109.pcf.forwarding.Mode; import org.adde0109.pcf.forwarding.PreLoginHandler; import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; @@ -63,8 +62,8 @@ public final class ModernForwarding { */ public static void handleHello( final @NonNull ServerLoginPacketListenerBridge slpl, final @NonNull CallbackInfo ci) { - if (!PCF.instance().forwarding().enabled() - || !PCF.instance().forwarding().mode().equals(Mode.MODERN)) { + if (!(PCF.instance().forwarding().enabled() + && PCF.instance().forwarding().mode().isModern())) { return; } final ConnectionBridge connection = slpl.bridge$connection(); diff --git a/common/src/main/java/org/adde0109/pcf/mixin/plugin/PCFMixinPlugin.java b/common/src/main/java/org/adde0109/pcf/mixin/plugin/PCFMixinPlugin.java index 234aaec8..a1f9d797 100644 --- a/common/src/main/java/org/adde0109/pcf/mixin/plugin/PCFMixinPlugin.java +++ b/common/src/main/java/org/adde0109/pcf/mixin/plugin/PCFMixinPlugin.java @@ -10,7 +10,6 @@ import dev.neuralnexus.taterapi.muxins.Muxins; import org.adde0109.pcf.PCF; -import org.adde0109.pcf.forwarding.Mode; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.objectweb.asm.tree.ClassNode; @@ -82,12 +81,15 @@ private static boolean shouldApplyMixin( PCF.logger.debug("Skipping mixin " + m + " because forwarding is disabled."); return false; } - if (forwarding.mode() != Mode.MODERN && m.contains(".forwarding.modern.")) { + if (!forwarding.mode().isModern() && m.contains(".forwarding.modern.")) { PCF.logger.debug("Skipping mixin " + m + " because forwarding mode is not MODERN."); return false; } - if (forwarding.mode() != Mode.LEGACY && m.contains(".forwarding.legacy.")) { - PCF.logger.debug("Skipping mixin " + m + " because forwarding mode is not LEGACY."); + if (!forwarding.mode().isLegacy() && m.contains(".forwarding.legacy.")) { + PCF.logger.debug( + "Skipping mixin " + + m + + " because forwarding mode is not LEGACY or BUNGEEGUARD."); return false; } if (advanced.modernForwardingVersion() != NO_OVERRIDE From e0f793a45c12875195ce116b8e62f634feac9d35 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Thu, 23 Apr 2026 00:37:09 -0600 Subject: [PATCH 15/71] Legacy and BungeeGuard forwarding implemented --- .../src/main/java/org/adde0109/pcf/PCF.java | 6 + .../pcf/forwarding/PacketDecoder.java | 28 +++++ .../pcf/forwarding/ReflectionUtils.java | 59 +++++++++- .../forwarding/bungeeguard/BungeeGuard.java | 55 +++++++++ .../forwarding/legacy/LegacyForwarding.java | 108 +++++++++++++++--- ...rverLoginPacketListenerImplHelloMixin.java | 26 ++--- 6 files changed, 250 insertions(+), 32 deletions(-) create mode 100644 common/src/main/java/org/adde0109/pcf/forwarding/bungeeguard/BungeeGuard.java diff --git a/common/src/main/java/org/adde0109/pcf/PCF.java b/common/src/main/java/org/adde0109/pcf/PCF.java index 0ebff583..ed293739 100644 --- a/common/src/main/java/org/adde0109/pcf/PCF.java +++ b/common/src/main/java/org/adde0109/pcf/PCF.java @@ -17,6 +17,7 @@ import dev.neuralnexus.taterapi.network.PayloadRegistry; import org.adde0109.pcf.forwarding.Mode; +import org.adde0109.pcf.forwarding.bungeeguard.BungeeGuard; import org.adde0109.pcf.forwarding.compatibility.prelogin.ArclightPreLogin; import org.adde0109.pcf.forwarding.compatibility.prelogin.MohistPreLogin; import org.adde0109.pcf.forwarding.compatibility.prelogin.SpigotPreLogin; @@ -189,6 +190,11 @@ void onInit() { c.setCancelled(SpongePreLogin.API8.fireAuthEvent(slpl)); }); } + + if (this.forwarding().mode() == Mode.BUNGEEGUARD) { + logger.debug("BungeeGuard detected, applying pre-login post processor"); + HANDLERS.addFirst(BungeeGuard::validateToken); + } } Constraint.Evaluator.DEBUG = debug; diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 92460449..0ed1693d 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -1,6 +1,7 @@ package org.adde0109.pcf.forwarding; import static org.adde0109.pcf.forwarding.ConnectionBridge.HANDLER_PACKET; +import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.PLAYER_NAME; import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.handleClientIntentionPacket; import static org.adde0109.pcf.forwarding.modern.ModernForwarding.LOGIN_MESSAGE_ID; import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleCustomQueryPacket; @@ -74,6 +75,33 @@ protected void decode( } } case LOGIN -> { + // TODO: Clean this up + if (PCF.instance().forwarding().enabled() + && PCF.instance().forwarding().mode().isLegacy()) { + final int readerIndex = msg.readerIndex(); + final FriendlyByteBuf data = new FriendlyByteBuf(msg); + final int id = data.readVarInt(); + PCF.logger.debug( + "Received packet with ID 0x" + + Integer.toHexString(id) + + " from " + + ctx.channel().remoteAddress()); + + //noinspection SwitchStatementWithTooFewBranches + switch (id) { + case 0x00 -> { + PCF.logger.debug( + "Handling ServerBoundHello from " + + ctx.channel().remoteAddress()); + final String name = data.readUtf(16); + ctx.channel().attr(PLAYER_NAME).set(name); + msg.readerIndex(readerIndex); + } + default -> msg.readerIndex(readerIndex); + } + break; + } + if (!PCF.instance().forwarding().enabled() || !PCF.instance().forwarding().mode().isModern()) { out.add(msg.retain()); diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/ReflectionUtils.java b/common/src/main/java/org/adde0109/pcf/forwarding/ReflectionUtils.java index 9a4cf828..0197fec1 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/ReflectionUtils.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/ReflectionUtils.java @@ -1,6 +1,7 @@ package org.adde0109.pcf.forwarding; import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import dev.neuralnexus.taterapi.meta.Constraint; @@ -20,14 +21,42 @@ public final class ReflectionUtils { private ReflectionUtils() {} private static final MethodHandle profilePropertiesHandle; + private static final MethodHandle profilePropertyNameHandle; + private static final MethodHandle profilePropertyValueHandle; static { + final MethodHandles.Lookup lookup = MethodHandles.lookup(); + + // com.mojang:authlib:5.0.0 or newer + final String profilePropertyNameString; + final String profilePropertyValueString; + if (Constraint.noLessThan(MinecraftVersions.V20_2).result()) { + profilePropertyNameString = "name"; + profilePropertyValueString = "value"; + } else { + profilePropertyNameString = "getName"; + profilePropertyValueString = "getValue"; + } + try { + profilePropertyNameHandle = + lookup.findVirtual( + Property.class, + profilePropertyNameString, + MethodType.methodType(String.class)); + profilePropertyValueHandle = + lookup.findVirtual( + Property.class, + profilePropertyValueString, + MethodType.methodType(String.class)); + } catch (final NoSuchMethodException | IllegalAccessException e) { + throw new IllegalStateException("Failed to initialize GameProfile method handles", e); + } + // com.mojang:authlib:7.0.0 or newer if (Constraint.noLessThan(MinecraftVersions.V21_9).result()) { profilePropertiesHandle = null; } else { try { - MethodHandles.Lookup lookup = MethodHandles.lookup(); //noinspection JavaLangInvokeHandleSignature profilePropertiesHandle = lookup.findVirtual( @@ -41,6 +70,34 @@ private ReflectionUtils() {} } } + /** + * Gets the name of a Property + * + * @param property the property + * @return the name + */ + public static @NonNull String getName(final @NonNull Property property) { + try { + return (String) profilePropertyNameHandle.invokeExact(property); + } catch (final Throwable e) { + throw new IllegalStateException("Failed to get name from Property", e); + } + } + + /** + * Gets the value of a Property + * + * @param property the property + * @return the value + */ + public static @NonNull String getValue(final @NonNull Property property) { + try { + return (String) profilePropertyValueHandle.invokeExact(property); + } catch (final Throwable e) { + throw new IllegalStateException("Failed to get value from Property", e); + } + } + /** * Gets the properties from the given GameProfile - 1.21.8 and older * diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/bungeeguard/BungeeGuard.java b/common/src/main/java/org/adde0109/pcf/forwarding/bungeeguard/BungeeGuard.java new file mode 100644 index 00000000..6b54a839 --- /dev/null +++ b/common/src/main/java/org/adde0109/pcf/forwarding/bungeeguard/BungeeGuard.java @@ -0,0 +1,55 @@ +package org.adde0109.pcf.forwarding.bungeeguard; + +import static dev.neuralnexus.taterapi.network.chat.Component.literal; + +import com.mojang.authlib.GameProfile; + +import dev.neuralnexus.taterapi.event.Cancellable; +import dev.neuralnexus.taterapi.mc.server.players.NameAndId; +import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; + +import io.netty.util.AttributeKey; + +import org.adde0109.pcf.PCF; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; +import org.jspecify.annotations.NonNull; + +import java.util.Collection; + +// https://github.com/lucko/BungeeGuard +public final class BungeeGuard { + public static final String BUNGEE_GUARD_TOKEN_PROPERTY_NAME = "bungeeguard-token"; + public static final AttributeKey> BUNGEE_GUARD_TOKEN = + AttributeKey.valueOf("pcf-bungeeguard-token"); + + private static final Object NO_DATA = + literal("&cUnable to authenticate - no data was forwarded by the proxy."); + private static final Object INVALID_TOKEN = literal("&cUnable to authenticate."); + + public static void validateToken( + final @NonNull ServerLoginPacketListenerBridge slpl, + final @NonNull GameProfile profile, + final @NonNull Cancellable ignored) { + final NameAndId nameAndId = new NameAndId(profile); + final String connectionDescription = + nameAndId.id() + " @ " + slpl.bridge$connection().bridge$address().getHostString(); + final Collection bungeeGuardTokens = + slpl.bridge$connection().bridge$channel().attr(BUNGEE_GUARD_TOKEN).getAndSet(null); + if (bungeeGuardTokens.size() > 1) { + PCF.logger.warn( + "Denying connection from " + connectionDescription + " - more than one token"); + throw new ThrowingComponent(INVALID_TOKEN); + } + final String bungeeGuardToken = bungeeGuardTokens.stream().findFirst().orElse(null); + + // TODO: Consider supporting multiple in PCF's config + if (!PCF.instance().forwarding().secret().equals(bungeeGuardToken)) { + final String reason = bungeeGuardToken == null ? "No Token" : "Invalid token"; + PCF.logger.warn( + "Denying connection from " + connectionDescription + " - reason: " + reason); + throw new ThrowingComponent(bungeeGuardToken == null ? NO_DATA : INVALID_TOKEN); + } + + PCF.logger.debug("Successfully validated BungeeGuard token for " + connectionDescription); + } +} diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java index 2a0062d7..c5acbb09 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java @@ -1,8 +1,13 @@ package org.adde0109.pcf.forwarding.legacy; import static dev.neuralnexus.taterapi.network.chat.Component.literal; +import static dev.neuralnexus.taterapi.network.chat.Component.translatable; +import static org.adde0109.pcf.forwarding.ReflectionUtils.getName; import static org.adde0109.pcf.forwarding.ReflectionUtils.getProperties; +import static org.adde0109.pcf.forwarding.ReflectionUtils.getValue; +import static org.adde0109.pcf.forwarding.bungeeguard.BungeeGuard.BUNGEE_GUARD_TOKEN; +import static org.adde0109.pcf.forwarding.bungeeguard.BungeeGuard.BUNGEE_GUARD_TOKEN_PROPERTY_NAME; import com.google.common.collect.ImmutableMultimap; import com.google.common.net.InetAddresses; @@ -13,6 +18,8 @@ import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; +import dev.neuralnexus.taterapi.event.Cancellable; +import dev.neuralnexus.taterapi.mc.server.players.NameAndId; import dev.neuralnexus.taterapi.meta.Constraint; import dev.neuralnexus.taterapi.meta.MinecraftVersions; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; @@ -20,15 +27,20 @@ import dev.neuralnexus.taterapi.network.protocol.handshake.ClientIntent; import dev.neuralnexus.taterapi.network.protocol.handshake.ClientIntentionPacket; +import io.netty.channel.Channel; import io.netty.util.AttributeKey; import org.adde0109.pcf.PCF; import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.Mode; +import org.adde0109.pcf.forwarding.PreLoginHandler; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.net.InetSocketAddress; import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -36,12 +48,14 @@ import java.util.regex.Pattern; public final class LegacyForwarding { + private static final Object REJECTED_PROXY_ERR = literal("Unapproved proxy host."); + + public static final AttributeKey PLAYER_NAME = AttributeKey.valueOf("pcf-player-name"); public static final AttributeKey SPOOFED_UUID = AttributeKey.valueOf("pcf-spoofed-uuid"); public static final AttributeKey> SPOOFED_PROFILE = AttributeKey.valueOf("pcf-spoofed-profile"); private static final char LEGACY_SEPARATOR = '\0'; - private static final String BUNGEE_GUARD_TOKEN_PROPERTY_NAME = "bungeeguard-token"; private static final Gson GSON = new GsonBuilder().create(); private static final TypeToken> profileTypeToken = new TypeToken<>() {}; @@ -66,11 +80,29 @@ public static void handleClientIntentionPacket( return; } + // Check if the connection is from an approved proxy + final List approved = PCF.instance().forwarding().approvedProxyHosts(); + if (!approved.isEmpty()) { + final InetSocketAddress address = connection.bridge$address(); + final String host = address.getHostString(); + final String ip = address.getAddress().getHostAddress(); + if (!approved.contains(host) && !approved.contains(ip)) { + PCF.logger.warn( + "Rejected connection from unapproved proxy host: " + + host + + " (IP: " + + ip + + ")"); + throw new ThrowingComponent(REJECTED_PROXY_ERR); + } + } + final String[] split = hostName.split("\00"); - if ((split.length < 3) || !(HOST_PATTERN.matcher(split[1]).matches())) { + if (split.length < 3 || !(HOST_PATTERN.matcher(split[1]).matches())) { throw new ThrowingComponent(DIRECT_CONNECT_ERR); } - if (PCF.instance().forwarding().mode() != Mode.BUNGEEGUARD && (split.length < 4)) { + if (PCF.instance().forwarding().mode() == Mode.BUNGEEGUARD + && (split.length < 4 || !split[3].contains(BUNGEE_GUARD_TOKEN_PROPERTY_NAME))) { throw new ThrowingComponent(BG_CONFIG_ERR); } @@ -129,19 +161,69 @@ private static boolean isFmlMarker(final @NonNull Property property) { && property.value().startsWith("\u0001FORGE"); } + private static final Object FAILED_TO_VERIFY = + translatable("multiplayer.disconnect.unverified_username"); + + public static void handleHello( + final @NonNull ServerLoginPacketListenerBridge slpl, final @NonNull CallbackInfo ci) { + if (!(PCF.instance().forwarding().enabled() + && PCF.instance().forwarding().mode().isLegacy())) { + return; + } + final GameProfile profile = createProfile(slpl.bridge$connection().bridge$channel()); + + // Proceed with login + try { + final Cancellable cancellable = Cancellable.simple(); + for (final PreLoginHandler processor : PreLoginHandler.HANDLERS) { + processor.process(slpl, profile, cancellable); + if (cancellable.cancelled()) { + break; + } + } + } catch (final ThrowingComponent e) { + throw e; + } catch (final Exception e) { + final NameAndId nameAndId = new NameAndId(profile); + PCF.logger.warn("Exception while forwarding user " + nameAndId.name()); + e.printStackTrace(); + throw new ThrowingComponent(FAILED_TO_VERIFY, e); + } finally { + ci.cancel(); + } + } + private static final Pattern PROP_PATTERN = Pattern.compile("\\w{0,16}"); - public static GameProfile createProfile( - final @NonNull ConnectionBridge conn, final @NonNull String name) { - final UUID uuid; - if (conn.bridge$channel().attr(SPOOFED_UUID).get() != null) { - uuid = conn.bridge$channel().attr(SPOOFED_UUID).get(); - } else { + public static @NonNull GameProfile createProfile(final @NonNull Channel channel) { + final String name = channel.attr(PLAYER_NAME).getAndSet(null); + final UUID uuid = channel.attr(SPOOFED_UUID).getAndSet(null); + if (name == null || uuid == null) { throw new ThrowingComponent(PLAYER_INFO_ERR); } - final Collection properties = conn.bridge$channel().attr(SPOOFED_PROFILE).get(); - if (properties == null) { + final Collection properties = channel.attr(SPOOFED_PROFILE).getAndSet(null); + + // Check for BungeeGuard tokens + if (PCF.instance().forwarding().mode() == Mode.BUNGEEGUARD + && properties != null + && !properties.isEmpty()) { + final Collection bungeeGuardTokens = new HashSet<>(); + for (final Property property : properties) { + if (getName(property).equals(BUNGEE_GUARD_TOKEN_PROPERTY_NAME)) { + bungeeGuardTokens.add(getValue(property)); + } + } + channel.attr(BUNGEE_GUARD_TOKEN).set(bungeeGuardTokens); + + // Remove BungeeGuard token(s) from properties. + // They're filtered out by PROP_PATTERN, but might as well remove them now. + properties.removeIf( + property -> getName(property).equals(BUNGEE_GUARD_TOKEN_PROPERTY_NAME)); + } + + // Create the profile + if (properties == null || properties.isEmpty()) { return new GameProfile(uuid, name); // com.mojang:authlib:7.0.0 or newer } else if (Constraint.noLessThan(MinecraftVersions.V21_9).result()) { @@ -156,8 +238,8 @@ public static GameProfile createProfile( final GameProfile profile = new GameProfile(uuid, name); final PropertyMap propertiesMap = getProperties(profile); for (final Property property : properties) { - if (!PROP_PATTERN.matcher(property.name()).matches()) continue; - propertiesMap.put(property.name(), property); + if (!PROP_PATTERN.matcher(getName(property)).matches()) continue; + propertiesMap.put(getName(property), property); } return profile; } diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java index b6c686fd..76125a67 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java @@ -1,24 +1,17 @@ package org.adde0109.pcf.mixin.v26_1.forwarding.legacy; -import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.createProfile; - -import com.mojang.authlib.GameProfile; - import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; import dev.neuralnexus.taterapi.meta.anno.Versions; import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; +import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; -import net.minecraft.network.Connection; -import net.minecraft.network.protocol.login.ServerboundHelloPacket; import net.minecraft.server.network.ServerLoginPacketListenerImpl; -import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.legacy.LegacyForwarding; import org.jspecify.annotations.NonNull; -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; @@ -28,18 +21,15 @@ public abstract class ServerLoginPacketListenerImplHelloMixin implements ServerLoginPacketListenerBridge { // spotless:off - @Shadow @Final private Connection connection; - @Shadow protected abstract void startClientVerification(GameProfile profile); - @AConstraint(mappings = Mappings.MOJANG, version = @Versions(min = MinecraftVersion.V20_2)) @Inject(method = "handleHello", cancellable = true, at = @At(value = "INVOKE", ordinal = 1, target = "Lnet/minecraft/server/network/ServerLoginPacketListenerImpl;startClientVerification(Lcom/mojang/authlib/GameProfile;)V")) // spotless:on - private void onHandleHello_20_M( - final ServerboundHelloPacket packet, final @NonNull CallbackInfo ci) { - // TODO: PostProcessors - this.startClientVerification( - createProfile((ConnectionBridge) this.connection, packet.name())); - ci.cancel(); + private void onHandleHello_20_M(final @NonNull CallbackInfo ci) { + try { + LegacyForwarding.handleHello(this, ci); + } catch (final ThrowingComponent e) { + this.bridge$disconnect(e.getComponent()); + } } } From fff78b8c78dcf77bac758f3e601afd79be1dbd81 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Thu, 23 Apr 2026 00:59:05 -0600 Subject: [PATCH 16/71] Reorganize init --- .../src/main/java/org/adde0109/pcf/PCF.java | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/PCF.java b/common/src/main/java/org/adde0109/pcf/PCF.java index ed293739..7dd124a3 100644 --- a/common/src/main/java/org/adde0109/pcf/PCF.java +++ b/common/src/main/java/org/adde0109/pcf/PCF.java @@ -80,17 +80,10 @@ void onInit() { } loader.onInit(); - // Modern forwarding init - if (this.forwarding().enabled() && this.forwarding().mode().isModern()) { - PayloadRegistry.register( - PlayerInfoQueryPayload.TYPE, - map(PlayerInfoQueryPayload.IDENTIFIER, MinecraftVersions.V7_2)); - } - // Forwarding init if (this.forwarding().enabled()) { if (Constraint.builder().platform(Platforms.ARCLIGHT).result()) { - logger.debug("Arclight detected, applying pre-login post processor"); + logger.debug("Arclight detected, applying pre-login handler"); if (Constraint.range(MinecraftVersions.V14, MinecraftVersions.V20_1).result()) { HANDLERS.removeFirst(); HANDLERS.add( @@ -111,7 +104,7 @@ void onInit() { .platform(Platforms.MOHIST) .version(MinecraftVersions.V20_1) .result()) { - logger.debug("Mohist detected, applying pre-login post processor"); + logger.debug("Mohist detected, applying pre-login handler"); HANDLERS.removeFirst(); HANDLERS.add( (slpl, profile, _) -> { @@ -122,7 +115,7 @@ void onInit() { .platform(Platforms.YOUER) .version(MinecraftVersions.V21_1) .result()) { - logger.debug("Youer detected, applying pre-login post processor"); + logger.debug("Youer detected, applying pre-login handler"); HANDLERS.removeFirst(); HANDLERS.add( (slpl, profile, _) -> { @@ -140,7 +133,7 @@ void onInit() { .platform(Platforms.MAGMA, Platforms.KETTING) .version(MinecraftVersions.V20_1)) .result()) { - logger.debug("Forge+Bukkit hybrid detected, applying pre-login post processor"); + logger.debug("Forge+Bukkit hybrid detected, applying pre-login handler"); HANDLERS.removeFirst(); HANDLERS.add( (slpl, profile, _) -> { @@ -155,8 +148,7 @@ void onInit() { .platform(Platforms.MOHIST) .version(MinecraftVersions.V20_2)) .result()) { - logger.debug( - "[Neo]Forge+Bukkit hybrid detected, applying pre-login post processor"); + logger.debug("[Neo]Forge+Bukkit hybrid detected, applying pre-login handler"); HANDLERS.removeFirst(); HANDLERS.add((slpl, profile, _) -> SpigotPreLogin.V20_2.fireEvents(slpl, profile)); } else if (Constraints.builder() @@ -173,8 +165,7 @@ void onInit() { .platform(Platforms.NEOTENET) .version(MinecraftVersions.V21_1, MinecraftVersions.V21_10)) .result()) { - logger.debug( - "[Neo]Forge+Bukkit hybrid detected, applying pre-login post processor"); + logger.debug("[Neo]Forge+Bukkit hybrid detected, applying pre-login handler"); HANDLERS.addFirst( (slpl, profile, _) -> SpigotPreLogin.V20_5.callPlayerPreLoginEvents(slpl, profile)); @@ -183,18 +174,26 @@ void onInit() { if (Constraint.range(MinecraftVersions.V16, MinecraftVersions.V18_2) .platform(Platforms.SPONGE) .result()) { - logger.debug("SpongeAPI 8 or 9 detected, applying pre-login post processor"); + logger.debug("SpongeAPI 8 or 9 detected, applying pre-login handler"); HANDLERS.addFirst( (slpl, profile, c) -> { slpl.bridge$setGameProfile(profile); c.setCancelled(SpongePreLogin.API8.fireAuthEvent(slpl)); }); } + } - if (this.forwarding().mode() == Mode.BUNGEEGUARD) { - logger.debug("BungeeGuard detected, applying pre-login post processor"); - HANDLERS.addFirst(BungeeGuard::validateToken); - } + // Modern forwarding init + if (this.forwarding().enabled() && this.forwarding().mode().isModern()) { + PayloadRegistry.register( + PlayerInfoQueryPayload.TYPE, + map(PlayerInfoQueryPayload.IDENTIFIER, MinecraftVersions.V7_2)); + } + + // BungeeGuard forwarding init + if (this.forwarding().enabled() && this.forwarding().mode() == Mode.BUNGEEGUARD) { + logger.debug("BungeeGuard detected, applying pre-login handler"); + HANDLERS.addFirst(BungeeGuard::validateToken); } Constraint.Evaluator.DEBUG = debug; From e5de9861a03b7943ad7ac291d48bce43fa390fbb Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Thu, 23 Apr 2026 01:04:04 -0600 Subject: [PATCH 17/71] Remove frivolous forwarding type checks --- .../java/org/adde0109/pcf/forwarding/PacketDecoder.java | 9 +++------ .../adde0109/pcf/forwarding/legacy/LegacyForwarding.java | 4 ---- .../adde0109/pcf/forwarding/modern/ModernForwarding.java | 4 ---- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 0ed1693d..5b7d6e42 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -38,8 +38,7 @@ protected void decode( switch (connection.bridge$protocol()) { case null -> {} case HANDSHAKING -> { - if (!(PCF.instance().forwarding().enabled() - && PCF.instance().forwarding().mode().isLegacy())) { + if (!PCF.instance().forwarding().mode().isLegacy()) { out.add(msg.retain()); return; } @@ -76,8 +75,7 @@ protected void decode( } case LOGIN -> { // TODO: Clean this up - if (PCF.instance().forwarding().enabled() - && PCF.instance().forwarding().mode().isLegacy()) { + if (PCF.instance().forwarding().mode().isLegacy()) { final int readerIndex = msg.readerIndex(); final FriendlyByteBuf data = new FriendlyByteBuf(msg); final int id = data.readVarInt(); @@ -102,8 +100,7 @@ protected void decode( break; } - if (!PCF.instance().forwarding().enabled() - || !PCF.instance().forwarding().mode().isModern()) { + if (!PCF.instance().forwarding().mode().isModern()) { out.add(msg.retain()); return; } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java index c5acbb09..40ed5880 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java @@ -166,10 +166,6 @@ private static boolean isFmlMarker(final @NonNull Property property) { public static void handleHello( final @NonNull ServerLoginPacketListenerBridge slpl, final @NonNull CallbackInfo ci) { - if (!(PCF.instance().forwarding().enabled() - && PCF.instance().forwarding().mode().isLegacy())) { - return; - } final GameProfile profile = createProfile(slpl.bridge$connection().bridge$channel()); // Proceed with login diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index ede7208a..daeb7682 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -62,10 +62,6 @@ public final class ModernForwarding { */ public static void handleHello( final @NonNull ServerLoginPacketListenerBridge slpl, final @NonNull CallbackInfo ci) { - if (!(PCF.instance().forwarding().enabled() - && PCF.instance().forwarding().mode().isModern())) { - return; - } final ConnectionBridge connection = slpl.bridge$connection(); final List approved = PCF.instance().forwarding().approvedProxyHosts(); From 3405b963c9848905925daaf438f7b9d817802d7c Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Thu, 23 Apr 2026 01:16:21 -0600 Subject: [PATCH 18/71] Clean up PreLoginHandler init --- common/src/main/java/org/adde0109/pcf/PCF.java | 18 +++++++++--------- .../pcf/forwarding/PreLoginHandler.java | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/PCF.java b/common/src/main/java/org/adde0109/pcf/PCF.java index 7dd124a3..31f493e5 100644 --- a/common/src/main/java/org/adde0109/pcf/PCF.java +++ b/common/src/main/java/org/adde0109/pcf/PCF.java @@ -17,6 +17,7 @@ import dev.neuralnexus.taterapi.network.PayloadRegistry; import org.adde0109.pcf.forwarding.Mode; +import org.adde0109.pcf.forwarding.PreLoginHandler; import org.adde0109.pcf.forwarding.bungeeguard.BungeeGuard; import org.adde0109.pcf.forwarding.compatibility.prelogin.ArclightPreLogin; import org.adde0109.pcf.forwarding.compatibility.prelogin.MohistPreLogin; @@ -85,18 +86,15 @@ void onInit() { if (Constraint.builder().platform(Platforms.ARCLIGHT).result()) { logger.debug("Arclight detected, applying pre-login handler"); if (Constraint.range(MinecraftVersions.V14, MinecraftVersions.V20_1).result()) { - HANDLERS.removeFirst(); HANDLERS.add( (slpl, profile, _) -> { slpl.bridge$setGameProfile(profile); ArclightPreLogin.V14.preLogin(slpl); }); } else if (Constraint.builder().version(MinecraftVersions.V20_2).result()) { - HANDLERS.removeFirst(); HANDLERS.add( (slpl, profile, _) -> ArclightPreLogin.V20_2.preLogin(slpl, profile)); } else if (Constraint.noLessThan(MinecraftVersions.V20_3).result()) { - HANDLERS.removeFirst(); HANDLERS.add( (slpl, profile, _) -> ArclightPreLogin.V20_4.preLogin(slpl, profile)); } @@ -105,7 +103,6 @@ void onInit() { .version(MinecraftVersions.V20_1) .result()) { logger.debug("Mohist detected, applying pre-login handler"); - HANDLERS.removeFirst(); HANDLERS.add( (slpl, profile, _) -> { slpl.bridge$setGameProfile(profile); @@ -116,7 +113,6 @@ void onInit() { .version(MinecraftVersions.V21_1) .result()) { logger.debug("Youer detected, applying pre-login handler"); - HANDLERS.removeFirst(); HANDLERS.add( (slpl, profile, _) -> { MohistPreLogin.Youer.fireEvents(slpl, profile); @@ -134,7 +130,6 @@ void onInit() { .version(MinecraftVersions.V20_1)) .result()) { logger.debug("Forge+Bukkit hybrid detected, applying pre-login handler"); - HANDLERS.removeFirst(); HANDLERS.add( (slpl, profile, _) -> { slpl.bridge$setGameProfile(profile); @@ -149,7 +144,6 @@ void onInit() { .version(MinecraftVersions.V20_2)) .result()) { logger.debug("[Neo]Forge+Bukkit hybrid detected, applying pre-login handler"); - HANDLERS.removeFirst(); HANDLERS.add((slpl, profile, _) -> SpigotPreLogin.V20_2.fireEvents(slpl, profile)); } else if (Constraints.builder() .or( @@ -166,9 +160,15 @@ void onInit() { .version(MinecraftVersions.V21_1, MinecraftVersions.V21_10)) .result()) { logger.debug("[Neo]Forge+Bukkit hybrid detected, applying pre-login handler"); - HANDLERS.addFirst( + HANDLERS.add( (slpl, profile, _) -> SpigotPreLogin.V20_5.callPlayerPreLoginEvents(slpl, profile)); + HANDLERS.add(PreLoginHandler.DEFAULT_HANDLER); + } + + // Serves both as a fallback and to populate the default + if (HANDLERS.isEmpty()) { + HANDLERS.add(PreLoginHandler.DEFAULT_HANDLER); } if (Constraint.range(MinecraftVersions.V16, MinecraftVersions.V18_2) @@ -192,7 +192,7 @@ void onInit() { // BungeeGuard forwarding init if (this.forwarding().enabled() && this.forwarding().mode() == Mode.BUNGEEGUARD) { - logger.debug("BungeeGuard detected, applying pre-login handler"); + logger.debug("Forwarding mode set to BungeeGuard, applying pre-login handler"); HANDLERS.addFirst(BungeeGuard::validateToken); } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PreLoginHandler.java b/common/src/main/java/org/adde0109/pcf/forwarding/PreLoginHandler.java index c3c5b2d8..0baf0075 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PreLoginHandler.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PreLoginHandler.java @@ -21,7 +21,7 @@ public interface PreLoginHandler { "UUID of player {} is {}", nameAndId.name(), nameAndId.id()); slpl.bridge$startClientVerification(profile); }; - @ApiStatus.Internal List HANDLERS = new ArrayList<>(List.of(DEFAULT_HANDLER)); + @ApiStatus.Internal List HANDLERS = new ArrayList<>(); /** * Process the forwarded profile From f1817667332b21898ff8eb80ef0bd428e3b4d766 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Thu, 23 Apr 2026 01:36:24 -0600 Subject: [PATCH 19/71] Pull handleHello mixins up a level and create a common delegate that invokes modern or legacy forwarding depending on the config --- .../adde0109/pcf/forwarding/Forwarding.java | 42 +++++++++++++++++++ ...ginPacketListenerImplHelloHybridMixin.java | 4 +- ...rverLoginPacketListenerImplHelloMixin.java | 4 +- ...rverLoginPacketListenerImplHelloMixin.java | 35 ---------------- .../src/main/resources/pcf.mixins.v26_1.json | 5 +-- ...rverLoginPacketListenerImplHelloMixin.java | 4 +- .../resources/pcf.mixins.v12_2.forge.json | 2 +- .../ServerLoginPacketListenerImplMixin.java | 2 +- ...rverLoginPacketListenerImplHelloMixin.java | 4 +- .../resources/pcf.mixins.v16_5.forge.json | 2 +- ...verLoginPacketListenerImplLoggerMixin.java | 2 +- .../resources/pcf.mixins.v17_1.forge.json | 2 +- 12 files changed, 57 insertions(+), 51 deletions(-) create mode 100644 common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java rename deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/{modern => }/ServerLoginPacketListenerImplHelloHybridMixin.java (94%) rename deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/{modern => }/ServerLoginPacketListenerImplHelloMixin.java (96%) delete mode 100644 deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java rename legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/{modern => }/ServerLoginPacketListenerImplHelloMixin.java (90%) rename modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/{modern => }/ServerLoginPacketListenerImplHelloMixin.java (94%) rename modern/v17_1/src/forge/java/org/adde0109/pcf/mixin/v17_1/forge/forwarding/{modern => }/ServerLoginPacketListenerImplLoggerMixin.java (95%) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java new file mode 100644 index 00000000..2294247f --- /dev/null +++ b/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java @@ -0,0 +1,42 @@ +package org.adde0109.pcf.forwarding; + +import static dev.neuralnexus.taterapi.network.chat.Component.translatable; + +import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; + +import org.adde0109.pcf.PCF; +import org.adde0109.pcf.forwarding.legacy.LegacyForwarding; +import org.adde0109.pcf.forwarding.modern.ModernForwarding; +import org.jspecify.annotations.NonNull; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +public final class Forwarding { + private static final Object FAILED_TO_VERIFY = + translatable("multiplayer.disconnect.unverified_username"); + + /** + * Abstract implementation of the hello packet handler + * + * @param slpl The ServerLoginPacketListenerImpl + * @param ci The callback info + */ + public static void handleHello( + final @NonNull ServerLoginPacketListenerBridge slpl, final @NonNull CallbackInfo ci) { + try { + switch (PCF.instance().forwarding().mode()) { + case LEGACY, BUNGEEGUARD -> LegacyForwarding.handleHello(slpl, ci); + case MODERN -> ModernForwarding.handleHello(slpl, ci); + } + } catch (final ThrowingComponent e) { + slpl.bridge$disconnect(e.getComponent()); + } catch (final Exception e) { + // final NameAndId nameAndId = new NameAndId(profile); + // PCF.logger.warn("Exception while forwarding user " + nameAndId.name()); + // throw new ThrowingComponent(FAILED_TO_VERIFY, e); + e.printStackTrace(); + slpl.bridge$disconnect(FAILED_TO_VERIFY); + } finally { + ci.cancel(); + } + } +} diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloHybridMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ServerLoginPacketListenerImplHelloHybridMixin.java similarity index 94% rename from deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloHybridMixin.java rename to deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ServerLoginPacketListenerImplHelloHybridMixin.java index a0b0fc3d..859901b4 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloHybridMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ServerLoginPacketListenerImplHelloHybridMixin.java @@ -1,6 +1,6 @@ -package org.adde0109.pcf.mixin.v26_1.forwarding.modern; +package org.adde0109.pcf.mixin.v26_1.forwarding; -import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleHello; +import static org.adde0109.pcf.forwarding.Forwarding.handleHello; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ServerLoginPacketListenerImplHelloMixin.java similarity index 96% rename from deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java rename to deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ServerLoginPacketListenerImplHelloMixin.java index 0e19a4ff..2d6d44c7 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ServerLoginPacketListenerImplHelloMixin.java @@ -1,6 +1,6 @@ -package org.adde0109.pcf.mixin.v26_1.forwarding.modern; +package org.adde0109.pcf.mixin.v26_1.forwarding; -import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleHello; +import static org.adde0109.pcf.forwarding.Forwarding.handleHello; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java deleted file mode 100644 index 76125a67..00000000 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.adde0109.pcf.mixin.v26_1.forwarding.legacy; - -import dev.neuralnexus.taterapi.meta.Mappings; -import dev.neuralnexus.taterapi.meta.anno.AConstraint; -import dev.neuralnexus.taterapi.meta.anno.Versions; -import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; -import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; - -import net.minecraft.server.network.ServerLoginPacketListenerImpl; - -import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; -import org.adde0109.pcf.forwarding.legacy.LegacyForwarding; -import org.jspecify.annotations.NonNull; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -// https://hub.spigotmc.org/stash/projects/SPIGOT/repos/spigot/browse/CraftBukkit-Patches/0024-BungeeCord-Support.patch -@Mixin(ServerLoginPacketListenerImpl.class) -public abstract class ServerLoginPacketListenerImplHelloMixin - implements ServerLoginPacketListenerBridge { - // spotless:off - @AConstraint(mappings = Mappings.MOJANG, version = @Versions(min = MinecraftVersion.V20_2)) - @Inject(method = "handleHello", cancellable = true, at = @At(value = "INVOKE", ordinal = 1, - target = "Lnet/minecraft/server/network/ServerLoginPacketListenerImpl;startClientVerification(Lcom/mojang/authlib/GameProfile;)V")) - // spotless:on - private void onHandleHello_20_M(final @NonNull CallbackInfo ci) { - try { - LegacyForwarding.handleHello(this, ci); - } catch (final ThrowingComponent e) { - this.bridge$disconnect(e.getComponent()); - } - } -} diff --git a/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json b/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json index 9a4c345a..334c7601 100644 --- a/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json +++ b/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json @@ -12,8 +12,7 @@ "v26_1.crossstich.ArgumentTypeInfoMixin", "v26_1.forwarding.ConnectionMixin", "v26_1.forwarding.ServerLoginPacketListenerImplMixin", - "v26_1.forwarding.legacy.ServerLoginPacketListenerImplHelloMixin", - "v26_1.forwarding.modern.ServerLoginPacketListenerImplHelloHybridMixin", - "v26_1.forwarding.modern.ServerLoginPacketListenerImplHelloMixin" + "v26_1.forwarding.ServerLoginPacketListenerImplHelloHybridMixin", + "v26_1.forwarding.ServerLoginPacketListenerImplHelloMixin" ] } diff --git a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ServerLoginPacketListenerImplHelloMixin.java similarity index 90% rename from legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java rename to legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ServerLoginPacketListenerImplHelloMixin.java index 568299df..c3d50b3f 100644 --- a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java +++ b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ServerLoginPacketListenerImplHelloMixin.java @@ -1,6 +1,6 @@ -package org.adde0109.pcf.mixin.v12_2.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v12_2.forge.forwarding; -import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleHello; +import static org.adde0109.pcf.forwarding.Forwarding.handleHello; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; diff --git a/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json b/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json index e85722f5..c23e0002 100644 --- a/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json +++ b/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json @@ -11,6 +11,6 @@ "v12_2.forge.forwarding.ConnectionMixin", "v12_2.forge.forwarding.ServerLoginPacketListenerImplMixin", "v12_2.forge.forwarding.ServerLoginPacketListenerImplMixin$SLPLIMixin_12", - "v12_2.forge.forwarding.modern.ServerLoginPacketListenerImplHelloMixin" + "v12_2.forge.forwarding.ServerLoginPacketListenerImplHelloMixin" ] } diff --git a/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ServerLoginPacketListenerImplMixin.java b/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ServerLoginPacketListenerImplMixin.java index 21bdd1af..60ca66af 100644 --- a/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ServerLoginPacketListenerImplMixin.java +++ b/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ServerLoginPacketListenerImplMixin.java @@ -1,6 +1,6 @@ package org.adde0109.pcf.mixin.v13_2.forge.forwarding; -import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleHello; +import static org.adde0109.pcf.forwarding.Forwarding.handleHello; import com.mojang.authlib.GameProfile; diff --git a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ServerLoginPacketListenerImplHelloMixin.java similarity index 94% rename from modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java rename to modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ServerLoginPacketListenerImplHelloMixin.java index 172f9e6c..b63946f2 100644 --- a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java +++ b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ServerLoginPacketListenerImplHelloMixin.java @@ -1,6 +1,6 @@ -package org.adde0109.pcf.mixin.v16_5.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v16_5.forge.forwarding; -import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleHello; +import static org.adde0109.pcf.forwarding.Forwarding.handleHello; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; diff --git a/modern/v16_5/src/forge/resources/pcf.mixins.v16_5.forge.json b/modern/v16_5/src/forge/resources/pcf.mixins.v16_5.forge.json index 22288958..b61ea358 100644 --- a/modern/v16_5/src/forge/resources/pcf.mixins.v16_5.forge.json +++ b/modern/v16_5/src/forge/resources/pcf.mixins.v16_5.forge.json @@ -13,6 +13,6 @@ "v16_5.forge.crossstitch.CommandsPacketMixin", "v16_5.forge.forwarding.ConnectionMixin", "v16_5.forge.forwarding.ServerLoginPacketListenerImplMixin", - "v16_5.forge.forwarding.modern.ServerLoginPacketListenerImplHelloMixin" + "v16_5.forge.forwarding.ServerLoginPacketListenerImplHelloMixin" ] } diff --git a/modern/v17_1/src/forge/java/org/adde0109/pcf/mixin/v17_1/forge/forwarding/modern/ServerLoginPacketListenerImplLoggerMixin.java b/modern/v17_1/src/forge/java/org/adde0109/pcf/mixin/v17_1/forge/forwarding/ServerLoginPacketListenerImplLoggerMixin.java similarity index 95% rename from modern/v17_1/src/forge/java/org/adde0109/pcf/mixin/v17_1/forge/forwarding/modern/ServerLoginPacketListenerImplLoggerMixin.java rename to modern/v17_1/src/forge/java/org/adde0109/pcf/mixin/v17_1/forge/forwarding/ServerLoginPacketListenerImplLoggerMixin.java index a3c595dd..ce1441e0 100644 --- a/modern/v17_1/src/forge/java/org/adde0109/pcf/mixin/v17_1/forge/forwarding/modern/ServerLoginPacketListenerImplLoggerMixin.java +++ b/modern/v17_1/src/forge/java/org/adde0109/pcf/mixin/v17_1/forge/forwarding/ServerLoginPacketListenerImplLoggerMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v17_1.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v17_1.forge.forwarding; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; diff --git a/modern/v17_1/src/forge/resources/pcf.mixins.v17_1.forge.json b/modern/v17_1/src/forge/resources/pcf.mixins.v17_1.forge.json index 5c783ef5..2fbab5ad 100644 --- a/modern/v17_1/src/forge/resources/pcf.mixins.v17_1.forge.json +++ b/modern/v17_1/src/forge/resources/pcf.mixins.v17_1.forge.json @@ -11,6 +11,6 @@ "v17_1.forge.crossstitch.ArgumentTypesAccessor", "v17_1.forge.crossstitch.ArgumentTypesEntryMixin", "v17_1.forge.crossstitch.CommandsPacketMixin", - "v17_1.forge.forwarding.modern.ServerLoginPacketListenerImplLoggerMixin" + "v17_1.forge.forwarding.ServerLoginPacketListenerImplLoggerMixin" ] } From 638bcc8f5dbedf64c9b9944e1825690324a65217 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Thu, 23 Apr 2026 03:19:01 -0600 Subject: [PATCH 20/71] Added bridge$disconnect to ConnectionBridge to allow for disconnects during handshake --- .../pcf/forwarding/ConnectionBridge.java | 13 +++++ .../adde0109/pcf/forwarding/Forwarding.java | 4 +- .../pcf/forwarding/PacketDecoder.java | 5 +- .../forwarding/modern/ModernForwarding.java | 2 +- .../v26_1/forwarding/ConnectionMixin.java | 7 +++ .../forge/forwarding/ConnectionMixin.java | 46 ++---------------- .../forge/forwarding/ConnectionMixin.java | 25 ++++++++++ .../resources/pcf.mixins.v7_10.forge.json | 1 + .../forge/forwarding/ConnectionMixin.java | 48 +++++++++++++++++++ .../resources/pcf.mixins.v13_2.forge.json | 1 + .../forge/forwarding/ConnectionMixin.java | 17 +++++-- .../forge/forwarding/ConnectionMixin.java | 4 +- .../forge/forwarding/ConnectionMixin.java | 7 +++ 13 files changed, 127 insertions(+), 53 deletions(-) create mode 100644 legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ConnectionMixin.java create mode 100644 modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ConnectionMixin.java diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java b/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java index 7df41abf..e0d60fdf 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java @@ -27,10 +27,23 @@ public interface ConnectionBridge { @Nullable Protocol bridge$protocol(); + @NonNull Object bridge$disconnectPacket(final @NonNull Object reason); + default void bridge$send(final @NonNull Object packet) { this.bridge$channel().writeAndFlush(packet).addListener(ConnectionBridge::errorListener); } + default void bridge$disconnect(final @NonNull Object reason) { + if (this.bridge$getPacketListener() instanceof ServerLoginPacketListenerBridge slpl) { + slpl.bridge$disconnect(reason); + return; + } + if (this.bridge$channel() != null && this.bridge$channel().isOpen()) { + this.bridge$send(this.bridge$disconnectPacket(reason)); + this.bridge$channel().close().awaitUninterruptibly(); + } + } + /** * Injects the packet encoder and decoder into the pipeline to handle login query packets * diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java index 2294247f..0cb0ea0e 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java @@ -28,13 +28,13 @@ public static void handleHello( case MODERN -> ModernForwarding.handleHello(slpl, ci); } } catch (final ThrowingComponent e) { - slpl.bridge$disconnect(e.getComponent()); + slpl.bridge$connection().bridge$disconnect(e.getComponent()); } catch (final Exception e) { // final NameAndId nameAndId = new NameAndId(profile); // PCF.logger.warn("Exception while forwarding user " + nameAndId.name()); // throw new ThrowingComponent(FAILED_TO_VERIFY, e); e.printStackTrace(); - slpl.bridge$disconnect(FAILED_TO_VERIFY); + slpl.bridge$connection().bridge$disconnect(FAILED_TO_VERIFY); } finally { ci.cancel(); } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 5b7d6e42..4f9ba639 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -62,8 +62,7 @@ protected void decode( try { handleClientIntentionPacket(connection, data); } catch (final ThrowingComponent e) { - throw e; - // connection.bridge$disconnect(e.getComponent()); + connection.bridge$disconnect(e.getComponent()); } finally { // Reset reader index and pass it along msg.readerIndex(readerIndex); @@ -139,7 +138,7 @@ protected void decode( try { handleCustomQueryPacket(slpl, packet); } catch (final ThrowingComponent e) { - slpl.bridge$disconnect(e.getComponent()); + slpl.bridge$connection().bridge$disconnect(e.getComponent()); } finally { msg.clear(); } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index daeb7682..9d42498b 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -76,7 +76,7 @@ public static void handleHello( + " (IP: " + ip + ")"); - slpl.bridge$disconnect(REJECTED_PROXY_ERR); + slpl.bridge$connection().bridge$disconnect(REJECTED_PROXY_ERR); ci.cancel(); return; } diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ConnectionMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ConnectionMixin.java index 0a96af26..d0fac8ae 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ConnectionMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ConnectionMixin.java @@ -6,6 +6,8 @@ import net.minecraft.network.Connection; import net.minecraft.network.PacketListener; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket; import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; @@ -47,4 +49,9 @@ public abstract class ConnectionMixin implements ConnectionBridge { } return Protocol.fromId(listener.protocol().id()); } + + @Override + public @NonNull Object bridge$disconnectPacket(final @NonNull Object reason) { + return new ClientboundLoginDisconnectPacket((Component) reason); + } } diff --git a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ConnectionMixin.java b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ConnectionMixin.java index 84609d2e..36c7b49e 100644 --- a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ConnectionMixin.java +++ b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ConnectionMixin.java @@ -4,58 +4,22 @@ import dev.neuralnexus.taterapi.meta.anno.AConstraint; import dev.neuralnexus.taterapi.meta.anno.Versions; import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; -import dev.neuralnexus.taterapi.network.Protocol; -import io.netty.util.AttributeKey; - -import net.minecraft.network.EnumConnectionState; -import net.minecraft.network.INetHandler; import net.minecraft.network.NetworkManager; +import net.minecraft.network.login.server.SPacketDisconnect; +import net.minecraft.util.text.ITextComponent; import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import java.net.InetSocketAddress; -import java.net.SocketAddress; @AConstraint( mappings = Mappings.SEARGE, - version = @Versions(min = MinecraftVersion.V7, max = MinecraftVersion.V12_2)) + version = @Versions(min = MinecraftVersion.V8, max = MinecraftVersion.V12_2)) @Mixin(NetworkManager.class) public abstract class ConnectionMixin implements ConnectionBridge { - // spotless:off - @Shadow private SocketAddress socketAddress; - @Shadow public abstract INetHandler shadow$getNetHandler(); - // spotless:on - - @Shadow @Final public static AttributeKey PROTOCOL_ATTRIBUTE_KEY; - - @Override - public @NonNull InetSocketAddress bridge$address() { - return (InetSocketAddress) this.socketAddress; - } - - @Override - public void bridge$address(final @NonNull InetSocketAddress address) { - this.socketAddress = address; - } - - @Override - public @Nullable Object bridge$getPacketListener() { - return this.shadow$getNetHandler(); - } - @Override - public Protocol bridge$protocol() { - final INetHandler listener = this.shadow$getNetHandler(); - if (listener == null) { - return null; - } - return Protocol.fromLegacyId( - this.bridge$channel().attr(PROTOCOL_ATTRIBUTE_KEY).get().getId()); + public @NonNull Object bridge$disconnectPacket(final @NonNull Object reason) { + return new SPacketDisconnect((ITextComponent) reason); } } diff --git a/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ConnectionMixin.java b/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ConnectionMixin.java new file mode 100644 index 00000000..b7f1c427 --- /dev/null +++ b/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ConnectionMixin.java @@ -0,0 +1,25 @@ +package org.adde0109.pcf.mixin.v7_10.forge.forwarding; + +import dev.neuralnexus.taterapi.meta.Mappings; +import dev.neuralnexus.taterapi.meta.anno.AConstraint; +import dev.neuralnexus.taterapi.meta.anno.Versions; +import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; + +import net.minecraft.network.NetworkManager; +import net.minecraft.network.login.server.S00PacketDisconnect; +import net.minecraft.util.IChatComponent; + +import org.adde0109.pcf.forwarding.ConnectionBridge; +import org.jspecify.annotations.NonNull; +import org.spongepowered.asm.mixin.Mixin; + +@AConstraint( + mappings = Mappings.SEARGE, + version = @Versions(min = MinecraftVersion.V7, max = MinecraftVersion.V7_10)) +@Mixin(NetworkManager.class) +public abstract class ConnectionMixin implements ConnectionBridge { + @Override + public @NonNull Object bridge$disconnectPacket(final @NonNull Object reason) { + return new S00PacketDisconnect((IChatComponent) reason); + } +} diff --git a/legacy/v7_10/src/forge/resources/pcf.mixins.v7_10.forge.json b/legacy/v7_10/src/forge/resources/pcf.mixins.v7_10.forge.json index 9a947598..b622d1a4 100644 --- a/legacy/v7_10/src/forge/resources/pcf.mixins.v7_10.forge.json +++ b/legacy/v7_10/src/forge/resources/pcf.mixins.v7_10.forge.json @@ -8,6 +8,7 @@ "plugin": "org.adde0109.pcf.mixin.plugin.PCFMixinPlugin", "package": "org.adde0109.pcf.mixin", "server": [ + "v7_10.forge.forwarding.ConnectionMixin", "v7_10.forge.forwarding.MessageSerializerMixin", "v7_10.forge.forwarding.ServerLoginPacketListenerImplMixin" ] diff --git a/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ConnectionMixin.java b/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ConnectionMixin.java new file mode 100644 index 00000000..4d54a370 --- /dev/null +++ b/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ConnectionMixin.java @@ -0,0 +1,48 @@ +package org.adde0109.pcf.mixin.v13_2.forge.forwarding; + +import dev.neuralnexus.taterapi.meta.Mappings; +import dev.neuralnexus.taterapi.meta.anno.AConstraint; +import dev.neuralnexus.taterapi.meta.anno.Versions; +import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; +import dev.neuralnexus.taterapi.network.Protocol; + +import io.netty.util.AttributeKey; + +import net.minecraft.network.EnumConnectionState; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.login.server.SPacketDisconnectLogin; +import net.minecraft.util.text.ITextComponent; + +import org.adde0109.pcf.forwarding.ConnectionBridge; +import org.jspecify.annotations.NonNull; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@AConstraint( + mappings = Mappings.SEARGE, + version = @Versions(min = MinecraftVersion.V7, max = MinecraftVersion.V13_2)) +@Mixin(NetworkManager.class) +public abstract class ConnectionMixin implements ConnectionBridge { + // spotless:off + @Shadow @Final public static AttributeKey PROTOCOL_ATTRIBUTE_KEY; + // spotless:on + + @Override + public Protocol bridge$protocol() { + final Object listener = this.bridge$getPacketListener(); + if (listener == null) { + return null; + } + return Protocol.fromLegacyId( + this.bridge$channel().attr(PROTOCOL_ATTRIBUTE_KEY).get().getId()); + } + + @AConstraint( + mappings = Mappings.SEARGE, + version = @Versions(min = MinecraftVersion.V13, max = MinecraftVersion.V13_2)) + @Override + public @NonNull Object bridge$disconnectPacket(final @NonNull Object reason) { + return new SPacketDisconnectLogin((ITextComponent) reason); + } +} diff --git a/modern/v13_2/src/forge/resources/pcf.mixins.v13_2.forge.json b/modern/v13_2/src/forge/resources/pcf.mixins.v13_2.forge.json index ecf6f0a0..8329255a 100644 --- a/modern/v13_2/src/forge/resources/pcf.mixins.v13_2.forge.json +++ b/modern/v13_2/src/forge/resources/pcf.mixins.v13_2.forge.json @@ -9,6 +9,7 @@ "package": "org.adde0109.pcf.mixin", "server": [ "v13_2.forge.crossstitch.CommandsPacketMixin", + "v13_2.forge.forwarding.ConnectionMixin", "v13_2.forge.forwarding.ServerLoginPacketListenerImplMixin" ] } diff --git a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ConnectionMixin.java b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ConnectionMixin.java index 246fe622..b13b17fe 100644 --- a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ConnectionMixin.java +++ b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ConnectionMixin.java @@ -11,6 +11,8 @@ import net.minecraft.network.Connection; import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.PacketListener; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket; import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; @@ -24,13 +26,15 @@ @AConstraint( mappings = Mappings.SEARGE, - version = @Versions(min = MinecraftVersion.V13, max = MinecraftVersion.V16_5)) + version = @Versions(min = MinecraftVersion.V7, max = MinecraftVersion.V16_5)) @Mixin(Connection.class) public abstract class ConnectionMixin implements ConnectionBridge { // spotless:off @Shadow private SocketAddress address; - @Shadow @Final public static AttributeKey ATTRIBUTE_PROTOCOL; @Shadow public abstract PacketListener shadow$getPacketListener(); + + @AConstraint(version = @Versions(min = MinecraftVersion.V14, max = MinecraftVersion.V16_5)) + @Shadow @Final public static AttributeKey ATTRIBUTE_PROTOCOL; // spotless:on @Override @@ -48,12 +52,19 @@ public abstract class ConnectionMixin implements ConnectionBridge { return this.shadow$getPacketListener(); } + @AConstraint(version = @Versions(min = MinecraftVersion.V14, max = MinecraftVersion.V16_5)) @Override public Protocol bridge$protocol() { - final PacketListener listener = this.shadow$getPacketListener(); + final Object listener = this.bridge$getPacketListener(); if (listener == null) { return null; } return Protocol.fromLegacyId(this.bridge$channel().attr(ATTRIBUTE_PROTOCOL).get().getId()); } + + @AConstraint(version = @Versions(min = MinecraftVersion.V14, max = MinecraftVersion.V16_5)) + @Override + public @NonNull Object bridge$disconnectPacket(final @NonNull Object reason) { + return new ClientboundLoginDisconnectPacket((Component) reason); + } } diff --git a/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/ConnectionMixin.java b/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/ConnectionMixin.java index 6791bd75..a15645ee 100644 --- a/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/ConnectionMixin.java +++ b/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/ConnectionMixin.java @@ -10,7 +10,6 @@ import net.minecraft.network.Connection; import net.minecraft.network.ConnectionProtocol; -import net.minecraft.network.PacketListener; import org.adde0109.pcf.forwarding.ConnectionBridge; import org.spongepowered.asm.mixin.Final; @@ -24,12 +23,11 @@ public abstract class ConnectionMixin implements ConnectionBridge { // spotless:off @Shadow @Final public static AttributeKey ATTRIBUTE_PROTOCOL; - @Shadow public abstract PacketListener shadow$getPacketListener(); // spotless:on @Override public Protocol bridge$protocol() { - final PacketListener listener = this.shadow$getPacketListener(); + final Object listener = this.bridge$getPacketListener(); if (listener == null) { return null; } diff --git a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ConnectionMixin.java b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ConnectionMixin.java index e4d2e8bb..cdd51539 100644 --- a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ConnectionMixin.java +++ b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ConnectionMixin.java @@ -8,6 +8,8 @@ import net.minecraft.network.Connection; import net.minecraft.network.PacketListener; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket; import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; @@ -54,4 +56,9 @@ public abstract class ConnectionMixin implements ConnectionBridge { } return Protocol.fromId(listener.protocol().id()); } + + @Override + public @NonNull Object bridge$disconnectPacket(final @NonNull Object reason) { + return new ClientboundLoginDisconnectPacket((Component) reason); + } } From 67bc7b8cd2387ff94a0a722b9d0642fe70570ba9 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Thu, 23 Apr 2026 06:04:03 -0600 Subject: [PATCH 21/71] Didn't work as expected due to handing the handshake too early, now deferring disconnects to handleHello --- .../adde0109/pcf/forwarding/Forwarding.java | 4 +- .../pcf/forwarding/PacketDecoder.java | 15 ++-- .../forwarding/legacy/LegacyForwarding.java | 81 ++++++++++++------- .../forwarding/modern/ModernForwarding.java | 2 +- 4 files changed, 59 insertions(+), 43 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java index 0cb0ea0e..2294247f 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java @@ -28,13 +28,13 @@ public static void handleHello( case MODERN -> ModernForwarding.handleHello(slpl, ci); } } catch (final ThrowingComponent e) { - slpl.bridge$connection().bridge$disconnect(e.getComponent()); + slpl.bridge$disconnect(e.getComponent()); } catch (final Exception e) { // final NameAndId nameAndId = new NameAndId(profile); // PCF.logger.warn("Exception while forwarding user " + nameAndId.name()); // throw new ThrowingComponent(FAILED_TO_VERIFY, e); e.printStackTrace(); - slpl.bridge$connection().bridge$disconnect(FAILED_TO_VERIFY); + slpl.bridge$disconnect(FAILED_TO_VERIFY); } finally { ci.cancel(); } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 4f9ba639..18f2fed4 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -59,14 +59,11 @@ protected void decode( "Handling ClientIntentionPacket from " + ctx.channel().remoteAddress()); - try { - handleClientIntentionPacket(connection, data); - } catch (final ThrowingComponent e) { - connection.bridge$disconnect(e.getComponent()); - } finally { - // Reset reader index and pass it along - msg.readerIndex(readerIndex); - } + // Rewrite the packet + handleClientIntentionPacket(connection, data); + + // Reset reader index and pass it along + msg.readerIndex(readerIndex); } // Reset reader index for unhandled packets default -> msg.readerIndex(readerIndex); @@ -138,7 +135,7 @@ protected void decode( try { handleCustomQueryPacket(slpl, packet); } catch (final ThrowingComponent e) { - slpl.bridge$connection().bridge$disconnect(e.getComponent()); + slpl.bridge$disconnect(e.getComponent()); } finally { msg.clear(); } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java index 40ed5880..e9174d0b 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java @@ -38,6 +38,7 @@ import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.Collection; import java.util.HashSet; @@ -50,6 +51,10 @@ public final class LegacyForwarding { private static final Object REJECTED_PROXY_ERR = literal("Unapproved proxy host."); + public static final AttributeKey DEFERRED_DISCONNECT = + AttributeKey.valueOf("pcf-deferred-disconnect"); + public static final AttributeKey FORWARDED_ADDRESS = + AttributeKey.valueOf("pcf-forwarded-address"); public static final AttributeKey PLAYER_NAME = AttributeKey.valueOf("pcf-player-name"); public static final AttributeKey SPOOFED_UUID = AttributeKey.valueOf("pcf-spoofed-uuid"); public static final AttributeKey> SPOOFED_PROFILE = @@ -74,63 +79,43 @@ public static void handleClientIntentionPacket( final @NonNull ConnectionBridge connection, final @NonNull FriendlyByteBuf data) { final int protocolVersion = data.readVarInt(); final String hostName = data.readUtf(Short.MAX_VALUE); - final int _ = data.readUnsignedShort(); + final int hostPort = data.readUnsignedShort(); final ClientIntent intention = ClientIntent.byId(data.readVarInt()); if (intention != ClientIntent.LOGIN) { return; } - - // Check if the connection is from an approved proxy - final List approved = PCF.instance().forwarding().approvedProxyHosts(); - if (!approved.isEmpty()) { - final InetSocketAddress address = connection.bridge$address(); - final String host = address.getHostString(); - final String ip = address.getAddress().getHostAddress(); - if (!approved.contains(host) && !approved.contains(ip)) { - PCF.logger.warn( - "Rejected connection from unapproved proxy host: " - + host - + " (IP: " - + ip - + ")"); - throw new ThrowingComponent(REJECTED_PROXY_ERR); - } - } + final Channel channel = connection.bridge$channel(); final String[] split = hostName.split("\00"); if (split.length < 3 || !(HOST_PATTERN.matcher(split[1]).matches())) { - throw new ThrowingComponent(DIRECT_CONNECT_ERR); + channel.attr(DEFERRED_DISCONNECT).set(DIRECT_CONNECT_ERR); + return; } if (PCF.instance().forwarding().mode() == Mode.BUNGEEGUARD && (split.length < 4 || !split[3].contains(BUNGEE_GUARD_TOKEN_PROPERTY_NAME))) { - throw new ThrowingComponent(BG_CONFIG_ERR); + channel.attr(DEFERRED_DISCONNECT).set(BG_CONFIG_ERR); } final String originalHost = split[0]; final String forwardedAddress = split[1]; final UUID uuid = fromStringLenient(split[2]); - PCF.logger.debug( - "Player " + uuid + " is connecting with forwarded address " + forwardedAddress); - // Update the proxied address - final int port = connection.bridge$address().getPort(); - final InetSocketAddress address = - new InetSocketAddress(InetAddresses.forString(forwardedAddress), port); - connection.bridge$address(address); + // Save the forwarded address + channel.attr(FORWARDED_ADDRESS).set(InetAddresses.forString(forwardedAddress)); // Save the UUID - connection.bridge$channel().attr(SPOOFED_UUID).set(uuid); + channel.attr(SPOOFED_UUID).set(uuid); // Save the properties if present final Optional fmlMarker; - if (split.length == 4) { + if (split.length >= 4) { final String profileJSON = split[3]; final List properties = GSON.fromJson(profileJSON, profileTypeToken); // Pop out the FML marker if present fmlMarker = properties.stream().filter(LegacyForwarding::isFmlMarker).findFirst(); properties.removeIf(LegacyForwarding::isFmlMarker); - connection.bridge$channel().attr(SPOOFED_PROFILE).set(properties); + channel.attr(SPOOFED_PROFILE).set(properties); } else { fmlMarker = Optional.empty(); } @@ -144,7 +129,7 @@ public static void handleClientIntentionPacket( // Write the original address back into packet final ClientIntentionPacket newPacket = - new ClientIntentionPacket(protocolVersion, host, port, intention); + new ClientIntentionPacket(protocolVersion, host, hostPort, intention); data.clear(); data.writeVarInt(0x00); ClientIntentionPacket.STREAM_CODEC.encode(data, newPacket); @@ -166,6 +151,40 @@ private static boolean isFmlMarker(final @NonNull Property property) { public static void handleHello( final @NonNull ServerLoginPacketListenerBridge slpl, final @NonNull CallbackInfo ci) { + final ConnectionBridge connection = slpl.bridge$connection(); + final Channel channel = connection.bridge$channel(); + + // Handle any deferred disconnects from the handshake phase + final Object deferredDisconnect = channel.attr(DEFERRED_DISCONNECT).getAndSet(null); + if (deferredDisconnect != null) { + slpl.bridge$disconnect(deferredDisconnect); + return; + } + + // Check if the connection is from an approved proxy + final List approved = PCF.instance().forwarding().approvedProxyHosts(); + if (!approved.isEmpty()) { + final InetSocketAddress address = connection.bridge$address(); + final String host = address.getHostString(); + final String ip = address.getAddress().getHostAddress(); + if (!approved.contains(host) && !approved.contains(ip)) { + PCF.logger.warn( + "Rejected connection from unapproved proxy host: " + + host + + " (IP: " + + ip + + ")"); + throw new ThrowingComponent(REJECTED_PROXY_ERR); + } + } + + // Update the address to the forwarded address + final InetAddress address = connection.bridge$channel().attr(FORWARDED_ADDRESS).get(); + final int port = connection.bridge$address().getPort(); + final InetSocketAddress socketAddress = new InetSocketAddress(address, port); + connection.bridge$address(socketAddress); + + // Create the profile final GameProfile profile = createProfile(slpl.bridge$connection().bridge$channel()); // Proceed with login diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index 9d42498b..daeb7682 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -76,7 +76,7 @@ public static void handleHello( + " (IP: " + ip + ")"); - slpl.bridge$connection().bridge$disconnect(REJECTED_PROXY_ERR); + slpl.bridge$disconnect(REJECTED_PROXY_ERR); ci.cancel(); return; } From 6397f195d168ab3028b47ab7d9d02b9b0c3708b3 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Thu, 23 Apr 2026 06:08:02 -0600 Subject: [PATCH 22/71] Removed ConnectionBridge disconnect helper method --- .../pcf/forwarding/ConnectionBridge.java | 13 ---------- .../v26_1/forwarding/ConnectionMixin.java | 7 ------ .../forge/forwarding/ConnectionMixin.java | 25 ------------------- .../resources/pcf.mixins.v12_2.forge.json | 1 - .../forge/forwarding/ConnectionMixin.java | 25 ------------------- .../resources/pcf.mixins.v7_10.forge.json | 1 - .../forge/forwarding/ConnectionMixin.java | 11 -------- .../forge/forwarding/ConnectionMixin.java | 8 ------ .../forge/forwarding/ConnectionMixin.java | 7 ------ 9 files changed, 98 deletions(-) delete mode 100644 legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ConnectionMixin.java delete mode 100644 legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ConnectionMixin.java diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java b/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java index e0d60fdf..7df41abf 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java @@ -27,23 +27,10 @@ public interface ConnectionBridge { @Nullable Protocol bridge$protocol(); - @NonNull Object bridge$disconnectPacket(final @NonNull Object reason); - default void bridge$send(final @NonNull Object packet) { this.bridge$channel().writeAndFlush(packet).addListener(ConnectionBridge::errorListener); } - default void bridge$disconnect(final @NonNull Object reason) { - if (this.bridge$getPacketListener() instanceof ServerLoginPacketListenerBridge slpl) { - slpl.bridge$disconnect(reason); - return; - } - if (this.bridge$channel() != null && this.bridge$channel().isOpen()) { - this.bridge$send(this.bridge$disconnectPacket(reason)); - this.bridge$channel().close().awaitUninterruptibly(); - } - } - /** * Injects the packet encoder and decoder into the pipeline to handle login query packets * diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ConnectionMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ConnectionMixin.java index d0fac8ae..0a96af26 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ConnectionMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ConnectionMixin.java @@ -6,8 +6,6 @@ import net.minecraft.network.Connection; import net.minecraft.network.PacketListener; -import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket; import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; @@ -49,9 +47,4 @@ public abstract class ConnectionMixin implements ConnectionBridge { } return Protocol.fromId(listener.protocol().id()); } - - @Override - public @NonNull Object bridge$disconnectPacket(final @NonNull Object reason) { - return new ClientboundLoginDisconnectPacket((Component) reason); - } } diff --git a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ConnectionMixin.java b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ConnectionMixin.java deleted file mode 100644 index 36c7b49e..00000000 --- a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ConnectionMixin.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.adde0109.pcf.mixin.v12_2.forge.forwarding; - -import dev.neuralnexus.taterapi.meta.Mappings; -import dev.neuralnexus.taterapi.meta.anno.AConstraint; -import dev.neuralnexus.taterapi.meta.anno.Versions; -import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; - -import net.minecraft.network.NetworkManager; -import net.minecraft.network.login.server.SPacketDisconnect; -import net.minecraft.util.text.ITextComponent; - -import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.jspecify.annotations.NonNull; -import org.spongepowered.asm.mixin.Mixin; - -@AConstraint( - mappings = Mappings.SEARGE, - version = @Versions(min = MinecraftVersion.V8, max = MinecraftVersion.V12_2)) -@Mixin(NetworkManager.class) -public abstract class ConnectionMixin implements ConnectionBridge { - @Override - public @NonNull Object bridge$disconnectPacket(final @NonNull Object reason) { - return new SPacketDisconnect((ITextComponent) reason); - } -} diff --git a/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json b/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json index c23e0002..996f37cd 100644 --- a/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json +++ b/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json @@ -8,7 +8,6 @@ "plugin": "org.adde0109.pcf.mixin.plugin.PCFMixinPlugin", "package": "org.adde0109.pcf.mixin", "server": [ - "v12_2.forge.forwarding.ConnectionMixin", "v12_2.forge.forwarding.ServerLoginPacketListenerImplMixin", "v12_2.forge.forwarding.ServerLoginPacketListenerImplMixin$SLPLIMixin_12", "v12_2.forge.forwarding.ServerLoginPacketListenerImplHelloMixin" diff --git a/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ConnectionMixin.java b/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ConnectionMixin.java deleted file mode 100644 index b7f1c427..00000000 --- a/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ConnectionMixin.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.adde0109.pcf.mixin.v7_10.forge.forwarding; - -import dev.neuralnexus.taterapi.meta.Mappings; -import dev.neuralnexus.taterapi.meta.anno.AConstraint; -import dev.neuralnexus.taterapi.meta.anno.Versions; -import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; - -import net.minecraft.network.NetworkManager; -import net.minecraft.network.login.server.S00PacketDisconnect; -import net.minecraft.util.IChatComponent; - -import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.jspecify.annotations.NonNull; -import org.spongepowered.asm.mixin.Mixin; - -@AConstraint( - mappings = Mappings.SEARGE, - version = @Versions(min = MinecraftVersion.V7, max = MinecraftVersion.V7_10)) -@Mixin(NetworkManager.class) -public abstract class ConnectionMixin implements ConnectionBridge { - @Override - public @NonNull Object bridge$disconnectPacket(final @NonNull Object reason) { - return new S00PacketDisconnect((IChatComponent) reason); - } -} diff --git a/legacy/v7_10/src/forge/resources/pcf.mixins.v7_10.forge.json b/legacy/v7_10/src/forge/resources/pcf.mixins.v7_10.forge.json index b622d1a4..9a947598 100644 --- a/legacy/v7_10/src/forge/resources/pcf.mixins.v7_10.forge.json +++ b/legacy/v7_10/src/forge/resources/pcf.mixins.v7_10.forge.json @@ -8,7 +8,6 @@ "plugin": "org.adde0109.pcf.mixin.plugin.PCFMixinPlugin", "package": "org.adde0109.pcf.mixin", "server": [ - "v7_10.forge.forwarding.ConnectionMixin", "v7_10.forge.forwarding.MessageSerializerMixin", "v7_10.forge.forwarding.ServerLoginPacketListenerImplMixin" ] diff --git a/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ConnectionMixin.java b/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ConnectionMixin.java index 4d54a370..3f86b0c4 100644 --- a/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ConnectionMixin.java +++ b/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ConnectionMixin.java @@ -10,11 +10,8 @@ import net.minecraft.network.EnumConnectionState; import net.minecraft.network.NetworkManager; -import net.minecraft.network.login.server.SPacketDisconnectLogin; -import net.minecraft.util.text.ITextComponent; import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -37,12 +34,4 @@ public abstract class ConnectionMixin implements ConnectionBridge { return Protocol.fromLegacyId( this.bridge$channel().attr(PROTOCOL_ATTRIBUTE_KEY).get().getId()); } - - @AConstraint( - mappings = Mappings.SEARGE, - version = @Versions(min = MinecraftVersion.V13, max = MinecraftVersion.V13_2)) - @Override - public @NonNull Object bridge$disconnectPacket(final @NonNull Object reason) { - return new SPacketDisconnectLogin((ITextComponent) reason); - } } diff --git a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ConnectionMixin.java b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ConnectionMixin.java index b13b17fe..9fe073d3 100644 --- a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ConnectionMixin.java +++ b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ConnectionMixin.java @@ -11,8 +11,6 @@ import net.minecraft.network.Connection; import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.PacketListener; -import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket; import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; @@ -61,10 +59,4 @@ public abstract class ConnectionMixin implements ConnectionBridge { } return Protocol.fromLegacyId(this.bridge$channel().attr(ATTRIBUTE_PROTOCOL).get().getId()); } - - @AConstraint(version = @Versions(min = MinecraftVersion.V14, max = MinecraftVersion.V16_5)) - @Override - public @NonNull Object bridge$disconnectPacket(final @NonNull Object reason) { - return new ClientboundLoginDisconnectPacket((Component) reason); - } } diff --git a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ConnectionMixin.java b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ConnectionMixin.java index cdd51539..e4d2e8bb 100644 --- a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ConnectionMixin.java +++ b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ConnectionMixin.java @@ -8,8 +8,6 @@ import net.minecraft.network.Connection; import net.minecraft.network.PacketListener; -import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket; import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; @@ -56,9 +54,4 @@ public abstract class ConnectionMixin implements ConnectionBridge { } return Protocol.fromId(listener.protocol().id()); } - - @Override - public @NonNull Object bridge$disconnectPacket(final @NonNull Object reason) { - return new ClientboundLoginDisconnectPacket((Component) reason); - } } From 375b7e7db15500b30b65bd449da618222b898990 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Thu, 23 Apr 2026 08:08:04 -0600 Subject: [PATCH 23/71] Cleaned up forwarding impls and pulled out common code --- .../adde0109/pcf/forwarding/Forwarding.java | 83 +++++++- .../pcf/forwarding/PacketDecoder.java | 8 +- .../forwarding/bungeeguard/BungeeGuard.java | 13 +- .../forwarding/legacy/LegacyForwarding.java | 187 +++++++++--------- .../forwarding/modern/ModernForwarding.java | 74 ++----- 5 files changed, 206 insertions(+), 159 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java index 2294247f..7d0ffb46 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java @@ -1,7 +1,12 @@ package org.adde0109.pcf.forwarding; +import static dev.neuralnexus.taterapi.network.chat.Component.literal; import static dev.neuralnexus.taterapi.network.chat.Component.translatable; +import com.mojang.authlib.GameProfile; + +import dev.neuralnexus.taterapi.event.Cancellable; +import dev.neuralnexus.taterapi.mc.server.players.NameAndId; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; import org.adde0109.pcf.PCF; @@ -10,9 +15,16 @@ import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.Collection; + public final class Forwarding { + public static final Object PLAYER_INFO_ERR = literal("Unable to verify player details."); + private static final Object FAILED_TO_VERIFY = translatable("multiplayer.disconnect.unverified_username"); + private static final Object REJECTED_PROXY_ERR = literal("Unapproved proxy host."); /** * Abstract implementation of the hello packet handler @@ -30,13 +42,78 @@ public static void handleHello( } catch (final ThrowingComponent e) { slpl.bridge$disconnect(e.getComponent()); } catch (final Exception e) { - // final NameAndId nameAndId = new NameAndId(profile); - // PCF.logger.warn("Exception while forwarding user " + nameAndId.name()); - // throw new ThrowingComponent(FAILED_TO_VERIFY, e); e.printStackTrace(); slpl.bridge$disconnect(FAILED_TO_VERIFY); } finally { ci.cancel(); } } + + /** + * Checks if the connection is coming from an approved proxy host + * + * @param connection The connection + */ + public static void checkProxy(final @NonNull ConnectionBridge connection) { + final Collection approved = PCF.instance().forwarding().approvedProxyHosts(); + if (!approved.isEmpty()) { + final InetSocketAddress address = connection.bridge$address(); + final String host = address.getHostString(); + final String ip = address.getAddress().getHostAddress(); + if (!approved.contains(host) && !approved.contains(ip)) { + PCF.logger.warn( + "Rejected connection from unapproved proxy host: " + + host + + " (IP: " + + ip + + ")"); + throw new ThrowingComponent(REJECTED_PROXY_ERR); + } + } + } + + /** + * Set the connection's address to the forwarded address from the proxy. + * + * @param connection The connection + * @param forwardedAddress The forwarded address + */ + public static void ipForwarding( + final @NonNull ConnectionBridge connection, + final @NonNull InetAddress forwardedAddress) { + final int port = connection.bridge$address().getPort(); + final InetSocketAddress address = new InetSocketAddress(forwardedAddress, port); + connection.bridge$address(address); + } + + /** + * Pre-login handler that invokes registered {@link PreLoginHandler}s + * + * @param profile The player's GameProfile + * @param slpl The ServerLoginPacketListenerImpl + * @param c Cancellable + */ + public static void preLogin( + final @NonNull GameProfile profile, + final @NonNull ServerLoginPacketListenerBridge slpl, + final @NonNull Cancellable c) { + try { + final Cancellable cancellable = Cancellable.simple(); + for (final PreLoginHandler processor : PreLoginHandler.HANDLERS) { + processor.process(slpl, profile, cancellable); + if (cancellable.cancelled()) { + break; + } + } + } catch (final ThrowingComponent e) { + throw e; + } catch (final Exception e) { + final NameAndId nameAndId = new NameAndId(profile); + PCF.logger.warn("Exception while forwarding user " + nameAndId.name()); + e.printStackTrace(); + throw new ThrowingComponent(FAILED_TO_VERIFY, e); + } finally { + c.cancel(); + } + } } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 18f2fed4..36fc5e9d 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -2,9 +2,9 @@ import static org.adde0109.pcf.forwarding.ConnectionBridge.HANDLER_PACKET; import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.PLAYER_NAME; -import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.handleClientIntentionPacket; +import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.handleClientIntention; import static org.adde0109.pcf.forwarding.modern.ModernForwarding.LOGIN_MESSAGE_ID; -import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleCustomQueryPacket; +import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleCustomQueryAnswer; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; @@ -60,7 +60,7 @@ protected void decode( + ctx.channel().remoteAddress()); // Rewrite the packet - handleClientIntentionPacket(connection, data); + handleClientIntention(connection, data); // Reset reader index and pass it along msg.readerIndex(readerIndex); @@ -133,7 +133,7 @@ protected void decode( + ctx.channel().remoteAddress()); try { - handleCustomQueryPacket(slpl, packet); + handleCustomQueryAnswer(slpl, packet); } catch (final ThrowingComponent e) { slpl.bridge$disconnect(e.getComponent()); } finally { diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/bungeeguard/BungeeGuard.java b/common/src/main/java/org/adde0109/pcf/forwarding/bungeeguard/BungeeGuard.java index 6b54a839..abb75d9c 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/bungeeguard/BungeeGuard.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/bungeeguard/BungeeGuard.java @@ -16,7 +16,7 @@ import java.util.Collection; -// https://github.com/lucko/BungeeGuard +/** Adapted from BungeeGuard */ public final class BungeeGuard { public static final String BUNGEE_GUARD_TOKEN_PROPERTY_NAME = "bungeeguard-token"; public static final AttributeKey> BUNGEE_GUARD_TOKEN = @@ -26,10 +26,17 @@ public final class BungeeGuard { literal("&cUnable to authenticate - no data was forwarded by the proxy."); private static final Object INVALID_TOKEN = literal("&cUnable to authenticate."); + /** + * Validates the BungeeGuard token for the given connection + * + * @param slpl The ServerLoginPacketListenerImpl + * @param profile The player's GameProfile + * @param c Cancellable + */ public static void validateToken( final @NonNull ServerLoginPacketListenerBridge slpl, final @NonNull GameProfile profile, - final @NonNull Cancellable ignored) { + final @NonNull Cancellable c) { final NameAndId nameAndId = new NameAndId(profile); final String connectionDescription = nameAndId.id() + " @ " + slpl.bridge$connection().bridge$address().getHostString(); @@ -38,6 +45,7 @@ public static void validateToken( if (bungeeGuardTokens.size() > 1) { PCF.logger.warn( "Denying connection from " + connectionDescription + " - more than one token"); + c.cancel(); throw new ThrowingComponent(INVALID_TOKEN); } final String bungeeGuardToken = bungeeGuardTokens.stream().findFirst().orElse(null); @@ -47,6 +55,7 @@ public static void validateToken( final String reason = bungeeGuardToken == null ? "No Token" : "Invalid token"; PCF.logger.warn( "Denying connection from " + connectionDescription + " - reason: " + reason); + c.cancel(); throw new ThrowingComponent(bungeeGuardToken == null ? NO_DATA : INVALID_TOKEN); } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java index e9174d0b..ed0f2b8d 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java @@ -1,8 +1,8 @@ package org.adde0109.pcf.forwarding.legacy; import static dev.neuralnexus.taterapi.network.chat.Component.literal; -import static dev.neuralnexus.taterapi.network.chat.Component.translatable; +import static org.adde0109.pcf.forwarding.Forwarding.PLAYER_INFO_ERR; import static org.adde0109.pcf.forwarding.ReflectionUtils.getName; import static org.adde0109.pcf.forwarding.ReflectionUtils.getProperties; import static org.adde0109.pcf.forwarding.ReflectionUtils.getValue; @@ -18,10 +18,9 @@ import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; -import dev.neuralnexus.taterapi.event.Cancellable; -import dev.neuralnexus.taterapi.mc.server.players.NameAndId; import dev.neuralnexus.taterapi.meta.Constraint; import dev.neuralnexus.taterapi.meta.MinecraftVersions; +import dev.neuralnexus.taterapi.mixin.CancellableMixin; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; import dev.neuralnexus.taterapi.network.protocol.handshake.ClientIntent; @@ -32,14 +31,14 @@ import org.adde0109.pcf.PCF; import org.adde0109.pcf.forwarding.ConnectionBridge; +import org.adde0109.pcf.forwarding.Forwarding; import org.adde0109.pcf.forwarding.Mode; -import org.adde0109.pcf.forwarding.PreLoginHandler; import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.net.InetAddress; -import java.net.InetSocketAddress; import java.util.Collection; import java.util.HashSet; import java.util.List; @@ -48,9 +47,13 @@ import java.util.UUID; import java.util.regex.Pattern; +/** + * Adapted from Spigot + * and BungeeForge + */ public final class LegacyForwarding { - private static final Object REJECTED_PROXY_ERR = literal("Unapproved proxy host."); - public static final AttributeKey DEFERRED_DISCONNECT = AttributeKey.valueOf("pcf-deferred-disconnect"); public static final AttributeKey FORWARDED_ADDRESS = @@ -60,23 +63,27 @@ public final class LegacyForwarding { public static final AttributeKey> SPOOFED_PROFILE = AttributeKey.valueOf("pcf-spoofed-profile"); - private static final char LEGACY_SEPARATOR = '\0'; + private static final Object LEGACY_DIRECT_CONNECT_ERR = + literal("This server requires you to connect with Velocity or BungeeCord."); + private static final Object BG_CONFIG_ERR = + literal("This server requires the proxy to be configured for BungeeGuard forwarding."); private static final Gson GSON = new GsonBuilder().create(); private static final TypeToken> profileTypeToken = new TypeToken<>() {}; private static final Pattern HOST_PATTERN = Pattern.compile("[0-9a-f.:]{0,45}"); + private static final Pattern PROP_PATTERN = Pattern.compile("\\w{0,16}"); + private static final char LEGACY_SEPARATOR = '\0'; - private static final Object DIRECT_CONNECT_ERR = // TODO: Consider two different messages - literal("This server requires you to connect with Velocity or BungeeCord."); - private static final Object BG_CONFIG_ERR = - literal("This server requires the proxy to be configured for BungeeGuard forwarding."); - private static final Object PLAYER_INFO_ERR = literal("Unable to verify player details."); - - // https://hub.spigotmc.org/stash/projects/SPIGOT/repos/spigot/browse/CraftBukkit-Patches/0024-BungeeCord-Support.patch - // https://github.com/caunt/BungeeForge/blob/1.20.2/src/main/java/ua/caunt/bungeeforge/mixin/network/protocol/handshake/ClientIntentionPacket.java#L51-L54 - public static void handleClientIntentionPacket( + /** + * Handle the client intention packet and extract player info + * + * @param connection The connection + * @param data The packet buffer + */ + public static void handleClientIntention( final @NonNull ConnectionBridge connection, final @NonNull FriendlyByteBuf data) { + // Read the original packet final int protocolVersion = data.readVarInt(); final String hostName = data.readUtf(Short.MAX_VALUE); final int hostPort = data.readUnsignedShort(); @@ -86,9 +93,10 @@ public static void handleClientIntentionPacket( } final Channel channel = connection.bridge$channel(); + // Parse the host name for forwarded data final String[] split = hostName.split("\00"); if (split.length < 3 || !(HOST_PATTERN.matcher(split[1]).matches())) { - channel.attr(DEFERRED_DISCONNECT).set(DIRECT_CONNECT_ERR); + channel.attr(DEFERRED_DISCONNECT).set(LEGACY_DIRECT_CONNECT_ERR); return; } if (PCF.instance().forwarding().mode() == Mode.BUNGEEGUARD @@ -100,19 +108,16 @@ public static void handleClientIntentionPacket( final String forwardedAddress = split[1]; final UUID uuid = fromStringLenient(split[2]); - // Save the forwarded address + // Save forwarded data channel.attr(FORWARDED_ADDRESS).set(InetAddresses.forString(forwardedAddress)); - - // Save the UUID channel.attr(SPOOFED_UUID).set(uuid); - // Save the properties if present final Optional fmlMarker; if (split.length >= 4) { final String profileJSON = split[3]; final List properties = GSON.fromJson(profileJSON, profileTypeToken); - // Pop out the FML marker if present + // Pop out the FML marker fmlMarker = properties.stream().filter(LegacyForwarding::isFmlMarker).findFirst(); properties.removeIf(LegacyForwarding::isFmlMarker); channel.attr(SPOOFED_PROFILE).set(properties); @@ -125,9 +130,10 @@ public static void handleClientIntentionPacket( + LEGACY_SEPARATOR + property.value().split("\u0001")[1] + LEGACY_SEPARATOR).orElse(originalHost); + PCF.logger.debug("Parsed forwarded data - Host: " + host + ", UUID: " + uuid); // spotless:on - // Write the original address back into packet + // Write the original address (and Forge marker) back into packet final ClientIntentionPacket newPacket = new ClientIntentionPacket(protocolVersion, host, hostPort, intention); data.clear(); @@ -135,20 +141,12 @@ public static void handleClientIntentionPacket( ClientIntentionPacket.STREAM_CODEC.encode(data, newPacket); } - private static @NonNull UUID fromStringLenient(final @NonNull String string) { - return UUID.fromString( - string.replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5")); - } - - // https://github.com/caunt/BungeeForge/blob/1.20.2/src/main/java/ua/caunt/bungeeforge/mixin/network/protocol/handshake/ClientIntentionPacket.java#L51-L54 - private static boolean isFmlMarker(final @NonNull Property property) { - return Objects.equals(property.name(), "extraData") - && property.value().startsWith("\u0001FORGE"); - } - - private static final Object FAILED_TO_VERIFY = - translatable("multiplayer.disconnect.unverified_username"); - + /** + * Hello packet handler for legacy forwarding + * + * @param slpl The ServerLoginPacketListenerImpl + * @param ci The callback info + */ public static void handleHello( final @NonNull ServerLoginPacketListenerBridge slpl, final @NonNull CallbackInfo ci) { final ConnectionBridge connection = slpl.bridge$connection(); @@ -157,72 +155,26 @@ public static void handleHello( // Handle any deferred disconnects from the handshake phase final Object deferredDisconnect = channel.attr(DEFERRED_DISCONNECT).getAndSet(null); if (deferredDisconnect != null) { - slpl.bridge$disconnect(deferredDisconnect); - return; + throw new ThrowingComponent(deferredDisconnect); } // Check if the connection is from an approved proxy - final List approved = PCF.instance().forwarding().approvedProxyHosts(); - if (!approved.isEmpty()) { - final InetSocketAddress address = connection.bridge$address(); - final String host = address.getHostString(); - final String ip = address.getAddress().getHostAddress(); - if (!approved.contains(host) && !approved.contains(ip)) { - PCF.logger.warn( - "Rejected connection from unapproved proxy host: " - + host - + " (IP: " - + ip - + ")"); - throw new ThrowingComponent(REJECTED_PROXY_ERR); - } - } - - // Update the address to the forwarded address - final InetAddress address = connection.bridge$channel().attr(FORWARDED_ADDRESS).get(); - final int port = connection.bridge$address().getPort(); - final InetSocketAddress socketAddress = new InetSocketAddress(address, port); - connection.bridge$address(socketAddress); - - // Create the profile - final GameProfile profile = createProfile(slpl.bridge$connection().bridge$channel()); - - // Proceed with login - try { - final Cancellable cancellable = Cancellable.simple(); - for (final PreLoginHandler processor : PreLoginHandler.HANDLERS) { - processor.process(slpl, profile, cancellable); - if (cancellable.cancelled()) { - break; - } - } - } catch (final ThrowingComponent e) { - throw e; - } catch (final Exception e) { - final NameAndId nameAndId = new NameAndId(profile); - PCF.logger.warn("Exception while forwarding user " + nameAndId.name()); - e.printStackTrace(); - throw new ThrowingComponent(FAILED_TO_VERIFY, e); - } finally { - ci.cancel(); - } - } + Forwarding.checkProxy(connection); - private static final Pattern PROP_PATTERN = Pattern.compile("\\w{0,16}"); + // Apply IP forwarding + final InetAddress address = channel.attr(FORWARDED_ADDRESS).get(); + Forwarding.ipForwarding(connection, address); - public static @NonNull GameProfile createProfile(final @NonNull Channel channel) { + // Query player info from channel final String name = channel.attr(PLAYER_NAME).getAndSet(null); final UUID uuid = channel.attr(SPOOFED_UUID).getAndSet(null); if (name == null || uuid == null) { throw new ThrowingComponent(PLAYER_INFO_ERR); } - final Collection properties = channel.attr(SPOOFED_PROFILE).getAndSet(null); // Check for BungeeGuard tokens - if (PCF.instance().forwarding().mode() == Mode.BUNGEEGUARD - && properties != null - && !properties.isEmpty()) { + if (PCF.instance().forwarding().mode() == Mode.BUNGEEGUARD && properties != null) { final Collection bungeeGuardTokens = new HashSet<>(); for (final Property property : properties) { if (getName(property).equals(BUNGEE_GUARD_TOKEN_PROPERTY_NAME)) { @@ -238,14 +190,60 @@ public static void handleHello( } // Create the profile + final GameProfile profile = createProfile(name, uuid, properties); + + // Proceed with login + Forwarding.preLogin(profile, slpl, new CancellableMixin(ci)); + } + + /** + * Parse a UUID from a string, leniently accepting both dashed and non-dashed formats + * + * @param string The string to parse + * @return The parsed UUID + */ + private static @NonNull UUID fromStringLenient(final @NonNull String string) { + return UUID.fromString( + string.replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5")); + } + + /** + * Check if a property is the FML marker used by Forge to indicate a modded client. + * + * @param property The property to check + * @return True if the property is the FML marker, false otherwise + */ + private static boolean isFmlMarker(final @NonNull Property property) { + return Objects.equals(property.name(), "extraData") + && property.value().startsWith("\u0001FORGE"); + } + + /** + * Creates a new GameProfile + * + * @param name The player's name + * @param uuid The player's UUID + * @param properties The player's properties, if any + * @return The created GameProfile + */ + public static @NonNull GameProfile createProfile( + final @NonNull String name, + final @NonNull UUID uuid, + final @Nullable Collection properties) { + // Exit early if there are no properties if (properties == null || properties.isEmpty()) { return new GameProfile(uuid, name); - // com.mojang:authlib:7.0.0 or newer - } else if (Constraint.noLessThan(MinecraftVersions.V21_9).result()) { + } + + // Filter out invalid properties + properties.removeIf(property -> !PROP_PATTERN.matcher(getName(property)).matches()); + + // Create the profile + if (Constraint.noLessThan(MinecraftVersions.V21_9) + .result()) { // com.mojang:authlib:7.0.0 or newer final ImmutableMultimap.Builder propertiesBuilder = ImmutableMultimap.builder(); for (final Property property : properties) { - if (!PROP_PATTERN.matcher(property.name()).matches()) continue; propertiesBuilder.put(property.name(), property); } return new GameProfile(uuid, name, new PropertyMap(propertiesBuilder.build())); @@ -253,7 +251,6 @@ public static void handleHello( final GameProfile profile = new GameProfile(uuid, name); final PropertyMap propertiesMap = getProperties(profile); for (final Property property : properties) { - if (!PROP_PATTERN.matcher(getName(property)).matches()) continue; propertiesMap.put(getName(property), property); } return profile; diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index daeb7682..4e0dde88 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -3,13 +3,13 @@ import static dev.neuralnexus.taterapi.network.chat.Component.literal; import static dev.neuralnexus.taterapi.network.chat.Component.translatable; +import static org.adde0109.pcf.forwarding.Forwarding.PLAYER_INFO_ERR; import static org.adde0109.pcf.forwarding.ReflectionUtils.enforceSecureProfile; import static org.adde0109.pcf.forwarding.modern.VelocityProxy.MODERN_MAX_VERSION; import static org.adde0109.pcf.forwarding.modern.VelocityProxy.PLAYER_INFO_PAYLOAD; import static org.adde0109.pcf.forwarding.modern.VelocityProxy.checkIntegrity; import dev.neuralnexus.taterapi.event.Cancellable; -import dev.neuralnexus.taterapi.mc.server.players.NameAndId; import dev.neuralnexus.taterapi.meta.Constraint; import dev.neuralnexus.taterapi.meta.MinecraftVersions; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; @@ -22,14 +22,12 @@ import org.adde0109.pcf.PCF; import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.adde0109.pcf.forwarding.PreLoginHandler; +import org.adde0109.pcf.forwarding.Forwarding; import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.net.InetSocketAddress; import java.security.InvalidKeyException; -import java.util.List; import java.util.concurrent.ThreadLocalRandom; /** @@ -52,10 +50,17 @@ public final class ModernForwarding { public static final AttributeKey LOGIN_MESSAGE_ID = AttributeKey.valueOf("pcf-login-message-id"); - private static final Object REJECTED_PROXY_ERR = literal("Unapproved proxy host."); + private static final Object MODERN_DIRECT_CONNECT_ERR = + literal("This server requires you to connect with Velocity."); + private static final Object EMPTY_PAYLOAD_ERR = + literal("Received empty player info payload from the proxy."); + private static final Object MISSING_PROFILE_PUBLIC_KEY = + translatable("multiplayer.disconnect.missing_public_key"); + private static final Object INVALID_SIGNATURE = + translatable("multiplayer.disconnect.invalid_public_key_signature"); /** - * Abstract implementation of the hello packet handler + * Hello packet handler for modern forwarding * * @param slpl The ServerLoginPacketListenerImpl * @param ci The callback info @@ -64,24 +69,10 @@ public static void handleHello( final @NonNull ServerLoginPacketListenerBridge slpl, final @NonNull CallbackInfo ci) { final ConnectionBridge connection = slpl.bridge$connection(); - final List approved = PCF.instance().forwarding().approvedProxyHosts(); - if (!approved.isEmpty()) { - final InetSocketAddress address = connection.bridge$address(); - final String host = address.getHostString(); - final String ip = address.getAddress().getHostAddress(); - if (!approved.contains(host) && !approved.contains(ip)) { - PCF.logger.warn( - "Rejected connection from unapproved proxy host: " - + host - + " (IP: " - + ip - + ")"); - slpl.bridge$disconnect(REJECTED_PROXY_ERR); - ci.cancel(); - return; - } - } + // Check if the connection is from an approved proxy + Forwarding.checkProxy(connection); + // Send forwarding request final int messageId = ThreadLocalRandom.current().nextInt(); connection.bridge$channel().attr(LOGIN_MESSAGE_ID).set(messageId); connection.bridge$send(new ClientboundCustomQueryPacket(messageId, PLAYER_INFO_PAYLOAD)); @@ -89,25 +80,13 @@ public static void handleHello( ci.cancel(); } - private static final Object DIRECT_CONNECT_ERR = - literal("This server requires you to connect with Velocity."); - private static final Object EMPTY_PAYLOAD_ERR = - literal("Received empty player info payload from the proxy."); - private static final Object PLAYER_INFO_ERR = literal("Unable to verify player details."); - private static final Object FAILED_TO_VERIFY = - translatable("multiplayer.disconnect.unverified_username"); - private static final Object MISSING_PROFILE_PUBLIC_KEY = - translatable("multiplayer.disconnect.missing_public_key"); - private static final Object INVALID_SIGNATURE = - translatable("multiplayer.disconnect.invalid_public_key_signature"); - /** - * Abstract implementation of the custom query packet handler + * CustomQueryAnswer packet handler for modern forwarding * * @param slpl The ServerLoginPacketListenerImpl * @param packet The Minecraft packet */ - public static void handleCustomQueryPacket( + public static void handleCustomQueryAnswer( final @NonNull ServerLoginPacketListenerBridge slpl, final @NonNull ServerboundCustomQueryAnswerPacket packet) { final CustomQueryAnswerPayload.Raw rawPayload = @@ -115,7 +94,7 @@ public static void handleCustomQueryPacket( // Validate payload presence if (rawPayload == null) { - throw new ThrowingComponent(DIRECT_CONNECT_ERR); + throw new ThrowingComponent(MODERN_DIRECT_CONNECT_ERR); } else if (rawPayload.data().readableBytes() == 0) { PCF.logger.error( "Received empty forwarding payload. Has Velocity been configured to use modern forwarding?"); @@ -162,9 +141,7 @@ public static void handleCustomQueryPacket( PCF.logger.debug("Using modern forwarding version: " + version); // Apply IP forwarding - final int port = slpl.bridge$connection().bridge$address().getPort(); - final InetSocketAddress address = new InetSocketAddress(payload.address(), port); - slpl.bridge$connection().bridge$address(address); + Forwarding.ipForwarding(slpl.bridge$connection(), payload.address()); // Handle profile key switch (version) { @@ -206,19 +183,6 @@ public static void handleCustomQueryPacket( } // Proceed with login - try { - final Cancellable cancellable = Cancellable.simple(); - for (final PreLoginHandler processor : PreLoginHandler.HANDLERS) { - processor.process(slpl, payload.profile(), cancellable); - if (cancellable.cancelled()) { - break; - } - } - } catch (final Exception e) { - final NameAndId nameAndId = new NameAndId(payload.profile()); - PCF.logger.warn("Exception while forwarding user " + nameAndId.name()); - e.printStackTrace(); - throw new ThrowingComponent(FAILED_TO_VERIFY, e); - } + Forwarding.preLogin(payload.profile(), slpl, Cancellable.simple()); } } From 74dae2ddd83a786e51822c153204b58e11aa9550 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Thu, 23 Apr 2026 21:48:53 -0600 Subject: [PATCH 24/71] Tidied things up some more --- .../adde0109/pcf/forwarding/Forwarding.java | 12 +- .../pcf/forwarding/PacketDecoder.java | 117 +++++++----------- .../forwarding/legacy/LegacyForwarding.java | 4 +- .../forwarding/modern/ModernForwarding.java | 23 +++- 4 files changed, 68 insertions(+), 88 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java index 7d0ffb46..33707b74 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java @@ -89,19 +89,17 @@ public static void ipForwarding( /** * Pre-login handler that invokes registered {@link PreLoginHandler}s * - * @param profile The player's GameProfile * @param slpl The ServerLoginPacketListenerImpl - * @param c Cancellable + * @param profile The player's GameProfile */ public static void preLogin( - final @NonNull GameProfile profile, final @NonNull ServerLoginPacketListenerBridge slpl, - final @NonNull Cancellable c) { + final @NonNull GameProfile profile) { + final Cancellable c = Cancellable.simple(); try { - final Cancellable cancellable = Cancellable.simple(); for (final PreLoginHandler processor : PreLoginHandler.HANDLERS) { - processor.process(slpl, profile, cancellable); - if (cancellable.cancelled()) { + processor.process(slpl, profile, c); + if (c.cancelled()) { break; } } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 36fc5e9d..8de12152 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -1,14 +1,15 @@ package org.adde0109.pcf.forwarding; +import static dev.neuralnexus.taterapi.network.protocol.login.ServerboundHelloPacket.MAX_NAME_LENGTH; + import static org.adde0109.pcf.forwarding.ConnectionBridge.HANDLER_PACKET; import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.PLAYER_NAME; import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.handleClientIntention; -import static org.adde0109.pcf.forwarding.modern.ModernForwarding.LOGIN_MESSAGE_ID; import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleCustomQueryAnswer; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; +import dev.neuralnexus.taterapi.network.Protocol; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; -import dev.neuralnexus.taterapi.network.protocol.login.ServerboundCustomQueryAnswerPacket; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; @@ -35,23 +36,30 @@ protected void decode( final ConnectionBridge connection = ((ConnectionBridge) ctx.channel().pipeline().get(HANDLER_PACKET)); + if (connection.bridge$protocol() != Protocol.HANDSHAKING + && connection.bridge$protocol() != Protocol.LOGIN) { + out.add(msg.retain()); + return; + } + + final int readerIndex = msg.readerIndex(); + final FriendlyByteBuf data = new FriendlyByteBuf(msg); + final int id = data.readVarInt(); + PCF.logger.debug( + "Received " + + connection.bridge$protocol() + + " packet with ID 0x" + + Integer.toHexString(id) + + " from " + + ctx.channel().remoteAddress()); + switch (connection.bridge$protocol()) { - case null -> {} case HANDSHAKING -> { if (!PCF.instance().forwarding().mode().isLegacy()) { - out.add(msg.retain()); - return; + msg.readerIndex(readerIndex); + break; } - final int readerIndex = msg.readerIndex(); - final FriendlyByteBuf data = new FriendlyByteBuf(msg); - final int id = data.readVarInt(); - PCF.logger.debug( - "Received packet with ID 0x" - + Integer.toHexString(id) - + " from " - + ctx.channel().remoteAddress()); - //noinspection SwitchStatementWithTooFewBranches switch (id) { case 0x00 -> { @@ -61,70 +69,35 @@ protected void decode( // Rewrite the packet handleClientIntention(connection, data); - - // Reset reader index and pass it along msg.readerIndex(readerIndex); } - // Reset reader index for unhandled packets default -> msg.readerIndex(readerIndex); } } case LOGIN -> { - // TODO: Clean this up - if (PCF.instance().forwarding().mode().isLegacy()) { - final int readerIndex = msg.readerIndex(); - final FriendlyByteBuf data = new FriendlyByteBuf(msg); - final int id = data.readVarInt(); - PCF.logger.debug( - "Received packet with ID 0x" - + Integer.toHexString(id) - + " from " - + ctx.channel().remoteAddress()); - - //noinspection SwitchStatementWithTooFewBranches - switch (id) { - case 0x00 -> { - PCF.logger.debug( - "Handling ServerBoundHello from " - + ctx.channel().remoteAddress()); - final String name = data.readUtf(16); - ctx.channel().attr(PLAYER_NAME).set(name); - msg.readerIndex(readerIndex); - } - default -> msg.readerIndex(readerIndex); - } - break; - } - - if (!PCF.instance().forwarding().mode().isModern()) { - out.add(msg.retain()); - return; - } - if (!(connection.bridge$getPacketListener() instanceof ServerLoginPacketListenerBridge slpl)) { - out.add(msg.retain()); - return; + msg.readerIndex(readerIndex); + break; } - final int readerIndex = msg.readerIndex(); - final FriendlyByteBuf data = new FriendlyByteBuf(msg); - final int id = data.readVarInt(); - PCF.logger.debug( - "Received packet with ID 0x" - + Integer.toHexString(id) - + " from " - + ctx.channel().remoteAddress()); - - //noinspection SwitchStatementWithTooFewBranches switch (id) { - case 0x02 -> { - final ServerboundCustomQueryAnswerPacket packet = - ServerboundCustomQueryAnswerPacket.STREAM_CODEC.decode(data); + case 0x00 -> { + if (!PCF.instance().forwarding().mode().isLegacy()) { + msg.readerIndex(readerIndex); + break; + } + PCF.logger.debug( + "Handling ServerBoundHelloPacket from " + + ctx.channel().remoteAddress()); - // Check if the packet should be handled - if (packet.transactionId() - != connection.bridge$channel().attr(LOGIN_MESSAGE_ID).get()) { + // Save player name + final String name = data.readUtf(MAX_NAME_LENGTH); + ctx.channel().attr(PLAYER_NAME).set(name); + msg.readerIndex(readerIndex); + } + case 0x02 -> { + if (!PCF.instance().forwarding().mode().isModern()) { msg.readerIndex(readerIndex); break; } @@ -132,22 +105,20 @@ protected void decode( "Handling ServerboundCustomQueryAnswerPacket from " + ctx.channel().remoteAddress()); + boolean handled = false; try { - handleCustomQueryAnswer(slpl, packet); + handled = handleCustomQueryAnswer(slpl, data); } catch (final ThrowingComponent e) { + handled = true; slpl.bridge$disconnect(e.getComponent()); } finally { - msg.clear(); + if (handled) msg.clear(); } } - // Reset reader index for unhandled packets default -> msg.readerIndex(readerIndex); } } - default -> { - out.add(msg.retain()); - return; - } + case null, default -> msg.readerIndex(readerIndex); } if (msg.isReadable()) { diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java index ed0f2b8d..50cea019 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java @@ -20,7 +20,6 @@ import dev.neuralnexus.taterapi.meta.Constraint; import dev.neuralnexus.taterapi.meta.MinecraftVersions; -import dev.neuralnexus.taterapi.mixin.CancellableMixin; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; import dev.neuralnexus.taterapi.network.protocol.handshake.ClientIntent; @@ -193,7 +192,8 @@ public static void handleHello( final GameProfile profile = createProfile(name, uuid, properties); // Proceed with login - Forwarding.preLogin(profile, slpl, new CancellableMixin(ci)); + ci.cancel(); + Forwarding.preLogin(slpl, profile); } /** diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index 4e0dde88..d05eec87 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -9,9 +9,9 @@ import static org.adde0109.pcf.forwarding.modern.VelocityProxy.PLAYER_INFO_PAYLOAD; import static org.adde0109.pcf.forwarding.modern.VelocityProxy.checkIntegrity; -import dev.neuralnexus.taterapi.event.Cancellable; import dev.neuralnexus.taterapi.meta.Constraint; import dev.neuralnexus.taterapi.meta.MinecraftVersions; +import dev.neuralnexus.taterapi.network.FriendlyByteBuf; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; import dev.neuralnexus.taterapi.network.protocol.login.ClientboundCustomQueryPacket; import dev.neuralnexus.taterapi.network.protocol.login.ServerboundCustomQueryAnswerPacket; @@ -84,11 +84,21 @@ public static void handleHello( * CustomQueryAnswer packet handler for modern forwarding * * @param slpl The ServerLoginPacketListenerImpl - * @param packet The Minecraft packet + * @param data The packet buffer */ - public static void handleCustomQueryAnswer( + public static boolean handleCustomQueryAnswer( final @NonNull ServerLoginPacketListenerBridge slpl, - final @NonNull ServerboundCustomQueryAnswerPacket packet) { + final @NonNull FriendlyByteBuf data) { + final ConnectionBridge connection = slpl.bridge$connection(); + final ServerboundCustomQueryAnswerPacket packet = + ServerboundCustomQueryAnswerPacket.STREAM_CODEC.decode(data); + + // Check if the packet should be handled + if (packet.transactionId() != connection.bridge$channel().attr(LOGIN_MESSAGE_ID).get()) { + return false; + } + + // Decode raw buffer final CustomQueryAnswerPayload.Raw rawPayload = packet.payload() instanceof CustomQueryAnswerPayload.Raw raw ? raw : null; @@ -141,7 +151,7 @@ public static void handleCustomQueryAnswer( PCF.logger.debug("Using modern forwarding version: " + version); // Apply IP forwarding - Forwarding.ipForwarding(slpl.bridge$connection(), payload.address()); + Forwarding.ipForwarding(connection, payload.address()); // Handle profile key switch (version) { @@ -183,6 +193,7 @@ public static void handleCustomQueryAnswer( } // Proceed with login - Forwarding.preLogin(payload.profile(), slpl, Cancellable.simple()); + Forwarding.preLogin(slpl, payload.profile()); + return true; } } From 749e720ff3cca3ee5500d2d690d28e89deeb8dcd Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Thu, 23 Apr 2026 23:42:02 -0600 Subject: [PATCH 25/71] 1.7.10 doesn't have access to AttributeKey.valueOf --- .../pcf/forwarding/ReflectionUtils.java | 39 +++++++++++++++++++ .../forwarding/bungeeguard/BungeeGuard.java | 4 +- .../forwarding/legacy/LegacyForwarding.java | 11 +++--- .../forwarding/modern/ModernForwarding.java | 3 +- 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/ReflectionUtils.java b/common/src/main/java/org/adde0109/pcf/forwarding/ReflectionUtils.java index 0197fec1..359f4881 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/ReflectionUtils.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/ReflectionUtils.java @@ -7,6 +7,9 @@ import dev.neuralnexus.taterapi.meta.Constraint; import dev.neuralnexus.taterapi.meta.MetaAPI; import dev.neuralnexus.taterapi.meta.MinecraftVersions; +import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; + +import io.netty.util.AttributeKey; import net.minecraft.server.MinecraftServer; @@ -146,4 +149,40 @@ public static boolean enforceSecureProfile() { throw new RuntimeException(e); } } + + private static final MethodHandle ATTRIBUTE_KEY_VALUE_OF; + + static { + final MethodHandles.Lookup lookup = MethodHandles.lookup(); + MethodHandle attributeKeyValueOfHandle; + try { + if (Constraint.noLessThan(MinecraftVersion.V8).result()) { + final Class attributeKeyClass = Class.forName("io.netty.util.AttributeKey"); + attributeKeyValueOfHandle = + lookup.findStatic( + attributeKeyClass, + "valueOf", + MethodType.methodType(AttributeKey.class, String.class)); + } else { // Get old AttributeKey constructor: AttributeKey(String name) + final Class attributeKeyClass = Class.forName("io.netty.util.AttributeKey"); + //noinspection JavaLangInvokeHandleSignature + attributeKeyValueOfHandle = + lookup.findConstructor( + attributeKeyClass, MethodType.methodType(void.class, String.class)); + } + } catch (final Throwable e) { + throw new IllegalStateException( + "Failed to initialize AttributeKey.valueOf MethodHandle", e); + } + ATTRIBUTE_KEY_VALUE_OF = attributeKeyValueOfHandle; + } + + @SuppressWarnings("unchecked") + public static AttributeKey attributeKeyValueOf(final @NonNull String name) { + try { + return (AttributeKey) ATTRIBUTE_KEY_VALUE_OF.invokeExact(name); + } catch (final Throwable e) { + throw new IllegalStateException("Failed to create AttributeKey with name: " + name, e); + } + } } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/bungeeguard/BungeeGuard.java b/common/src/main/java/org/adde0109/pcf/forwarding/bungeeguard/BungeeGuard.java index abb75d9c..77ca116d 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/bungeeguard/BungeeGuard.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/bungeeguard/BungeeGuard.java @@ -2,6 +2,8 @@ import static dev.neuralnexus.taterapi.network.chat.Component.literal; +import static org.adde0109.pcf.forwarding.ReflectionUtils.attributeKeyValueOf; + import com.mojang.authlib.GameProfile; import dev.neuralnexus.taterapi.event.Cancellable; @@ -20,7 +22,7 @@ public final class BungeeGuard { public static final String BUNGEE_GUARD_TOKEN_PROPERTY_NAME = "bungeeguard-token"; public static final AttributeKey> BUNGEE_GUARD_TOKEN = - AttributeKey.valueOf("pcf-bungeeguard-token"); + attributeKeyValueOf("pcf-bungeeguard-token"); private static final Object NO_DATA = literal("&cUnable to authenticate - no data was forwarded by the proxy."); diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java index 50cea019..46b13d2d 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java @@ -3,6 +3,7 @@ import static dev.neuralnexus.taterapi.network.chat.Component.literal; import static org.adde0109.pcf.forwarding.Forwarding.PLAYER_INFO_ERR; +import static org.adde0109.pcf.forwarding.ReflectionUtils.attributeKeyValueOf; import static org.adde0109.pcf.forwarding.ReflectionUtils.getName; import static org.adde0109.pcf.forwarding.ReflectionUtils.getProperties; import static org.adde0109.pcf.forwarding.ReflectionUtils.getValue; @@ -54,13 +55,13 @@ */ public final class LegacyForwarding { public static final AttributeKey DEFERRED_DISCONNECT = - AttributeKey.valueOf("pcf-deferred-disconnect"); + attributeKeyValueOf("pcf-deferred-disconnect"); public static final AttributeKey FORWARDED_ADDRESS = - AttributeKey.valueOf("pcf-forwarded-address"); - public static final AttributeKey PLAYER_NAME = AttributeKey.valueOf("pcf-player-name"); - public static final AttributeKey SPOOFED_UUID = AttributeKey.valueOf("pcf-spoofed-uuid"); + attributeKeyValueOf("pcf-forwarded-address"); + public static final AttributeKey PLAYER_NAME = attributeKeyValueOf("pcf-player-name"); + public static final AttributeKey SPOOFED_UUID = attributeKeyValueOf("pcf-spoofed-uuid"); public static final AttributeKey> SPOOFED_PROFILE = - AttributeKey.valueOf("pcf-spoofed-profile"); + attributeKeyValueOf("pcf-spoofed-profile"); private static final Object LEGACY_DIRECT_CONNECT_ERR = literal("This server requires you to connect with Velocity or BungeeCord."); diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index d05eec87..59d1caca 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -4,6 +4,7 @@ import static dev.neuralnexus.taterapi.network.chat.Component.translatable; import static org.adde0109.pcf.forwarding.Forwarding.PLAYER_INFO_ERR; +import static org.adde0109.pcf.forwarding.ReflectionUtils.attributeKeyValueOf; import static org.adde0109.pcf.forwarding.ReflectionUtils.enforceSecureProfile; import static org.adde0109.pcf.forwarding.modern.VelocityProxy.MODERN_MAX_VERSION; import static org.adde0109.pcf.forwarding.modern.VelocityProxy.PLAYER_INFO_PAYLOAD; @@ -48,7 +49,7 @@ */ public final class ModernForwarding { public static final AttributeKey LOGIN_MESSAGE_ID = - AttributeKey.valueOf("pcf-login-message-id"); + attributeKeyValueOf("pcf-login-message-id"); private static final Object MODERN_DIRECT_CONNECT_ERR = literal("This server requires you to connect with Velocity."); From 1207d479d8f8d4a552b663e3248aee063bf93c9f Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Fri, 24 Apr 2026 00:32:51 -0600 Subject: [PATCH 26/71] Fixed 1.7.10 chat component handling --- .../forge/forwarding/ServerLoginPacketListenerImplMixin.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ServerLoginPacketListenerImplMixin.java b/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ServerLoginPacketListenerImplMixin.java index 9702fc88..7ac1d8f4 100644 --- a/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ServerLoginPacketListenerImplMixin.java +++ b/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ServerLoginPacketListenerImplMixin.java @@ -28,7 +28,8 @@ public abstract class ServerLoginPacketListenerImplMixin @Override public void bridge$disconnect(final @NonNull Object reason) { - this.shadow$closeConnection(((IChatComponent) reason).getFormattedText()); + // Note: IChatComponent.getFormattedText() is client-only + this.shadow$closeConnection(((IChatComponent) reason).getUnformattedTextForChat()); } @Override From 097693534b2474a779af45c21bc61719613b81c7 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Fri, 24 Apr 2026 03:36:09 -0600 Subject: [PATCH 27/71] Remove copy task from main buildscript --- build.gradle.kts | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index cbe3285c..8359dd29 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -88,6 +88,14 @@ repositories { maven("https://maven.neuralnexus.dev/releases") } +tasks.jar { + enabled = false +} + +tasks.shadowJar { + enabled = false +} + val projs = listOf( ":legacy:v7_10", ":legacy:v12_2", @@ -173,27 +181,21 @@ val customDowngrade = tasks.register("customDowngrade") { archiveClassifier = "downgraded-8" } -val customShadeDowngradedApi = tasks.register("customShadeDowngradedApi") { +val finalJar = tasks.register("finalJar") { inputFile.set(customDowngrade.get().archiveFile) shadePath = { it.substringBefore(".") .substringBeforeLast("-") .replace(Regex("[.;\\[/]"), "-") - .replace("pcf", "org/adde0109/pcf/lib/jvmdg") + .replace("proxy-compatible-forge", "org/adde0109/pcf/lib/jvmdg") } - archiveFileName = "pcf-${version}.jar" -} - -val renameJar = tasks.register("renameJar") { - from(customShadeDowngradedApi.get().archiveFile) - into(file("./build/libs")) - rename { "proxy-compatible-forge-${version}.jar" } + archiveFileName = "proxy-compatible-forge-${rootProject.version}.jar" doLast { - file("./build/libs/proxy-compatible-forge-${version}-mono.jar").delete() - file("./build/libs/proxy-compatible-forge-${version}-downgraded-8.jar").delete() - file("./build/libs/pcf-${version}.jar").delete() + file("./build/libs/proxy-compatible-forge-${rootProject.version}-all.jar").delete() + file("./build/libs/proxy-compatible-forge-${rootProject.version}-mono.jar").delete() + file("./build/libs/proxy-compatible-forge-${rootProject.version}-downgraded-8.jar").delete() } } -tasks.assemble.get().dependsOn(renameJar) +tasks.assemble.get().dependsOn(finalJar) From 88dbf10d3a717bad15cde4fc755b5ed73ca7c73e Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 03:12:23 -0600 Subject: [PATCH 28/71] ConnectionBridge now has a helper method for querying the protocol phase, and the decoder acquires the connection object from the netty pipeline --- .../forwarding/modern/ConnectionBridge.java | 6 +++ .../forwarding/modern/ModernForwarding.java | 6 +-- .../pcf/forwarding/modern/PacketDecoder.java | 16 ++++---- .../forwarding/modern/ConnectionMixin.java | 4 +- .../forwarding/modern/ConnectionMixin.java | 10 +++++ .../forwarding/modern/ConnectionMixin.java | 17 +++++++++ .../forwarding/modern/ConnectionMixin.java | 15 ++++++++ .../forwarding/modern/ConnectionMixin.java | 38 +++++++++++++++++++ .../resources/pcf.mixins.v19_2.forge.json | 1 + .../forwarding/modern/ConnectionMixin.java | 13 +++++++ 10 files changed, 113 insertions(+), 13 deletions(-) create mode 100644 modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ConnectionMixin.java diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ConnectionBridge.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ConnectionBridge.java index e99e7007..2ccf1ee3 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ConnectionBridge.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ConnectionBridge.java @@ -1,5 +1,7 @@ package org.adde0109.pcf.forwarding.modern; +import dev.neuralnexus.taterapi.network.Protocol; + import io.netty.channel.Channel; import org.jspecify.annotations.NonNull; @@ -8,6 +10,8 @@ import java.net.InetSocketAddress; public interface ConnectionBridge { + String PACKET_HANDLER = "packet_handler"; + @NonNull InetSocketAddress bridge$address(); void bridge$address(final @NonNull InetSocketAddress address); @@ -16,6 +20,8 @@ public interface ConnectionBridge { @Nullable Object bridge$getPacketListener(); + @Nullable Protocol bridge$protocol(); + default void bridge$send(final @NonNull Object packet) { this.bridge$channel().writeAndFlush(packet).addListener(ModernForwarding::errorListener); } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index 717c4666..59aeb11a 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -60,11 +60,9 @@ public final class ModernForwarding { /** * Injects the packet encoder and decoder into the pipeline to handle login query packets * - * @param connection the connection * @param ctx the channel handler context */ - public static void injectIntoPipeline( - final @NonNull ConnectionBridge connection, final @NonNull ChannelHandlerContext ctx) { + public static void injectIntoPipeline(final @NonNull ChannelHandlerContext ctx) { if (ctx.pipeline().get(PacketDecoder.NAME) != null || ctx.pipeline().get(PacketEncoder.NAME) != null) { return; @@ -73,7 +71,7 @@ public static void injectIntoPipeline( "Injecting packet handlers into pipeline of " + ctx.channel().remoteAddress()); ctx.channel() .pipeline() - .addAfter(HANDLER_SPLITTER, PacketDecoder.NAME, new PacketDecoder(connection)) + .addAfter(HANDLER_SPLITTER, PacketDecoder.NAME, new PacketDecoder()) .addAfter(HANDLER_PREPENDER, PacketEncoder.NAME, new PacketEncoder()); } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/PacketDecoder.java index d569e47c..208fe23c 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/PacketDecoder.java @@ -1,8 +1,10 @@ package org.adde0109.pcf.forwarding.modern; +import static org.adde0109.pcf.forwarding.modern.ConnectionBridge.PACKET_HANDLER; import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleCustomQueryPacket; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; +import dev.neuralnexus.taterapi.network.Protocol; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; import dev.neuralnexus.taterapi.network.protocol.login.ServerboundCustomQueryAnswerPacket; @@ -18,12 +20,6 @@ public final class PacketDecoder extends MessageToMessageDecoder { public static final String NAME = "pcf-decoder"; - private final ConnectionBridge connection; - - public PacketDecoder(final @NonNull ConnectionBridge connection) { - this.connection = connection; - } - @SuppressWarnings("RedundantThrows") @Override protected void decode( @@ -34,7 +30,13 @@ protected void decode( if (!msg.isReadable()) { return; } - if (!(this.connection.bridge$getPacketListener() + final ConnectionBridge connection = + ((ConnectionBridge) ctx.channel().pipeline().get(PACKET_HANDLER)); + if (!(connection.bridge$protocol() == Protocol.LOGIN)) { + out.add(msg.retain()); + return; + } + if (!(connection.bridge$getPacketListener() instanceof ServerLoginPacketListenerBridge slpl)) { out.add(msg.retain()); return; diff --git a/common/src/main/java/org/adde0109/pcf/mixin/common/forwarding/modern/ConnectionMixin.java b/common/src/main/java/org/adde0109/pcf/mixin/common/forwarding/modern/ConnectionMixin.java index 238fd4da..7c0415c3 100644 --- a/common/src/main/java/org/adde0109/pcf/mixin/common/forwarding/modern/ConnectionMixin.java +++ b/common/src/main/java/org/adde0109/pcf/mixin/common/forwarding/modern/ConnectionMixin.java @@ -41,7 +41,7 @@ public abstract static class Mojang implements ConnectionBridge { @Inject(method = "channelActive", at = @At("TAIL"), remap = false) private void onChannelActive( final @NonNull ChannelHandlerContext ctx, final @NonNull CallbackInfo ci) { - injectIntoPipeline(this, ctx); + injectIntoPipeline(ctx); } } @@ -61,7 +61,7 @@ public abstract static class Searge implements ConnectionBridge { @Inject(method = "channelActive", at = @At("TAIL"), remap = false) private void onChannelActive( final @NonNull ChannelHandlerContext ctx, final @NonNull CallbackInfo ci) { - injectIntoPipeline(this, ctx); + injectIntoPipeline(ctx); } } } diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ConnectionMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ConnectionMixin.java index 42c8e95c..a48744f8 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ConnectionMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ConnectionMixin.java @@ -2,6 +2,7 @@ import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; +import dev.neuralnexus.taterapi.network.Protocol; import net.minecraft.network.Connection; import net.minecraft.network.PacketListener; @@ -37,4 +38,13 @@ public abstract class ConnectionMixin implements ConnectionBridge { public @Nullable Object bridge$getPacketListener() { return this.shadow$getPacketListener(); } + + @Override + public Protocol bridge$protocol() { + final PacketListener listener = this.shadow$getPacketListener(); + if (listener == null) { + return null; + } + return Protocol.fromId(listener.protocol().id()); + } } diff --git a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ConnectionMixin.java b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ConnectionMixin.java index 1e73dd28..c9dff544 100644 --- a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ConnectionMixin.java +++ b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ConnectionMixin.java @@ -4,13 +4,18 @@ import dev.neuralnexus.taterapi.meta.anno.AConstraint; import dev.neuralnexus.taterapi.meta.anno.Versions; import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; +import dev.neuralnexus.taterapi.network.Protocol; +import io.netty.util.AttributeKey; + +import net.minecraft.network.EnumConnectionState; import net.minecraft.network.INetHandler; import net.minecraft.network.NetworkManager; import org.adde0109.pcf.forwarding.modern.ConnectionBridge; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -27,6 +32,8 @@ public abstract class ConnectionMixin implements ConnectionBridge { @Shadow public abstract INetHandler shadow$getNetHandler(); // spotless:on + @Shadow @Final public static AttributeKey PROTOCOL_ATTRIBUTE_KEY; + @Override public @NonNull InetSocketAddress bridge$address() { return (InetSocketAddress) this.socketAddress; @@ -41,4 +48,14 @@ public abstract class ConnectionMixin implements ConnectionBridge { public @Nullable Object bridge$getPacketListener() { return this.shadow$getNetHandler(); } + + @Override + public Protocol bridge$protocol() { + final INetHandler listener = this.shadow$getNetHandler(); + if (listener == null) { + return null; + } + return Protocol.fromLegacyId( + this.bridge$channel().attr(PROTOCOL_ATTRIBUTE_KEY).get().getId()); + } } diff --git a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ConnectionMixin.java b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ConnectionMixin.java index f4263bc3..50f89d62 100644 --- a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ConnectionMixin.java +++ b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ConnectionMixin.java @@ -4,13 +4,18 @@ import dev.neuralnexus.taterapi.meta.anno.AConstraint; import dev.neuralnexus.taterapi.meta.anno.Versions; import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; +import dev.neuralnexus.taterapi.network.Protocol; + +import io.netty.util.AttributeKey; import net.minecraft.network.Connection; +import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.PacketListener; import org.adde0109.pcf.forwarding.modern.ConnectionBridge; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -24,6 +29,7 @@ public abstract class ConnectionMixin implements ConnectionBridge { // spotless:off @Shadow private SocketAddress address; + @Shadow @Final public static AttributeKey ATTRIBUTE_PROTOCOL; @Shadow public abstract PacketListener shadow$getPacketListener(); // spotless:on @@ -41,4 +47,13 @@ public abstract class ConnectionMixin implements ConnectionBridge { public @Nullable Object bridge$getPacketListener() { return this.shadow$getPacketListener(); } + + @Override + public Protocol bridge$protocol() { + final PacketListener listener = this.shadow$getPacketListener(); + if (listener == null) { + return null; + } + return Protocol.fromLegacyId(this.bridge$channel().attr(ATTRIBUTE_PROTOCOL).get().getId()); + } } diff --git a/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ConnectionMixin.java b/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ConnectionMixin.java new file mode 100644 index 00000000..f2b7cca5 --- /dev/null +++ b/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ConnectionMixin.java @@ -0,0 +1,38 @@ +package org.adde0109.pcf.mixin.v19_2.forge.forwarding.modern; + +import dev.neuralnexus.taterapi.meta.Mappings; +import dev.neuralnexus.taterapi.meta.anno.AConstraint; +import dev.neuralnexus.taterapi.meta.anno.Versions; +import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; +import dev.neuralnexus.taterapi.network.Protocol; + +import io.netty.util.AttributeKey; + +import net.minecraft.network.Connection; +import net.minecraft.network.ConnectionProtocol; +import net.minecraft.network.PacketListener; + +import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@AConstraint( + mappings = Mappings.SEARGE, + version = @Versions(min = MinecraftVersion.V17, max = MinecraftVersion.V20_1)) +@Mixin(Connection.class) +public abstract class ConnectionMixin implements ConnectionBridge { + // spotless:off + @Shadow @Final public static AttributeKey ATTRIBUTE_PROTOCOL; + @Shadow public abstract PacketListener shadow$getPacketListener(); + // spotless:on + + @Override + public Protocol bridge$protocol() { + final PacketListener listener = this.shadow$getPacketListener(); + if (listener == null) { + return null; + } + return Protocol.fromLegacyId(this.bridge$channel().attr(ATTRIBUTE_PROTOCOL).get().getId()); + } +} diff --git a/modern/v19_2/src/forge/resources/pcf.mixins.v19_2.forge.json b/modern/v19_2/src/forge/resources/pcf.mixins.v19_2.forge.json index 69f323bf..61ff1a19 100644 --- a/modern/v19_2/src/forge/resources/pcf.mixins.v19_2.forge.json +++ b/modern/v19_2/src/forge/resources/pcf.mixins.v19_2.forge.json @@ -8,6 +8,7 @@ "plugin": "org.adde0109.pcf.mixin.plugin.PCFMixinPlugin", "package": "org.adde0109.pcf.mixin", "server": [ + "v19_2.forge.forwarding.modern.ConnectionMixin", "v19_2.forge.forwarding.modern.LastSeenMessagesValidatorMixin", "v19_2.forge.forwarding.modern.PlayerChatMessageMixin", "v19_2.forge.forwarding.modern.ServerLoginPacketListenerImplKeyV1Mixin", diff --git a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ConnectionMixin.java b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ConnectionMixin.java index b286edd2..c1b0d945 100644 --- a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ConnectionMixin.java +++ b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ConnectionMixin.java @@ -4,6 +4,7 @@ import dev.neuralnexus.taterapi.meta.anno.AConstraint; import dev.neuralnexus.taterapi.meta.anno.Versions; import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; +import dev.neuralnexus.taterapi.network.Protocol; import net.minecraft.network.Connection; import net.minecraft.network.PacketListener; @@ -41,4 +42,16 @@ public abstract class ConnectionMixin implements ConnectionBridge { public @Nullable Object bridge$getPacketListener() { return this.shadow$getPacketListener(); } + + @AConstraint( + mappings = Mappings.SEARGE, + version = @Versions(min = MinecraftVersion.V20_2, max = MinecraftVersion.V20_4)) + @Override + public Protocol bridge$protocol() { + final PacketListener listener = this.shadow$getPacketListener(); + if (listener == null) { + return null; + } + return Protocol.fromId(listener.protocol().id()); + } } From 6f68684f74248f35446239992847e50c5f176bd0 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 03:12:31 -0600 Subject: [PATCH 29/71] Merge updates from main diff --git c/gradle.properties i/gradle.properties index 086c9c8..2f6c4f9 100644 --- c/gradle.properties +++ i/gradle.properties @@ -6,7 +6,7 @@ mod_id=pcf mod_name=ProxyCompatibleForge description=Bring modern forwarding to Neo/Forge servers, requires the Ambassador plugin on Velocity for 1.13-1.20.1, should work standalone on 1.20.2+ group=org.adde0109.pcf -version=1.2.6 +version=1.3.0-SNAPSHOT license=LGPL-2.1 authors=adde0109,JT122406,p0t4t0sandwich java_version=25 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 086c9c87..2f6c4f90 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ mod_id=pcf mod_name=ProxyCompatibleForge description=Bring modern forwarding to Neo/Forge servers, requires the Ambassador plugin on Velocity for 1.13-1.20.1, should work standalone on 1.20.2+ group=org.adde0109.pcf -version=1.2.6 +version=1.3.0-SNAPSHOT license=LGPL-2.1 authors=adde0109,JT122406,p0t4t0sandwich java_version=25 From 9d7d7a2a8dea329dafd86022338bc4d0782d02f7 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 03:16:32 -0600 Subject: [PATCH 30/71] Beginnings of legacy forwarding support --- .../org/adde0109/pcf/forwarding/Mode.java | 3 + .../legacy/ConnectionBridgeLegacy.java | 17 +++ .../forwarding/modern/ReflectionUtils.java | 2 +- .../legacy/ClientIntentionPacketMixin.java | 20 +++ .../legacy/ConnectionLegacyMixin.java | 88 ++++++++++++++ ...erverHandshakePacketListenerImplMixin.java | 115 ++++++++++++++++++ ...rverLoginPacketListenerImplHelloMixin.java | 84 +++++++++++++ .../src/main/resources/pcf.mixins.v26_1.json | 4 + 8 files changed, 332 insertions(+), 1 deletion(-) create mode 100644 common/src/main/java/org/adde0109/pcf/forwarding/legacy/ConnectionBridgeLegacy.java create mode 100644 deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ClientIntentionPacketMixin.java create mode 100644 deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ConnectionLegacyMixin.java create mode 100644 deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerHandshakePacketListenerImplMixin.java create mode 100644 deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/Mode.java b/common/src/main/java/org/adde0109/pcf/forwarding/Mode.java index be35157f..3cf087d8 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/Mode.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/Mode.java @@ -2,5 +2,8 @@ /** Forwarding types supported by PCF */ public enum Mode { + NONE, + LEGACY, + BUNGEEGUARD, MODERN } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/ConnectionBridgeLegacy.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/ConnectionBridgeLegacy.java new file mode 100644 index 00000000..79e415a4 --- /dev/null +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/ConnectionBridgeLegacy.java @@ -0,0 +1,17 @@ +package org.adde0109.pcf.forwarding.legacy; + +import com.mojang.authlib.properties.Property; + +import org.jspecify.annotations.NonNull; + +import java.util.UUID; + +public interface ConnectionBridgeLegacy { + UUID bridge$spoofedUUID(); + + void bridge$spoofedUUID(final @NonNull UUID uuid); + + Property[] bridge$spoofedProfile(); + + void bridge$spoofedProfile(final @NonNull Property[] properties); +} diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ReflectionUtils.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ReflectionUtils.java index 69bf85cc..7618448f 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ReflectionUtils.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ReflectionUtils.java @@ -47,7 +47,7 @@ private ReflectionUtils() {} * @param profile the profile * @return the properties */ - static @NonNull PropertyMap getProperties(final @NonNull GameProfile profile) { + public static @NonNull PropertyMap getProperties(final @NonNull GameProfile profile) { try { return (PropertyMap) profilePropertiesHandle.invokeExact(profile); } catch (final Throwable e) { diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ClientIntentionPacketMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ClientIntentionPacketMixin.java new file mode 100644 index 00000000..5e568590 --- /dev/null +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ClientIntentionPacketMixin.java @@ -0,0 +1,20 @@ +package org.adde0109.pcf.mixin.v26_1.forwarding.legacy; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.handshake.ClientIntentionPacket; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +// https://github.com/caunt/BungeeForge/blob/1.20.2/src/main/java/ua/caunt/bungeeforge/mixin/network/protocol/handshake/ClientIntentionPacket.java#L28 +@Mixin(ClientIntentionPacket.class) +public final class ClientIntentionPacketMixin { + // spotless:off + @Redirect(method = "(Lnet/minecraft/network/FriendlyByteBuf;)V", at = @At(value = "INVOKE", + target = "Lnet/minecraft/network/FriendlyByteBuf;readUtf(I)Ljava/lang/String;")) + // spotless:on + private static String onConstruct(final FriendlyByteBuf input, int length) { + return input.readUtf(Short.MAX_VALUE); + } +} diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ConnectionLegacyMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ConnectionLegacyMixin.java new file mode 100644 index 00000000..074f3ff5 --- /dev/null +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ConnectionLegacyMixin.java @@ -0,0 +1,88 @@ +package org.adde0109.pcf.mixin.v26_1.forwarding.legacy; + +import com.mojang.authlib.properties.Property; + +import dev.neuralnexus.taterapi.meta.Mappings; +import dev.neuralnexus.taterapi.meta.anno.AConstraint; +import dev.neuralnexus.taterapi.network.Protocol; + +import io.netty.channel.Channel; + +import net.minecraft.network.Connection; +import net.minecraft.network.PacketListener; + +import org.adde0109.pcf.forwarding.legacy.ConnectionBridgeLegacy; +import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.UUID; + +@AConstraint(mappings = Mappings.MOJANG) +@Mixin(Connection.class) +public abstract class ConnectionLegacyMixin implements ConnectionBridge, ConnectionBridgeLegacy { + // spotless:off + @Shadow private SocketAddress address; + @Shadow public abstract PacketListener shadow$getPacketListener(); + @Shadow public abstract Channel channel(); + // spotless:on + + @Override + public @NonNull InetSocketAddress bridge$address() { + return (InetSocketAddress) this.address; + } + + @Override + public void bridge$address(final @NonNull InetSocketAddress address) { + this.address = address; + } + + @Override + public @NonNull Channel bridge$channel() { + return this.channel(); + } + + @Override + public @Nullable Object bridge$getPacketListener() { + return this.shadow$getPacketListener(); + } + + @Override + public Protocol bridge$protocol() { + final PacketListener listener = this.shadow$getPacketListener(); + if (listener == null) { + return null; + } + return Protocol.fromId(listener.protocol().id()); + } + + // spotless:off + @Unique private UUID pcf$spoofedUUID = null; + @Unique private Property[] pcf$spoofedProfile = null; + // spotless:on + + @Override + public UUID bridge$spoofedUUID() { + return this.pcf$spoofedUUID; + } + + @Override + public void bridge$spoofedUUID(final @NonNull UUID uuid) { + this.pcf$spoofedUUID = uuid; + } + + @Override + public Property[] bridge$spoofedProfile() { + return this.pcf$spoofedProfile; + } + + @Override + public void bridge$spoofedProfile(final @NonNull Property[] properties) { + this.pcf$spoofedProfile = properties; + } +} diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerHandshakePacketListenerImplMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerHandshakePacketListenerImplMixin.java new file mode 100644 index 00000000..88c20171 --- /dev/null +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerHandshakePacketListenerImplMixin.java @@ -0,0 +1,115 @@ +package org.adde0109.pcf.mixin.v26_1.forwarding.legacy; + +import static dev.neuralnexus.taterapi.network.chat.Component.literal; + +import com.google.common.net.InetAddresses; +import com.google.gson.Gson; +import com.mojang.authlib.properties.Property; + +import net.minecraft.network.Connection; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.handshake.ClientIntentionPacket; +import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket; +import net.minecraft.server.network.ServerHandshakePacketListenerImpl; + +import org.adde0109.pcf.PCF; +import org.adde0109.pcf.forwarding.Mode; +import org.adde0109.pcf.forwarding.legacy.ConnectionBridgeLegacy; +import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.net.InetSocketAddress; +import java.util.Objects; +import java.util.UUID; +import java.util.regex.Pattern; + +// https://hub.spigotmc.org/stash/projects/SPIGOT/repos/spigot/browse/CraftBukkit-Patches/0024-BungeeCord-Support.patch +@Mixin(ServerHandshakePacketListenerImpl.class) +public abstract class ServerHandshakePacketListenerImplMixin { + // spotless:off + @Shadow @Final private Connection connection; + + @Unique private static final char pcf$LEGACY_SEPARATOR = '\0'; + @Unique private static final String pcf$BUNGEE_GUARD_TOKEN_PROPERTY_NAME = "bungeeguard-token"; + + @Unique private static final Gson pcf$gson = new Gson(); + @Unique private static final Pattern pcf$HOST_PATTERN = Pattern.compile("[0-9a-f.:]{0,45}"); + + @Unique private static final Object pcf$DIRECT_CONNECT_ERR = // TODO: Consider two different messages + literal("This server requires you to connect with Velocity or BungeeCord."); + @Unique private static final Object pcf$BG_CONFIG_ERR = + literal("This server requires the proxy to be configured for BungeeGuard forwarding."); + + @Inject(method = "beginLogin", cancellable = true, at = @At(value = "RETURN", + target = "Lnet/minecraft/network/Connection;setupInboundProtocol(Lnet/minecraft/network/ProtocolInfo;Lnet/minecraft/network/PacketListener;)V")) + // spotless:on + private void onBeginLogin( + final ClientIntentionPacket packet, final boolean transfer, final CallbackInfo ci) { + if (PCF.instance().forwarding().mode() != Mode.LEGACY + && PCF.instance().forwarding().mode() != Mode.BUNGEEGUARD) return; + + // Spigot Start + // TODO: Stick this in a packet listener and extract it there and add to the + // ConnectionBridgeLegacy + // Then replace the original serverAddress used for the regular login flow + // Do not forget Forge markers if present + final String[] split = packet.hostName().split("\00"); + PCF.logger.info( + "Received handshake with " + + split.length + + " parts: " + + String.join("\n ", split)); + if ((split.length < 3) || !(pcf$HOST_PATTERN.matcher(split[1]).matches())) { + this.pcf$disconnect(pcf$DIRECT_CONNECT_ERR); + return; + } + if ((split.length < 4) && PCF.instance().forwarding().mode() != Mode.BUNGEEGUARD) { + this.pcf$disconnect(pcf$BG_CONFIG_ERR); + return; + } + + final String originalAddress = split[1]; + final UUID uuid = pcf$fromStringLenient(split[2]); + PCF.logger.info( + "Player " + uuid + " is connecting with original address " + originalAddress); + + // Update the proxied address + final int port = ((ConnectionBridge) this.connection).bridge$address().getPort(); + final InetSocketAddress address = + new InetSocketAddress(InetAddresses.forString(originalAddress), port); + ((ConnectionBridge) this.connection).bridge$address(address); + + // Save the UUID + ((ConnectionBridgeLegacy) this.connection).bridge$spoofedUUID(uuid); + + // Save the properties if present + if (split.length == 4) { // TODO: Enforce if BungeeGuard forwarding + final String profileJSON = split[3]; + ((ConnectionBridgeLegacy) this.connection) + .bridge$spoofedProfile(pcf$gson.fromJson(profileJSON, Property[].class)); + } + // Spigot End + } + + @Unique public void pcf$disconnect(Object component) { + this.connection.send(new ClientboundLoginDisconnectPacket((Component) component)); + this.connection.disconnect((Component) component); + } + + @Unique private static UUID pcf$fromStringLenient(final String string) { + return UUID.fromString( + string.replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5")); + } + + // https://github.com/caunt/BungeeForge/blob/1.20.2/src/main/java/ua/caunt/bungeeforge/mixin/network/protocol/handshake/ClientIntentionPacket.java#L51-L54 + @Unique private static boolean pcf$isFmlMarker(Property property) { + return Objects.equals(property.name(), "extraData") + && property.value().startsWith("\u0001FORGE"); + } +} diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java new file mode 100644 index 00000000..f67d72ce --- /dev/null +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java @@ -0,0 +1,84 @@ +package org.adde0109.pcf.mixin.v26_1.forwarding.legacy; + +import static org.adde0109.pcf.forwarding.modern.ReflectionUtils.getProperties; + +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; + +import dev.neuralnexus.taterapi.meta.Mappings; +import dev.neuralnexus.taterapi.meta.anno.AConstraint; +import dev.neuralnexus.taterapi.meta.anno.Versions; +import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; + +import net.minecraft.network.Connection; +import net.minecraft.network.protocol.login.ServerboundHelloPacket; +import net.minecraft.server.network.ServerLoginPacketListenerImpl; + +import org.adde0109.pcf.forwarding.legacy.ConnectionBridgeLegacy; +import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.jspecify.annotations.NonNull; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.nio.charset.StandardCharsets; +import java.util.UUID; +import java.util.regex.Pattern; + +// https://hub.spigotmc.org/stash/projects/SPIGOT/repos/spigot/browse/CraftBukkit-Patches/0024-BungeeCord-Support.patch +@Mixin(ServerLoginPacketListenerImpl.class) +public abstract class ServerLoginPacketListenerImplHelloMixin + implements ServerLoginPacketListenerBridge { + // spotless:off + @Shadow @Final private Connection connection; + + @Shadow protected abstract void startClientVerification(GameProfile profile); + + @Unique private static final Pattern pcf$PROP_PATTERN = Pattern.compile("\\w{0,16}"); + + @AConstraint(mappings = Mappings.MOJANG, version = @Versions(min = MinecraftVersion.V20_2)) + @Inject(method = "handleHello", cancellable = true, at = @At(value = "INVOKE", ordinal = 1, + target = "Lnet/minecraft/server/network/ServerLoginPacketListenerImpl;startClientVerification(Lcom/mojang/authlib/GameProfile;)V")) + // spotless:on + private void onHandleHello_20_M( + final ServerboundHelloPacket packet, final @NonNull CallbackInfo ci) { + ConnectionBridgeLegacy conn = (ConnectionBridgeLegacy) this.connection; + if (conn.bridge$spoofedProfile() == null) { + return; // TODO: Provide client-bound disconnect error + } + + // TODO: PostProcessors + this.startClientVerification(this.pcf$createOfflineProfile(packet.name())); + ci.cancel(); + } + + // Spigot start + @Unique protected GameProfile pcf$createOfflineProfile(String name) { + final UUID uuid; + if (((ConnectionBridgeLegacy) this.connection).bridge$spoofedUUID() != null) { + uuid = ((ConnectionBridgeLegacy) this.connection).bridge$spoofedUUID(); + } else { + uuid = + UUID.nameUUIDFromBytes( + ("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8)); + } + + // TODO: Add 1.21.9 support + final GameProfile profile = new GameProfile(uuid, name); + final PropertyMap propertiesMap = getProperties(profile); + if (((ConnectionBridgeLegacy) this.connection).bridge$spoofedProfile() != null) { + for (final Property property : + ((ConnectionBridgeLegacy) this.connection).bridge$spoofedProfile()) { + if (!pcf$PROP_PATTERN.matcher(property.name()).matches()) continue; + propertiesMap.put(property.name(), property); + } + } + return profile; + } + // Spigot end +} diff --git a/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json b/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json index b59a9619..7bec5b0e 100644 --- a/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json +++ b/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json @@ -10,6 +10,10 @@ "server": [ "v26_1.crossstich.ArgumentNodeStubMixin", "v26_1.crossstich.ArgumentTypeInfoMixin", + "v26_1.forwarding.legacy.ClientIntentionPacketMixin", + "v26_1.forwarding.legacy.ConnectionLegacyMixin", + "v26_1.forwarding.legacy.ServerHandshakePacketListenerImplMixin", + "v26_1.forwarding.legacy.ServerLoginPacketListenerImplHelloMixin", "v26_1.forwarding.modern.ConnectionMixin", "v26_1.forwarding.modern.ServerLoginPacketListenerImplHelloHybridMixin", "v26_1.forwarding.modern.ServerLoginPacketListenerImplHelloMixin", From 9f548b4df7a4a5bb188af54a618b98d2d6ab094c Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 03:20:23 -0600 Subject: [PATCH 31/71] Relocated ConnectionBridge and PacketEncoder/Decoder --- .../pcf/forwarding/ConnectionBridge.java | 51 +++++++++++++++++++ .../{modern => }/PacketDecoder.java | 7 +-- .../{modern => }/PacketEncoder.java | 2 +- .../forwarding/modern/ConnectionBridge.java | 28 ---------- .../forwarding/modern/ModernForwarding.java | 22 -------- .../ServerLoginPacketListenerBridge.java | 1 + .../{modern => }/ConnectionMixin.java | 10 ++-- .../{modern => }/ConnectionMixin.java | 4 +- .../legacy/ConnectionLegacyMixin.java | 2 +- ...erverHandshakePacketListenerImplMixin.java | 2 +- .../ServerLoginPacketListenerImplMixin.java | 2 +- .../src/main/resources/pcf.mixins.v26_1.json | 2 +- .../{modern => }/ConnectionMixin.java | 4 +- .../ServerLoginPacketListenerImplMixin.java | 2 +- .../resources/pcf.mixins.v12_2.forge.json | 2 +- .../ServerLoginPacketListenerImplMixin.java | 2 +- .../{modern => }/ConnectionMixin.java | 4 +- .../ServerLoginPacketListenerImplMixin.java | 2 +- .../resources/pcf.mixins.v16_5.forge.json | 2 +- .../{modern => }/ConnectionMixin.java | 4 +- .../resources/pcf.mixins.v19_2.forge.json | 2 +- .../{modern => }/ConnectionMixin.java | 4 +- .../ServerLoginPacketListenerImplMixin.java | 2 +- .../resources/pcf.mixins.v20_4.forge.json | 2 +- 24 files changed, 83 insertions(+), 82 deletions(-) create mode 100644 common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java rename common/src/main/java/org/adde0109/pcf/forwarding/{modern => }/PacketDecoder.java (93%) rename common/src/main/java/org/adde0109/pcf/forwarding/{modern => }/PacketEncoder.java (96%) delete mode 100644 common/src/main/java/org/adde0109/pcf/forwarding/modern/ConnectionBridge.java rename common/src/main/java/org/adde0109/pcf/mixin/common/forwarding/{modern => }/ConnectionMixin.java (88%) rename deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/{modern => }/ConnectionMixin.java (92%) rename legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/{modern => }/ConnectionMixin.java (93%) rename modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/{modern => }/ConnectionMixin.java (93%) rename modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/{modern => }/ConnectionMixin.java (91%) rename modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/{modern => }/ConnectionMixin.java (93%) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java b/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java new file mode 100644 index 00000000..8e40c1b6 --- /dev/null +++ b/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java @@ -0,0 +1,51 @@ +package org.adde0109.pcf.forwarding; + +import dev.neuralnexus.taterapi.network.Protocol; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; + +import org.adde0109.pcf.PCF; +import org.adde0109.pcf.forwarding.modern.ModernForwarding; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +import java.net.InetSocketAddress; + +public interface ConnectionBridge { + String HANDLER_PACKET = "packet_handler"; + String HANDLER_SPLITTER = "splitter"; + String HANDLER_PREPENDER = "prepender"; + + @NonNull InetSocketAddress bridge$address(); + + void bridge$address(final @NonNull InetSocketAddress address); + + @NonNull Channel bridge$channel(); + + @Nullable Object bridge$getPacketListener(); + + @Nullable Protocol bridge$protocol(); + + default void bridge$send(final @NonNull Object packet) { + this.bridge$channel().writeAndFlush(packet).addListener(ModernForwarding::errorListener); + } + + /** + * Injects the packet encoder and decoder into the pipeline to handle login query packets + * + * @param ctx the channel handler context + */ + static void injectIntoPipeline(final @NonNull ChannelHandlerContext ctx) { + if (ctx.pipeline().get(PacketDecoder.NAME) != null + || ctx.pipeline().get(PacketEncoder.NAME) != null) { + return; + } + PCF.logger.debug( + "Injecting packet handlers into pipeline of " + ctx.channel().remoteAddress()); + ctx.channel() + .pipeline() + .addAfter(HANDLER_SPLITTER, PacketDecoder.NAME, new PacketDecoder()) + .addAfter(HANDLER_PREPENDER, PacketEncoder.NAME, new PacketEncoder()); + } +} diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java similarity index 93% rename from common/src/main/java/org/adde0109/pcf/forwarding/modern/PacketDecoder.java rename to common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 208fe23c..9cb1c2e5 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -1,6 +1,6 @@ -package org.adde0109.pcf.forwarding.modern; +package org.adde0109.pcf.forwarding; -import static org.adde0109.pcf.forwarding.modern.ConnectionBridge.PACKET_HANDLER; +import static org.adde0109.pcf.forwarding.ConnectionBridge.HANDLER_PACKET; import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleCustomQueryPacket; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; @@ -13,6 +13,7 @@ import io.netty.handler.codec.MessageToMessageDecoder; import org.adde0109.pcf.PCF; +import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import java.util.List; @@ -31,7 +32,7 @@ protected void decode( return; } final ConnectionBridge connection = - ((ConnectionBridge) ctx.channel().pipeline().get(PACKET_HANDLER)); + ((ConnectionBridge) ctx.channel().pipeline().get(HANDLER_PACKET)); if (!(connection.bridge$protocol() == Protocol.LOGIN)) { out.add(msg.retain()); return; diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/PacketEncoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketEncoder.java similarity index 96% rename from common/src/main/java/org/adde0109/pcf/forwarding/modern/PacketEncoder.java rename to common/src/main/java/org/adde0109/pcf/forwarding/PacketEncoder.java index 1de935fe..0097013b 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/PacketEncoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketEncoder.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.forwarding.modern; +package org.adde0109.pcf.forwarding; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; import dev.neuralnexus.taterapi.network.protocol.login.ClientboundCustomQueryPacket; diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ConnectionBridge.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ConnectionBridge.java deleted file mode 100644 index 2ccf1ee3..00000000 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ConnectionBridge.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.adde0109.pcf.forwarding.modern; - -import dev.neuralnexus.taterapi.network.Protocol; - -import io.netty.channel.Channel; - -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -import java.net.InetSocketAddress; - -public interface ConnectionBridge { - String PACKET_HANDLER = "packet_handler"; - - @NonNull InetSocketAddress bridge$address(); - - void bridge$address(final @NonNull InetSocketAddress address); - - @NonNull Channel bridge$channel(); - - @Nullable Object bridge$getPacketListener(); - - @Nullable Protocol bridge$protocol(); - - default void bridge$send(final @NonNull Object packet) { - this.bridge$channel().writeAndFlush(packet).addListener(ModernForwarding::errorListener); - } -} diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index 59aeb11a..27a5366f 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -19,7 +19,6 @@ import dev.neuralnexus.taterapi.network.protocol.login.ServerboundCustomQueryAnswerPacket; import dev.neuralnexus.taterapi.network.protocol.login.custom.CustomQueryAnswerPayload; -import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.DecoderException; import io.netty.util.concurrent.Future; @@ -54,27 +53,6 @@ public final class ModernForwarding { private static final Object REJECTED_PROXY_ERR = literal("Unapproved proxy host."); - private static final String HANDLER_SPLITTER = "splitter"; - private static final String HANDLER_PREPENDER = "prepender"; - - /** - * Injects the packet encoder and decoder into the pipeline to handle login query packets - * - * @param ctx the channel handler context - */ - public static void injectIntoPipeline(final @NonNull ChannelHandlerContext ctx) { - if (ctx.pipeline().get(PacketDecoder.NAME) != null - || ctx.pipeline().get(PacketEncoder.NAME) != null) { - return; - } - PCF.logger.debug( - "Injecting packet handlers into pipeline of " + ctx.channel().remoteAddress()); - ctx.channel() - .pipeline() - .addAfter(HANDLER_SPLITTER, PacketDecoder.NAME, new PacketDecoder()) - .addAfter(HANDLER_PREPENDER, PacketEncoder.NAME, new PacketEncoder()); - } - /** * Listener for logging errors during packet handling * diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ServerLoginPacketListenerBridge.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ServerLoginPacketListenerBridge.java index 0de20f66..0686d116 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ServerLoginPacketListenerBridge.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ServerLoginPacketListenerBridge.java @@ -4,6 +4,7 @@ import dev.neuralnexus.taterapi.mc.world.entity.player.ProfilePublicKey; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; diff --git a/common/src/main/java/org/adde0109/pcf/mixin/common/forwarding/modern/ConnectionMixin.java b/common/src/main/java/org/adde0109/pcf/mixin/common/forwarding/ConnectionMixin.java similarity index 88% rename from common/src/main/java/org/adde0109/pcf/mixin/common/forwarding/modern/ConnectionMixin.java rename to common/src/main/java/org/adde0109/pcf/mixin/common/forwarding/ConnectionMixin.java index 7c0415c3..e0d8fd6b 100644 --- a/common/src/main/java/org/adde0109/pcf/mixin/common/forwarding/modern/ConnectionMixin.java +++ b/common/src/main/java/org/adde0109/pcf/mixin/common/forwarding/ConnectionMixin.java @@ -1,6 +1,4 @@ -package org.adde0109.pcf.mixin.common.forwarding.modern; - -import static org.adde0109.pcf.forwarding.modern.ModernForwarding.injectIntoPipeline; +package org.adde0109.pcf.mixin.common.forwarding; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; @@ -11,7 +9,7 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -41,7 +39,7 @@ public abstract static class Mojang implements ConnectionBridge { @Inject(method = "channelActive", at = @At("TAIL"), remap = false) private void onChannelActive( final @NonNull ChannelHandlerContext ctx, final @NonNull CallbackInfo ci) { - injectIntoPipeline(ctx); + ConnectionBridge.injectIntoPipeline(ctx); } } @@ -61,7 +59,7 @@ public abstract static class Searge implements ConnectionBridge { @Inject(method = "channelActive", at = @At("TAIL"), remap = false) private void onChannelActive( final @NonNull ChannelHandlerContext ctx, final @NonNull CallbackInfo ci) { - injectIntoPipeline(ctx); + ConnectionBridge.injectIntoPipeline(ctx); } } } diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ConnectionMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ConnectionMixin.java similarity index 92% rename from deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ConnectionMixin.java rename to deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ConnectionMixin.java index a48744f8..0a96af26 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ConnectionMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ConnectionMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v26_1.forwarding.modern; +package org.adde0109.pcf.mixin.v26_1.forwarding; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; @@ -7,7 +7,7 @@ import net.minecraft.network.Connection; import net.minecraft.network.PacketListener; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ConnectionLegacyMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ConnectionLegacyMixin.java index 074f3ff5..01c77d59 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ConnectionLegacyMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ConnectionLegacyMixin.java @@ -11,8 +11,8 @@ import net.minecraft.network.Connection; import net.minecraft.network.PacketListener; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.legacy.ConnectionBridgeLegacy; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerHandshakePacketListenerImplMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerHandshakePacketListenerImplMixin.java index 88c20171..e3bbb437 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerHandshakePacketListenerImplMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerHandshakePacketListenerImplMixin.java @@ -13,9 +13,9 @@ import net.minecraft.server.network.ServerHandshakePacketListenerImpl; import org.adde0109.pcf.PCF; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.Mode; import org.adde0109.pcf.forwarding.legacy.ConnectionBridgeLegacy; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplMixin.java index f1592689..840ec438 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplMixin.java @@ -11,7 +11,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.server.network.ServerLoginPacketListenerImpl; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import org.slf4j.Logger; diff --git a/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json b/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json index 7bec5b0e..af4961cd 100644 --- a/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json +++ b/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json @@ -10,11 +10,11 @@ "server": [ "v26_1.crossstich.ArgumentNodeStubMixin", "v26_1.crossstich.ArgumentTypeInfoMixin", + "v26_1.forwarding.ConnectionMixin", "v26_1.forwarding.legacy.ClientIntentionPacketMixin", "v26_1.forwarding.legacy.ConnectionLegacyMixin", "v26_1.forwarding.legacy.ServerHandshakePacketListenerImplMixin", "v26_1.forwarding.legacy.ServerLoginPacketListenerImplHelloMixin", - "v26_1.forwarding.modern.ConnectionMixin", "v26_1.forwarding.modern.ServerLoginPacketListenerImplHelloHybridMixin", "v26_1.forwarding.modern.ServerLoginPacketListenerImplHelloMixin", "v26_1.forwarding.modern.ServerLoginPacketListenerImplMixin" diff --git a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ConnectionMixin.java b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ConnectionMixin.java similarity index 93% rename from legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ConnectionMixin.java rename to legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ConnectionMixin.java index c9dff544..84609d2e 100644 --- a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ConnectionMixin.java +++ b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ConnectionMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v12_2.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v12_2.forge.forwarding; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; @@ -12,7 +12,7 @@ import net.minecraft.network.INetHandler; import net.minecraft.network.NetworkManager; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.Final; diff --git a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java index a407f474..6a6cc92e 100644 --- a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java @@ -11,7 +11,7 @@ import net.minecraft.server.network.NetHandlerLoginServer; import net.minecraft.util.text.ITextComponent; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; import org.apache.logging.log4j.Logger; import org.jspecify.annotations.NonNull; diff --git a/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json b/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json index d6446391..ee3cc450 100644 --- a/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json +++ b/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json @@ -8,7 +8,7 @@ "plugin": "org.adde0109.pcf.mixin.plugin.PCFMixinPlugin", "package": "org.adde0109.pcf.mixin", "server": [ - "v12_2.forge.forwarding.modern.ConnectionMixin", + "v12_2.forge.forwarding.ConnectionMixin", "v12_2.forge.forwarding.modern.ServerLoginPacketListenerImplHelloMixin", "v12_2.forge.forwarding.modern.ServerLoginPacketListenerImplMixin", "v12_2.forge.forwarding.modern.ServerLoginPacketListenerImplMixin$SLPLIMixin_12" diff --git a/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java index 4638354b..4a746826 100644 --- a/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java @@ -13,7 +13,7 @@ import net.minecraft.network.NetworkManager; import net.minecraft.util.text.ITextComponent; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; import org.apache.logging.log4j.Logger; import org.jspecify.annotations.NonNull; diff --git a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ConnectionMixin.java b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ConnectionMixin.java similarity index 93% rename from modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ConnectionMixin.java rename to modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ConnectionMixin.java index 50f89d62..246fe622 100644 --- a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ConnectionMixin.java +++ b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ConnectionMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v16_5.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v16_5.forge.forwarding; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; @@ -12,7 +12,7 @@ import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.PacketListener; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.Final; diff --git a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java index 1f94b4c1..03178fc8 100644 --- a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java @@ -14,7 +14,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.server.network.ServerLoginPacketListenerImpl; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; import org.apache.commons.lang3.Validate; import org.apache.logging.log4j.Logger; diff --git a/modern/v16_5/src/forge/resources/pcf.mixins.v16_5.forge.json b/modern/v16_5/src/forge/resources/pcf.mixins.v16_5.forge.json index 8250d302..1b3365fe 100644 --- a/modern/v16_5/src/forge/resources/pcf.mixins.v16_5.forge.json +++ b/modern/v16_5/src/forge/resources/pcf.mixins.v16_5.forge.json @@ -11,7 +11,7 @@ "v16_5.forge.crossstitch.ArgumentTypesAccessor", "v16_5.forge.crossstitch.ArgumentTypesEntryMixin", "v16_5.forge.crossstitch.CommandsPacketMixin", - "v16_5.forge.forwarding.modern.ConnectionMixin", + "v16_5.forge.forwarding.ConnectionMixin", "v16_5.forge.forwarding.modern.ServerLoginPacketListenerImplMixin" ] } diff --git a/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ConnectionMixin.java b/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/ConnectionMixin.java similarity index 91% rename from modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ConnectionMixin.java rename to modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/ConnectionMixin.java index f2b7cca5..6791bd75 100644 --- a/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ConnectionMixin.java +++ b/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/ConnectionMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v19_2.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v19_2.forge.forwarding; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; @@ -12,7 +12,7 @@ import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.PacketListener; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; diff --git a/modern/v19_2/src/forge/resources/pcf.mixins.v19_2.forge.json b/modern/v19_2/src/forge/resources/pcf.mixins.v19_2.forge.json index 61ff1a19..133aed07 100644 --- a/modern/v19_2/src/forge/resources/pcf.mixins.v19_2.forge.json +++ b/modern/v19_2/src/forge/resources/pcf.mixins.v19_2.forge.json @@ -8,7 +8,7 @@ "plugin": "org.adde0109.pcf.mixin.plugin.PCFMixinPlugin", "package": "org.adde0109.pcf.mixin", "server": [ - "v19_2.forge.forwarding.modern.ConnectionMixin", + "v19_2.forge.forwarding.ConnectionMixin", "v19_2.forge.forwarding.modern.LastSeenMessagesValidatorMixin", "v19_2.forge.forwarding.modern.PlayerChatMessageMixin", "v19_2.forge.forwarding.modern.ServerLoginPacketListenerImplKeyV1Mixin", diff --git a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ConnectionMixin.java b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ConnectionMixin.java similarity index 93% rename from modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ConnectionMixin.java rename to modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ConnectionMixin.java index c1b0d945..e4d2e8bb 100644 --- a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ConnectionMixin.java +++ b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ConnectionMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v20_4.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v20_4.forge.forwarding; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; @@ -9,7 +9,7 @@ import net.minecraft.network.Connection; import net.minecraft.network.PacketListener; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; diff --git a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java index ceee182b..6772624c 100644 --- a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java @@ -11,7 +11,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.server.network.ServerLoginPacketListenerImpl; -import org.adde0109.pcf.forwarding.modern.ConnectionBridge; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; diff --git a/modern/v20_4/src/forge/resources/pcf.mixins.v20_4.forge.json b/modern/v20_4/src/forge/resources/pcf.mixins.v20_4.forge.json index f444e6e2..b404d10e 100644 --- a/modern/v20_4/src/forge/resources/pcf.mixins.v20_4.forge.json +++ b/modern/v20_4/src/forge/resources/pcf.mixins.v20_4.forge.json @@ -10,7 +10,7 @@ "server": [ "v20_4.forge.crossstitch.ArgumentNodeStubMixin", "v20_4.forge.crossstitch.ArgumentTypeInfoMixin", - "v20_4.forge.forwarding.modern.ConnectionMixin", + "v20_4.forge.forwarding.ConnectionMixin", "v20_4.forge.forwarding.modern.ServerLoginPacketListenerImplLoggerMixin", "v20_4.forge.forwarding.modern.ServerLoginPacketListenerImplMixin" ] From 51853c871a43d79fcd0244dc16801a1d5a6c1c5b Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 03:27:16 -0600 Subject: [PATCH 32/71] Disable mixins in the forwarding.legacy package if the mode is not LEGACY --- .../java/org/adde0109/pcf/mixin/plugin/PCFMixinPlugin.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common/src/main/java/org/adde0109/pcf/mixin/plugin/PCFMixinPlugin.java b/common/src/main/java/org/adde0109/pcf/mixin/plugin/PCFMixinPlugin.java index 2c0cb1fd..234aaec8 100644 --- a/common/src/main/java/org/adde0109/pcf/mixin/plugin/PCFMixinPlugin.java +++ b/common/src/main/java/org/adde0109/pcf/mixin/plugin/PCFMixinPlugin.java @@ -86,6 +86,10 @@ private static boolean shouldApplyMixin( PCF.logger.debug("Skipping mixin " + m + " because forwarding mode is not MODERN."); return false; } + if (forwarding.mode() != Mode.LEGACY && m.contains(".forwarding.legacy.")) { + PCF.logger.debug("Skipping mixin " + m + " because forwarding mode is not LEGACY."); + return false; + } if (advanced.modernForwardingVersion() != NO_OVERRIDE && Constraint.builder().version(MinecraftVersions.V19).result() && advanced.modernForwardingVersion() != MODERN_FORWARDING_WITH_KEY From 21361acb77bf7c991445d0d1aefb8ffeaff6b777 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 03:38:36 -0600 Subject: [PATCH 33/71] Missed a package change --- common/src/main/resources/pcf.mixins.common.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/main/resources/pcf.mixins.common.json b/common/src/main/resources/pcf.mixins.common.json index 204d63a5..f4833e26 100644 --- a/common/src/main/resources/pcf.mixins.common.json +++ b/common/src/main/resources/pcf.mixins.common.json @@ -8,7 +8,7 @@ "plugin": "org.adde0109.pcf.mixin.plugin.PCFMixinPlugin", "package": "org.adde0109.pcf.mixin", "server": [ - "common.forwarding.modern.ConnectionMixin$Mojang", - "common.forwarding.modern.ConnectionMixin$Searge" + "common.forwarding.ConnectionMixin$Mojang", + "common.forwarding.ConnectionMixin$Searge" ] } From 09d8cf734ae868a8b73ba50ad7a1e7051a5194b8 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 06:22:24 -0600 Subject: [PATCH 34/71] Moved intention packet handling into the decoder --- common/build.gradle.kts | 1 + .../pcf/forwarding/PacketDecoder.java | 119 +++++++++++------ .../legacy/ConnectionBridgeLegacy.java | 17 --- .../forwarding/legacy/LegacyForwarding.java | 123 ++++++++++++++++++ .../legacy/ClientIntentionPacketMixin.java | 20 --- .../legacy/ConnectionLegacyMixin.java | 88 ------------- ...erverHandshakePacketListenerImplMixin.java | 115 ---------------- ...rverLoginPacketListenerImplHelloMixin.java | 20 +-- .../src/main/resources/pcf.mixins.v26_1.json | 3 - gradle/libs.versions.toml | 1 + 10 files changed, 218 insertions(+), 289 deletions(-) delete mode 100644 common/src/main/java/org/adde0109/pcf/forwarding/legacy/ConnectionBridgeLegacy.java create mode 100644 common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java delete mode 100644 deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ClientIntentionPacketMixin.java delete mode 100644 deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ConnectionLegacyMixin.java delete mode 100644 deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerHandshakePacketListenerImplMixin.java diff --git a/common/build.gradle.kts b/common/build.gradle.kts index de358e8e..4eff3ab9 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -23,6 +23,7 @@ dependencies { compileOnly(libs.annotations) compileOnly(libs.mojang.authlib) compileOnly(libs.mojang.brigadier) + compileOnly(libs.gson) compileOnly(libs.guava) compileOnly(libs.jspecify) compileOnly(libs.mixin) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 9cb1c2e5..0e21ae7d 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -1,10 +1,10 @@ package org.adde0109.pcf.forwarding; import static org.adde0109.pcf.forwarding.ConnectionBridge.HANDLER_PACKET; +import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.handleClientIntentionPacket; import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleCustomQueryPacket; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; -import dev.neuralnexus.taterapi.network.Protocol; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; import dev.neuralnexus.taterapi.network.protocol.login.ServerboundCustomQueryAnswerPacket; @@ -33,50 +33,93 @@ protected void decode( } final ConnectionBridge connection = ((ConnectionBridge) ctx.channel().pipeline().get(HANDLER_PACKET)); - if (!(connection.bridge$protocol() == Protocol.LOGIN)) { - out.add(msg.retain()); - return; - } - if (!(connection.bridge$getPacketListener() - instanceof ServerLoginPacketListenerBridge slpl)) { - out.add(msg.retain()); - return; - } - final int readerIndex = msg.readerIndex(); - final FriendlyByteBuf data = new FriendlyByteBuf(msg); - final int id = data.readVarInt(); - PCF.logger.debug( - "Received packet with ID 0x" - + Integer.toHexString(id) - + " from " - + ctx.channel().remoteAddress()); - - //noinspection SwitchStatementWithTooFewBranches - switch (id) { - case 0x02 -> { - final ServerboundCustomQueryAnswerPacket packet = - ServerboundCustomQueryAnswerPacket.STREAM_CODEC.decode(data); - - // Check if the packet should be handled - if (packet.transactionId() != slpl.bridge$velocityLoginMessageId()) { - msg.readerIndex(readerIndex); - break; + switch (connection.bridge$protocol()) { + case null -> {} + case HANDSHAKING -> { + if (PCF.instance().forwarding().mode() != Mode.LEGACY + && PCF.instance().forwarding().mode() != Mode.BUNGEEGUARD) { + out.add(msg.retain()); + return; + } + + final int readerIndex = msg.readerIndex(); + final FriendlyByteBuf data = new FriendlyByteBuf(msg); + final int id = data.readVarInt(); + PCF.logger.debug( + "Received packet with ID 0x" + + Integer.toHexString(id) + + " from " + + ctx.channel().remoteAddress()); + + //noinspection SwitchStatementWithTooFewBranches + switch (id) { + case 0x00 -> { + PCF.logger.debug( + "Handling ClientIntentionPacket from " + + ctx.channel().remoteAddress()); + + try { + handleClientIntentionPacket(connection, data); + } catch (final ThrowingComponent e) { + throw e; + // connection.bridge$disconnect(e.getComponent()); + } finally { + // Reset reader index and pass it along + msg.readerIndex(readerIndex); + } + } + // Reset reader index for unhandled packets + default -> msg.readerIndex(readerIndex); + } + } + case LOGIN -> { + if (!(connection.bridge$getPacketListener() + instanceof ServerLoginPacketListenerBridge slpl)) { + out.add(msg.retain()); + return; } + + final int readerIndex = msg.readerIndex(); + final FriendlyByteBuf data = new FriendlyByteBuf(msg); + final int id = data.readVarInt(); PCF.logger.debug( - "Handling ServerboundCustomQueryAnswerPacket from " + "Received packet with ID 0x" + + Integer.toHexString(id) + + " from " + ctx.channel().remoteAddress()); - try { - handleCustomQueryPacket(slpl, packet); - } catch (final ThrowingComponent e) { - slpl.bridge$disconnect(e.getComponent()); - } finally { - msg.clear(); + //noinspection SwitchStatementWithTooFewBranches + switch (id) { + case 0x02 -> { + final ServerboundCustomQueryAnswerPacket packet = + ServerboundCustomQueryAnswerPacket.STREAM_CODEC.decode(data); + + // Check if the packet should be handled + if (packet.transactionId() != slpl.bridge$velocityLoginMessageId()) { + msg.readerIndex(readerIndex); + break; + } + PCF.logger.debug( + "Handling ServerboundCustomQueryAnswerPacket from " + + ctx.channel().remoteAddress()); + + try { + handleCustomQueryPacket(slpl, packet); + } catch (final ThrowingComponent e) { + slpl.bridge$disconnect(e.getComponent()); + } finally { + msg.clear(); + } + } + // Reset reader index for unhandled packets + default -> msg.readerIndex(readerIndex); } } - // Reset reader index for unhandled packets - default -> msg.readerIndex(readerIndex); + default -> { + out.add(msg.retain()); + return; + } } if (msg.isReadable()) { diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/ConnectionBridgeLegacy.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/ConnectionBridgeLegacy.java deleted file mode 100644 index 79e415a4..00000000 --- a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/ConnectionBridgeLegacy.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.adde0109.pcf.forwarding.legacy; - -import com.mojang.authlib.properties.Property; - -import org.jspecify.annotations.NonNull; - -import java.util.UUID; - -public interface ConnectionBridgeLegacy { - UUID bridge$spoofedUUID(); - - void bridge$spoofedUUID(final @NonNull UUID uuid); - - Property[] bridge$spoofedProfile(); - - void bridge$spoofedProfile(final @NonNull Property[] properties); -} diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java new file mode 100644 index 00000000..40ad081d --- /dev/null +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java @@ -0,0 +1,123 @@ +package org.adde0109.pcf.forwarding.legacy; + +import static dev.neuralnexus.taterapi.network.chat.Component.literal; + +import com.google.common.net.InetAddresses; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.mojang.authlib.properties.Property; + +import dev.neuralnexus.taterapi.network.FriendlyByteBuf; +import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; +import dev.neuralnexus.taterapi.network.protocol.handshake.ClientIntent; +import dev.neuralnexus.taterapi.network.protocol.handshake.ClientIntentionPacket; + +import io.netty.util.AttributeKey; + +import org.adde0109.pcf.PCF; +import org.adde0109.pcf.forwarding.ConnectionBridge; +import org.adde0109.pcf.forwarding.Mode; +import org.jspecify.annotations.NonNull; + +import java.net.InetSocketAddress; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.regex.Pattern; + +public final class LegacyForwarding { + public static final AttributeKey SPOOFED_UUID = AttributeKey.valueOf("pcf-spoofed-uuid"); + public static final AttributeKey> SPOOFED_PROFILE = + AttributeKey.valueOf("pcf-spoofed-profile"); + + private static final char LEGACY_SEPARATOR = '\0'; + private static final String BUNGEE_GUARD_TOKEN_PROPERTY_NAME = "bungeeguard-token"; + + private static final Gson GSON = new GsonBuilder().create(); + private static final TypeToken> profileTypeToken = new TypeToken<>() {}; + + private static final Pattern HOST_PATTERN = Pattern.compile("[0-9a-f.:]{0,45}"); + + private static final Object DIRECT_CONNECT_ERR = // TODO: Consider two different messages + literal("This server requires you to connect with Velocity or BungeeCord."); + private static final Object BG_CONFIG_ERR = + literal("This server requires the proxy to be configured for BungeeGuard forwarding."); + + // https://hub.spigotmc.org/stash/projects/SPIGOT/repos/spigot/browse/CraftBukkit-Patches/0024-BungeeCord-Support.patch + // https://github.com/caunt/BungeeForge/blob/1.20.2/src/main/java/ua/caunt/bungeeforge/mixin/network/protocol/handshake/ClientIntentionPacket.java#L51-L54 + public static void handleClientIntentionPacket( + final @NonNull ConnectionBridge connection, final @NonNull FriendlyByteBuf data) { + final int protocolVersion = data.readVarInt(); + final String hostName = data.readUtf(Short.MAX_VALUE); + final int _ = data.readUnsignedShort(); + final ClientIntent intention = ClientIntent.byId(data.readVarInt()); + if (intention != ClientIntent.LOGIN) { + return; + } + + final String[] split = hostName.split("\00"); + if ((split.length < 3) || !(HOST_PATTERN.matcher(split[1]).matches())) { + throw new ThrowingComponent(DIRECT_CONNECT_ERR); + } + if (PCF.instance().forwarding().mode() != Mode.BUNGEEGUARD && (split.length < 4)) { + throw new ThrowingComponent(BG_CONFIG_ERR); + } + + final String originalHost = split[0]; + final String forwardedAddress = split[1]; + final UUID uuid = fromStringLenient(split[2]); + PCF.logger.debug( + "Player " + uuid + " is connecting with forwarded address " + forwardedAddress); + + // Update the proxied address + final int port = connection.bridge$address().getPort(); + final InetSocketAddress address = + new InetSocketAddress(InetAddresses.forString(forwardedAddress), port); + connection.bridge$address(address); + + // Save the UUID + connection.bridge$channel().attr(SPOOFED_UUID).set(uuid); + + // Save the properties if present + final Optional fmlMarker; + if (split.length == 4) { + final String profileJSON = split[3]; + final List properties = GSON.fromJson(profileJSON, profileTypeToken); + + // Pop out the FML marker if present + fmlMarker = properties.stream().filter(LegacyForwarding::isFmlMarker).findFirst(); + properties.removeIf(LegacyForwarding::isFmlMarker); + connection.bridge$channel().attr(SPOOFED_PROFILE).set(properties); + } else { + fmlMarker = Optional.empty(); + } + + // spotless:off + final String host = fmlMarker.map(property -> originalHost + + LEGACY_SEPARATOR + + property.value().split("\u0001")[1] + + LEGACY_SEPARATOR).orElse(originalHost); + // spotless:on + + // Write the original address back into packet + final ClientIntentionPacket newPacket = + new ClientIntentionPacket(protocolVersion, host, port, intention); + data.clear(); + data.writeVarInt(0x00); + ClientIntentionPacket.STREAM_CODEC.encode(data, newPacket); + } + + private static @NonNull UUID fromStringLenient(final @NonNull String string) { + return UUID.fromString( + string.replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5")); + } + + // https://github.com/caunt/BungeeForge/blob/1.20.2/src/main/java/ua/caunt/bungeeforge/mixin/network/protocol/handshake/ClientIntentionPacket.java#L51-L54 + private static boolean isFmlMarker(final @NonNull Property property) { + return Objects.equals(property.name(), "extraData") + && property.value().startsWith("\u0001FORGE"); + } +} diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ClientIntentionPacketMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ClientIntentionPacketMixin.java deleted file mode 100644 index 5e568590..00000000 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ClientIntentionPacketMixin.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.adde0109.pcf.mixin.v26_1.forwarding.legacy; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.protocol.handshake.ClientIntentionPacket; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -// https://github.com/caunt/BungeeForge/blob/1.20.2/src/main/java/ua/caunt/bungeeforge/mixin/network/protocol/handshake/ClientIntentionPacket.java#L28 -@Mixin(ClientIntentionPacket.class) -public final class ClientIntentionPacketMixin { - // spotless:off - @Redirect(method = "(Lnet/minecraft/network/FriendlyByteBuf;)V", at = @At(value = "INVOKE", - target = "Lnet/minecraft/network/FriendlyByteBuf;readUtf(I)Ljava/lang/String;")) - // spotless:on - private static String onConstruct(final FriendlyByteBuf input, int length) { - return input.readUtf(Short.MAX_VALUE); - } -} diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ConnectionLegacyMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ConnectionLegacyMixin.java deleted file mode 100644 index 01c77d59..00000000 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ConnectionLegacyMixin.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.adde0109.pcf.mixin.v26_1.forwarding.legacy; - -import com.mojang.authlib.properties.Property; - -import dev.neuralnexus.taterapi.meta.Mappings; -import dev.neuralnexus.taterapi.meta.anno.AConstraint; -import dev.neuralnexus.taterapi.network.Protocol; - -import io.netty.channel.Channel; - -import net.minecraft.network.Connection; -import net.minecraft.network.PacketListener; - -import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.adde0109.pcf.forwarding.legacy.ConnectionBridgeLegacy; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; - -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.util.UUID; - -@AConstraint(mappings = Mappings.MOJANG) -@Mixin(Connection.class) -public abstract class ConnectionLegacyMixin implements ConnectionBridge, ConnectionBridgeLegacy { - // spotless:off - @Shadow private SocketAddress address; - @Shadow public abstract PacketListener shadow$getPacketListener(); - @Shadow public abstract Channel channel(); - // spotless:on - - @Override - public @NonNull InetSocketAddress bridge$address() { - return (InetSocketAddress) this.address; - } - - @Override - public void bridge$address(final @NonNull InetSocketAddress address) { - this.address = address; - } - - @Override - public @NonNull Channel bridge$channel() { - return this.channel(); - } - - @Override - public @Nullable Object bridge$getPacketListener() { - return this.shadow$getPacketListener(); - } - - @Override - public Protocol bridge$protocol() { - final PacketListener listener = this.shadow$getPacketListener(); - if (listener == null) { - return null; - } - return Protocol.fromId(listener.protocol().id()); - } - - // spotless:off - @Unique private UUID pcf$spoofedUUID = null; - @Unique private Property[] pcf$spoofedProfile = null; - // spotless:on - - @Override - public UUID bridge$spoofedUUID() { - return this.pcf$spoofedUUID; - } - - @Override - public void bridge$spoofedUUID(final @NonNull UUID uuid) { - this.pcf$spoofedUUID = uuid; - } - - @Override - public Property[] bridge$spoofedProfile() { - return this.pcf$spoofedProfile; - } - - @Override - public void bridge$spoofedProfile(final @NonNull Property[] properties) { - this.pcf$spoofedProfile = properties; - } -} diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerHandshakePacketListenerImplMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerHandshakePacketListenerImplMixin.java deleted file mode 100644 index e3bbb437..00000000 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerHandshakePacketListenerImplMixin.java +++ /dev/null @@ -1,115 +0,0 @@ -package org.adde0109.pcf.mixin.v26_1.forwarding.legacy; - -import static dev.neuralnexus.taterapi.network.chat.Component.literal; - -import com.google.common.net.InetAddresses; -import com.google.gson.Gson; -import com.mojang.authlib.properties.Property; - -import net.minecraft.network.Connection; -import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.handshake.ClientIntentionPacket; -import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket; -import net.minecraft.server.network.ServerHandshakePacketListenerImpl; - -import org.adde0109.pcf.PCF; -import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.adde0109.pcf.forwarding.Mode; -import org.adde0109.pcf.forwarding.legacy.ConnectionBridgeLegacy; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.net.InetSocketAddress; -import java.util.Objects; -import java.util.UUID; -import java.util.regex.Pattern; - -// https://hub.spigotmc.org/stash/projects/SPIGOT/repos/spigot/browse/CraftBukkit-Patches/0024-BungeeCord-Support.patch -@Mixin(ServerHandshakePacketListenerImpl.class) -public abstract class ServerHandshakePacketListenerImplMixin { - // spotless:off - @Shadow @Final private Connection connection; - - @Unique private static final char pcf$LEGACY_SEPARATOR = '\0'; - @Unique private static final String pcf$BUNGEE_GUARD_TOKEN_PROPERTY_NAME = "bungeeguard-token"; - - @Unique private static final Gson pcf$gson = new Gson(); - @Unique private static final Pattern pcf$HOST_PATTERN = Pattern.compile("[0-9a-f.:]{0,45}"); - - @Unique private static final Object pcf$DIRECT_CONNECT_ERR = // TODO: Consider two different messages - literal("This server requires you to connect with Velocity or BungeeCord."); - @Unique private static final Object pcf$BG_CONFIG_ERR = - literal("This server requires the proxy to be configured for BungeeGuard forwarding."); - - @Inject(method = "beginLogin", cancellable = true, at = @At(value = "RETURN", - target = "Lnet/minecraft/network/Connection;setupInboundProtocol(Lnet/minecraft/network/ProtocolInfo;Lnet/minecraft/network/PacketListener;)V")) - // spotless:on - private void onBeginLogin( - final ClientIntentionPacket packet, final boolean transfer, final CallbackInfo ci) { - if (PCF.instance().forwarding().mode() != Mode.LEGACY - && PCF.instance().forwarding().mode() != Mode.BUNGEEGUARD) return; - - // Spigot Start - // TODO: Stick this in a packet listener and extract it there and add to the - // ConnectionBridgeLegacy - // Then replace the original serverAddress used for the regular login flow - // Do not forget Forge markers if present - final String[] split = packet.hostName().split("\00"); - PCF.logger.info( - "Received handshake with " - + split.length - + " parts: " - + String.join("\n ", split)); - if ((split.length < 3) || !(pcf$HOST_PATTERN.matcher(split[1]).matches())) { - this.pcf$disconnect(pcf$DIRECT_CONNECT_ERR); - return; - } - if ((split.length < 4) && PCF.instance().forwarding().mode() != Mode.BUNGEEGUARD) { - this.pcf$disconnect(pcf$BG_CONFIG_ERR); - return; - } - - final String originalAddress = split[1]; - final UUID uuid = pcf$fromStringLenient(split[2]); - PCF.logger.info( - "Player " + uuid + " is connecting with original address " + originalAddress); - - // Update the proxied address - final int port = ((ConnectionBridge) this.connection).bridge$address().getPort(); - final InetSocketAddress address = - new InetSocketAddress(InetAddresses.forString(originalAddress), port); - ((ConnectionBridge) this.connection).bridge$address(address); - - // Save the UUID - ((ConnectionBridgeLegacy) this.connection).bridge$spoofedUUID(uuid); - - // Save the properties if present - if (split.length == 4) { // TODO: Enforce if BungeeGuard forwarding - final String profileJSON = split[3]; - ((ConnectionBridgeLegacy) this.connection) - .bridge$spoofedProfile(pcf$gson.fromJson(profileJSON, Property[].class)); - } - // Spigot End - } - - @Unique public void pcf$disconnect(Object component) { - this.connection.send(new ClientboundLoginDisconnectPacket((Component) component)); - this.connection.disconnect((Component) component); - } - - @Unique private static UUID pcf$fromStringLenient(final String string) { - return UUID.fromString( - string.replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5")); - } - - // https://github.com/caunt/BungeeForge/blob/1.20.2/src/main/java/ua/caunt/bungeeforge/mixin/network/protocol/handshake/ClientIntentionPacket.java#L51-L54 - @Unique private static boolean pcf$isFmlMarker(Property property) { - return Objects.equals(property.name(), "extraData") - && property.value().startsWith("\u0001FORGE"); - } -} diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java index f67d72ce..3414ec7e 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java @@ -1,5 +1,7 @@ package org.adde0109.pcf.mixin.v26_1.forwarding.legacy; +import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.SPOOFED_PROFILE; +import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.SPOOFED_UUID; import static org.adde0109.pcf.forwarding.modern.ReflectionUtils.getProperties; import com.mojang.authlib.GameProfile; @@ -15,7 +17,7 @@ import net.minecraft.network.protocol.login.ServerboundHelloPacket; import net.minecraft.server.network.ServerLoginPacketListenerImpl; -import org.adde0109.pcf.forwarding.legacy.ConnectionBridgeLegacy; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.Final; @@ -47,8 +49,9 @@ public abstract class ServerLoginPacketListenerImplHelloMixin // spotless:on private void onHandleHello_20_M( final ServerboundHelloPacket packet, final @NonNull CallbackInfo ci) { - ConnectionBridgeLegacy conn = (ConnectionBridgeLegacy) this.connection; - if (conn.bridge$spoofedProfile() == null) { + final ConnectionBridge conn = (ConnectionBridge) this.connection; + + if (conn.bridge$channel().attr(SPOOFED_UUID).get() == null) { return; // TODO: Provide client-bound disconnect error } @@ -59,9 +62,11 @@ private void onHandleHello_20_M( // Spigot start @Unique protected GameProfile pcf$createOfflineProfile(String name) { + final ConnectionBridge conn = (ConnectionBridge) this.connection; + final UUID uuid; - if (((ConnectionBridgeLegacy) this.connection).bridge$spoofedUUID() != null) { - uuid = ((ConnectionBridgeLegacy) this.connection).bridge$spoofedUUID(); + if (conn.bridge$channel().attr(SPOOFED_UUID).get() != null) { + uuid = conn.bridge$channel().attr(SPOOFED_UUID).get(); } else { uuid = UUID.nameUUIDFromBytes( @@ -71,9 +76,8 @@ private void onHandleHello_20_M( // TODO: Add 1.21.9 support final GameProfile profile = new GameProfile(uuid, name); final PropertyMap propertiesMap = getProperties(profile); - if (((ConnectionBridgeLegacy) this.connection).bridge$spoofedProfile() != null) { - for (final Property property : - ((ConnectionBridgeLegacy) this.connection).bridge$spoofedProfile()) { + if (conn.bridge$channel().attr(SPOOFED_PROFILE).get() != null) { + for (final Property property : conn.bridge$channel().attr(SPOOFED_PROFILE).get()) { if (!pcf$PROP_PATTERN.matcher(property.name()).matches()) continue; propertiesMap.put(property.name(), property); } diff --git a/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json b/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json index af4961cd..ce16ba82 100644 --- a/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json +++ b/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json @@ -11,9 +11,6 @@ "v26_1.crossstich.ArgumentNodeStubMixin", "v26_1.crossstich.ArgumentTypeInfoMixin", "v26_1.forwarding.ConnectionMixin", - "v26_1.forwarding.legacy.ClientIntentionPacketMixin", - "v26_1.forwarding.legacy.ConnectionLegacyMixin", - "v26_1.forwarding.legacy.ServerHandshakePacketListenerImplMixin", "v26_1.forwarding.legacy.ServerLoginPacketListenerImplHelloMixin", "v26_1.forwarding.modern.ServerLoginPacketListenerImplHelloHybridMixin", "v26_1.forwarding.modern.ServerLoginPacketListenerImplHelloMixin", diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 82fc455c..873a7cda 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,6 +12,7 @@ unimined = "1.3.16-SNAPSHOT" annotations = { group = "org.jetbrains", name = "annotations", version = "26.0.2" } asm-tree = { group = "org.ow2.asm", name = "asm-tree", version = "6.2" } entrypoint-spoof = { group = "dev.neuralnexus", name = "entrypoint-spoof", version = "0.1.30" } +gson = { group = "com.google.code.gson", name = "gson", version = "2.13.2" } guava = { group = "com.google.guava", name = "guava", version = "33.3.1-jre" } jspecify = { group = "org.jspecify", name = "jspecify", version = "1.0.0" } mixin = { group = "org.spongepowered", name = "mixin", version = "0.8.5-SNAPSHOT" } From 8a2378194c1526a90101160f11c42eda33d4c782 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 07:01:08 -0600 Subject: [PATCH 35/71] Switch to using a Netty attribute for modern forwarding login message ids --- .../adde0109/pcf/forwarding/PacketDecoder.java | 15 ++++++++++++--- .../pcf/forwarding/modern/ModernForwarding.java | 16 ++++++++++------ .../modern/ServerLoginPacketListenerBridge.java | 4 ---- .../ServerLoginPacketListenerImplMixin.java | 12 ------------ .../ServerLoginPacketListenerImplMixin.java | 12 ------------ .../ServerLoginPacketListenerImplMixin.java | 12 ------------ .../ServerLoginPacketListenerImplMixin.java | 12 ------------ .../ServerLoginPacketListenerImplMixin.java | 13 ------------- 8 files changed, 22 insertions(+), 74 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 0e21ae7d..655dfac7 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -2,6 +2,7 @@ import static org.adde0109.pcf.forwarding.ConnectionBridge.HANDLER_PACKET; import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.handleClientIntentionPacket; +import static org.adde0109.pcf.forwarding.modern.ModernForwarding.LOGIN_MESSAGE_ID; import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleCustomQueryPacket; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; @@ -37,8 +38,9 @@ protected void decode( switch (connection.bridge$protocol()) { case null -> {} case HANDSHAKING -> { - if (PCF.instance().forwarding().mode() != Mode.LEGACY - && PCF.instance().forwarding().mode() != Mode.BUNGEEGUARD) { + if (!PCF.instance().forwarding().enabled() + || (PCF.instance().forwarding().mode() != Mode.LEGACY + && PCF.instance().forwarding().mode() != Mode.BUNGEEGUARD)) { out.add(msg.retain()); return; } @@ -74,6 +76,12 @@ protected void decode( } } case LOGIN -> { + if (!PCF.instance().forwarding().enabled() + || !PCF.instance().forwarding().mode().equals(Mode.MODERN)) { + out.add(msg.retain()); + return; + } + if (!(connection.bridge$getPacketListener() instanceof ServerLoginPacketListenerBridge slpl)) { out.add(msg.retain()); @@ -96,7 +104,8 @@ protected void decode( ServerboundCustomQueryAnswerPacket.STREAM_CODEC.decode(data); // Check if the packet should be handled - if (packet.transactionId() != slpl.bridge$velocityLoginMessageId()) { + if (packet.transactionId() + != connection.bridge$channel().attr(LOGIN_MESSAGE_ID).get()) { msg.readerIndex(readerIndex); break; } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index 27a5366f..9bda8de7 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -20,9 +20,11 @@ import dev.neuralnexus.taterapi.network.protocol.login.custom.CustomQueryAnswerPayload; import io.netty.handler.codec.DecoderException; +import io.netty.util.AttributeKey; import io.netty.util.concurrent.Future; import org.adde0109.pcf.PCF; +import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.Mode; import org.jetbrains.annotations.ApiStatus; import org.jspecify.annotations.NonNull; @@ -51,6 +53,9 @@ * 1.20.x */ public final class ModernForwarding { + public static final AttributeKey LOGIN_MESSAGE_ID = + AttributeKey.valueOf("pcf-login-message-id"); + private static final Object REJECTED_PROXY_ERR = literal("Unapproved proxy host."); /** @@ -76,10 +81,11 @@ public static void handleHello( || !PCF.instance().forwarding().mode().equals(Mode.MODERN)) { return; } + final ConnectionBridge connection = slpl.bridge$connection(); final List approved = PCF.instance().forwarding().approvedProxyHosts(); if (!approved.isEmpty()) { - final InetSocketAddress address = slpl.bridge$connection().bridge$address(); + final InetSocketAddress address = connection.bridge$address(); final String host = address.getHostString(); final String ip = address.getAddress().getHostAddress(); if (!approved.contains(host) && !approved.contains(ip)) { @@ -95,11 +101,9 @@ public static void handleHello( } } - slpl.bridge$setVelocityLoginMessageId(ThreadLocalRandom.current().nextInt()); - slpl.bridge$connection() - .bridge$send( - new ClientboundCustomQueryPacket( - slpl.bridge$velocityLoginMessageId(), PLAYER_INFO_PAYLOAD)); + final int messageId = ThreadLocalRandom.current().nextInt(); + connection.bridge$channel().attr(LOGIN_MESSAGE_ID).set(messageId); + connection.bridge$send(new ClientboundCustomQueryPacket(messageId, PLAYER_INFO_PAYLOAD)); PCF.logger.debug("Sent Forward Request"); ci.cancel(); } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ServerLoginPacketListenerBridge.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ServerLoginPacketListenerBridge.java index 0686d116..f9af4a60 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ServerLoginPacketListenerBridge.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ServerLoginPacketListenerBridge.java @@ -11,10 +11,6 @@ import java.util.UUID; public interface ServerLoginPacketListenerBridge { - int bridge$velocityLoginMessageId(); - - void bridge$setVelocityLoginMessageId(final int id); - @NonNull ConnectionBridge bridge$connection(); void bridge$disconnect(final @NonNull Object reason); diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplMixin.java index 840ec438..2dde090a 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplMixin.java @@ -18,7 +18,6 @@ import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; @AConstraint(mappings = Mappings.MOJANG, version = @Versions(min = MinecraftVersion.V20_2)) @Mixin(ServerLoginPacketListenerImpl.class) @@ -30,19 +29,8 @@ public abstract class ServerLoginPacketListenerImplMixin @Shadow public abstract void shadow$disconnect(Component details); @Shadow protected abstract void shadow$startClientVerification(GameProfile profile); @Shadow private GameProfile authenticatedProfile; - @Unique private int pcf$velocityLoginMessageId = -1; // spotless:on - @Override - public int bridge$velocityLoginMessageId() { - return this.pcf$velocityLoginMessageId; - } - - @Override - public void bridge$setVelocityLoginMessageId(final int id) { - this.pcf$velocityLoginMessageId = id; - } - @Override public @NonNull ConnectionBridge bridge$connection() { return (ConnectionBridge) this.connection; diff --git a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java index 6a6cc92e..e05d71c9 100644 --- a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java @@ -18,7 +18,6 @@ import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; @AConstraint( mappings = Mappings.SEARGE, @@ -30,19 +29,8 @@ public abstract class ServerLoginPacketListenerImplMixin @Shadow @Final public NetworkManager networkManager; @Shadow private GameProfile loginGameProfile; @Shadow private NetHandlerLoginServer.LoginState currentLoginState; - @Unique private int pcf$velocityLoginMessageId = -1; // spotless:on - @Override - public int bridge$velocityLoginMessageId() { - return this.pcf$velocityLoginMessageId; - } - - @Override - public void bridge$setVelocityLoginMessageId(final int id) { - this.pcf$velocityLoginMessageId = id; - } - @Override public @NonNull ConnectionBridge bridge$connection() { return (ConnectionBridge) this.networkManager; diff --git a/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java index 4a746826..ce099e55 100644 --- a/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java @@ -22,7 +22,6 @@ import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -39,7 +38,6 @@ public abstract class ServerLoginPacketListenerImplMixin @Shadow private NetHandlerLoginServer.LoginState currentLoginState; @Shadow @Final private static Logger LOGGER; @Shadow public abstract void shadow$disconnect(ITextComponent reason); - @Unique private int pcf$velocityLoginMessageId = -1; // spotless:on // spotless:off @@ -50,16 +48,6 @@ private void onHandleHello(final @NonNull CallbackInfo ci) { handleHello(this, ci); } - @Override - public int bridge$velocityLoginMessageId() { - return this.pcf$velocityLoginMessageId; - } - - @Override - public void bridge$setVelocityLoginMessageId(final int id) { - this.pcf$velocityLoginMessageId = id; - } - @Override public @NonNull ConnectionBridge bridge$connection() { return (ConnectionBridge) this.networkManager; diff --git a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java index 03178fc8..2d979d9c 100644 --- a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java @@ -24,7 +24,6 @@ import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -41,7 +40,6 @@ public abstract class ServerLoginPacketListenerImplMixin @Shadow private ServerLoginPacketListenerImpl.State state; @Shadow @Final private static Logger LOGGER; @Shadow public abstract void shadow$disconnect(Component reason); - @Unique private int pcf$velocityLoginMessageId = -1; // spotless:on // spotless:off @@ -67,16 +65,6 @@ private void onHandleHelloHybrid(final @NonNull CallbackInfo ci) { handleHello(this, ci); } - @Override - public int bridge$velocityLoginMessageId() { - return this.pcf$velocityLoginMessageId; - } - - @Override - public void bridge$setVelocityLoginMessageId(final int id) { - this.pcf$velocityLoginMessageId = id; - } - @Override public @NonNull ConnectionBridge bridge$connection() { return (ConnectionBridge) this.connection; diff --git a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java index 6772624c..3e290c3c 100644 --- a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java @@ -18,7 +18,6 @@ import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; @AConstraint(mappings = Mappings.SEARGE, version = @Versions(min = MinecraftVersion.V17)) @Mixin(ServerLoginPacketListenerImpl.class) @@ -33,20 +32,8 @@ public abstract class ServerLoginPacketListenerImplMixin @AConstraint(version = @Versions(min = MinecraftVersion.V20_2)) @Shadow private @Nullable GameProfile authenticatedProfile; - - @Unique private int pcf$velocityLoginMessageId = -1; // spotless:on - @Override - public int bridge$velocityLoginMessageId() { - return this.pcf$velocityLoginMessageId; - } - - @Override - public void bridge$setVelocityLoginMessageId(final int id) { - this.pcf$velocityLoginMessageId = id; - } - @Override public @NonNull ConnectionBridge bridge$connection() { return (ConnectionBridge) this.connection; From ec80fba2bb8ad9f171480e6d520414c3f322006b Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 07:20:08 -0600 Subject: [PATCH 36/71] Move SLPL impl mixins into the common forwarding package --- .../pcf/forwarding/PacketDecoder.java | 1 - .../ServerLoginPacketListenerBridge.java | 3 +- .../prelogin/ArclightPreLogin.java | 2 +- .../prelogin/MohistPreLogin.java | 2 +- .../prelogin/SpigotPreLogin.java | 2 +- .../prelogin/SpongePreLogin.java | 2 +- .../forwarding/modern/ModernForwarding.java | 1 + .../ServerLoginPacketListenerImplMixin.java | 4 +- ...rverLoginPacketListenerImplHelloMixin.java | 2 +- ...ginPacketListenerImplHelloHybridMixin.java | 2 +- ...rverLoginPacketListenerImplHelloMixin.java | 2 +- .../src/main/resources/pcf.mixins.v26_1.json | 4 +- .../ServerLoginPacketListenerImplMixin.java | 4 +- ...rverLoginPacketListenerImplHelloMixin.java | 2 +- .../resources/pcf.mixins.v12_2.forge.json | 6 +- .../{modern => }/MessageSerializerMixin.java | 2 +- .../ServerLoginPacketListenerImplMixin.java | 4 +- .../resources/pcf.mixins.v7_10.forge.json | 4 +- .../ServerLoginPacketListenerImplMixin.java | 4 +- .../resources/pcf.mixins.v13_2.forge.json | 2 +- .../ServerLoginPacketListenerImplMixin.java | 67 +++++++++++++++++++ ...verLoginPacketListenerImplHelloMixin.java} | 49 +------------- .../resources/pcf.mixins.v16_5.forge.json | 3 +- ...verLoginPacketListenerImplLoggerMixin.java | 2 +- ...tenerImplStartClientVerificationMixin.java | 4 +- ...rverLoginPacketListenerImplKeyV1Mixin.java | 2 +- ...rverLoginPacketListenerImplKeyV2Mixin.java | 2 +- .../resources/pcf.mixins.v19_2.forge.json | 2 +- ...verLoginPacketListenerImplLoggerMixin.java | 4 +- .../ServerLoginPacketListenerImplMixin.java | 4 +- .../resources/pcf.mixins.v20_4.forge.json | 4 +- 31 files changed, 110 insertions(+), 88 deletions(-) rename common/src/main/java/org/adde0109/pcf/forwarding/{modern => }/ServerLoginPacketListenerBridge.java (92%) rename deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/{modern => }/ServerLoginPacketListenerImplMixin.java (94%) rename legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/{modern => }/ServerLoginPacketListenerImplMixin.java (95%) rename legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/{modern => }/MessageSerializerMixin.java (93%) rename legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/{modern => }/ServerLoginPacketListenerImplMixin.java (91%) rename modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/{modern => }/ServerLoginPacketListenerImplMixin.java (95%) create mode 100644 modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ServerLoginPacketListenerImplMixin.java rename modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/{ServerLoginPacketListenerImplMixin.java => ServerLoginPacketListenerImplHelloMixin.java} (58%) rename modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/{modern => }/ServerLoginPacketListenerImplStartClientVerificationMixin.java (90%) rename modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/{modern => }/ServerLoginPacketListenerImplLoggerMixin.java (88%) rename modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/{modern => }/ServerLoginPacketListenerImplMixin.java (93%) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 655dfac7..8bdac86f 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -14,7 +14,6 @@ import io.netty.handler.codec.MessageToMessageDecoder; import org.adde0109.pcf.PCF; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import java.util.List; diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ServerLoginPacketListenerBridge.java b/common/src/main/java/org/adde0109/pcf/forwarding/ServerLoginPacketListenerBridge.java similarity index 92% rename from common/src/main/java/org/adde0109/pcf/forwarding/modern/ServerLoginPacketListenerBridge.java rename to common/src/main/java/org/adde0109/pcf/forwarding/ServerLoginPacketListenerBridge.java index f9af4a60..6eb1677c 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ServerLoginPacketListenerBridge.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/ServerLoginPacketListenerBridge.java @@ -1,10 +1,9 @@ -package org.adde0109.pcf.forwarding.modern; +package org.adde0109.pcf.forwarding; import com.mojang.authlib.GameProfile; import dev.neuralnexus.taterapi.mc.world.entity.player.ProfilePublicKey; -import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/ArclightPreLogin.java b/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/ArclightPreLogin.java index f2d8c4c8..97522e27 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/ArclightPreLogin.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/ArclightPreLogin.java @@ -2,7 +2,7 @@ import com.mojang.authlib.GameProfile; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import java.lang.invoke.MethodHandle; diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/MohistPreLogin.java b/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/MohistPreLogin.java index 230a7eaa..f225417a 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/MohistPreLogin.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/MohistPreLogin.java @@ -2,7 +2,7 @@ import com.mojang.authlib.GameProfile; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import java.lang.invoke.MethodHandle; diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/SpigotPreLogin.java b/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/SpigotPreLogin.java index 789b374c..dd427260 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/SpigotPreLogin.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/SpigotPreLogin.java @@ -2,7 +2,7 @@ import com.mojang.authlib.GameProfile; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import java.lang.invoke.MethodHandle; diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/SpongePreLogin.java b/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/SpongePreLogin.java index 6f2bec3a..f16ac0c7 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/SpongePreLogin.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/compatibility/prelogin/SpongePreLogin.java @@ -1,6 +1,6 @@ package org.adde0109.pcf.forwarding.compatibility.prelogin; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jetbrains.annotations.NotNull; import java.lang.invoke.MethodHandle; diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index 9bda8de7..3ecf92e2 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -26,6 +26,7 @@ import org.adde0109.pcf.PCF; import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.Mode; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jetbrains.annotations.ApiStatus; import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ServerLoginPacketListenerImplMixin.java similarity index 94% rename from deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplMixin.java rename to deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ServerLoginPacketListenerImplMixin.java index 2dde090a..46338c28 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ServerLoginPacketListenerImplMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v26_1.forwarding.modern; +package org.adde0109.pcf.mixin.v26_1.forwarding; import com.mojang.authlib.GameProfile; @@ -12,7 +12,7 @@ import net.minecraft.server.network.ServerLoginPacketListenerImpl; import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import org.slf4j.Logger; import org.spongepowered.asm.mixin.Final; diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java index 3414ec7e..86c6dbc6 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java @@ -18,7 +18,7 @@ import net.minecraft.server.network.ServerLoginPacketListenerImpl; import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloHybridMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloHybridMixin.java index b2a682bf..a0b0fc3d 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloHybridMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloHybridMixin.java @@ -10,7 +10,7 @@ import net.minecraft.server.network.ServerLoginPacketListenerImpl; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.apache.commons.lang3.Validate; import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.Mixin; diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java index 77b9dc98..0e19a4ff 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java @@ -9,7 +9,7 @@ import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; import dev.neuralnexus.taterapi.meta.enums.Platform; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Mixin; diff --git a/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json b/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json index ce16ba82..9a4c345a 100644 --- a/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json +++ b/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json @@ -11,9 +11,9 @@ "v26_1.crossstich.ArgumentNodeStubMixin", "v26_1.crossstich.ArgumentTypeInfoMixin", "v26_1.forwarding.ConnectionMixin", + "v26_1.forwarding.ServerLoginPacketListenerImplMixin", "v26_1.forwarding.legacy.ServerLoginPacketListenerImplHelloMixin", "v26_1.forwarding.modern.ServerLoginPacketListenerImplHelloHybridMixin", - "v26_1.forwarding.modern.ServerLoginPacketListenerImplHelloMixin", - "v26_1.forwarding.modern.ServerLoginPacketListenerImplMixin" + "v26_1.forwarding.modern.ServerLoginPacketListenerImplHelloMixin" ] } diff --git a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ServerLoginPacketListenerImplMixin.java similarity index 95% rename from legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java rename to legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ServerLoginPacketListenerImplMixin.java index e05d71c9..3a82fe05 100644 --- a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ServerLoginPacketListenerImplMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v12_2.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v12_2.forge.forwarding; import com.mojang.authlib.GameProfile; @@ -12,7 +12,7 @@ import net.minecraft.util.text.ITextComponent; import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.apache.logging.log4j.Logger; import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.Final; diff --git a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java index 232dbb0a..568299df 100644 --- a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java +++ b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java @@ -9,7 +9,7 @@ import net.minecraft.server.network.NetHandlerLoginServer; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Mixin; diff --git a/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json b/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json index ee3cc450..e85722f5 100644 --- a/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json +++ b/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json @@ -9,8 +9,8 @@ "package": "org.adde0109.pcf.mixin", "server": [ "v12_2.forge.forwarding.ConnectionMixin", - "v12_2.forge.forwarding.modern.ServerLoginPacketListenerImplHelloMixin", - "v12_2.forge.forwarding.modern.ServerLoginPacketListenerImplMixin", - "v12_2.forge.forwarding.modern.ServerLoginPacketListenerImplMixin$SLPLIMixin_12" + "v12_2.forge.forwarding.ServerLoginPacketListenerImplMixin", + "v12_2.forge.forwarding.ServerLoginPacketListenerImplMixin$SLPLIMixin_12", + "v12_2.forge.forwarding.modern.ServerLoginPacketListenerImplHelloMixin" ] } diff --git a/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/modern/MessageSerializerMixin.java b/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/MessageSerializerMixin.java similarity index 93% rename from legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/modern/MessageSerializerMixin.java rename to legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/MessageSerializerMixin.java index 0b2597e4..54068f17 100644 --- a/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/modern/MessageSerializerMixin.java +++ b/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/MessageSerializerMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v7_10.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v7_10.forge.forwarding; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; diff --git a/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ServerLoginPacketListenerImplMixin.java similarity index 91% rename from legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java rename to legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ServerLoginPacketListenerImplMixin.java index 536c7612..9702fc88 100644 --- a/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ServerLoginPacketListenerImplMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v7_10.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v7_10.forge.forwarding; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; @@ -8,7 +8,7 @@ import net.minecraft.server.network.NetHandlerLoginServer; import net.minecraft.util.IChatComponent; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.apache.logging.log4j.Logger; import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.Final; diff --git a/legacy/v7_10/src/forge/resources/pcf.mixins.v7_10.forge.json b/legacy/v7_10/src/forge/resources/pcf.mixins.v7_10.forge.json index 8d99e8c9..9a947598 100644 --- a/legacy/v7_10/src/forge/resources/pcf.mixins.v7_10.forge.json +++ b/legacy/v7_10/src/forge/resources/pcf.mixins.v7_10.forge.json @@ -8,7 +8,7 @@ "plugin": "org.adde0109.pcf.mixin.plugin.PCFMixinPlugin", "package": "org.adde0109.pcf.mixin", "server": [ - "v7_10.forge.forwarding.modern.MessageSerializerMixin", - "v7_10.forge.forwarding.modern.ServerLoginPacketListenerImplMixin" + "v7_10.forge.forwarding.MessageSerializerMixin", + "v7_10.forge.forwarding.ServerLoginPacketListenerImplMixin" ] } diff --git a/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ServerLoginPacketListenerImplMixin.java similarity index 95% rename from modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java rename to modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ServerLoginPacketListenerImplMixin.java index ce099e55..21bdd1af 100644 --- a/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ServerLoginPacketListenerImplMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v13_2.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v13_2.forge.forwarding; import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleHello; @@ -14,7 +14,7 @@ import net.minecraft.util.text.ITextComponent; import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.apache.logging.log4j.Logger; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; diff --git a/modern/v13_2/src/forge/resources/pcf.mixins.v13_2.forge.json b/modern/v13_2/src/forge/resources/pcf.mixins.v13_2.forge.json index dbf496cb..ecf6f0a0 100644 --- a/modern/v13_2/src/forge/resources/pcf.mixins.v13_2.forge.json +++ b/modern/v13_2/src/forge/resources/pcf.mixins.v13_2.forge.json @@ -9,6 +9,6 @@ "package": "org.adde0109.pcf.mixin", "server": [ "v13_2.forge.crossstitch.CommandsPacketMixin", - "v13_2.forge.forwarding.modern.ServerLoginPacketListenerImplMixin" + "v13_2.forge.forwarding.ServerLoginPacketListenerImplMixin" ] } diff --git a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ServerLoginPacketListenerImplMixin.java b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ServerLoginPacketListenerImplMixin.java new file mode 100644 index 00000000..98c1d7e9 --- /dev/null +++ b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ServerLoginPacketListenerImplMixin.java @@ -0,0 +1,67 @@ +package org.adde0109.pcf.mixin.v16_5.forge.forwarding; + +import com.mojang.authlib.GameProfile; + +import dev.neuralnexus.taterapi.meta.Mappings; +import dev.neuralnexus.taterapi.meta.anno.AConstraint; +import dev.neuralnexus.taterapi.meta.anno.Versions; +import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; + +import net.minecraft.network.Connection; +import net.minecraft.network.chat.Component; +import net.minecraft.server.network.ServerLoginPacketListenerImpl; + +import org.adde0109.pcf.forwarding.ConnectionBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; +import org.apache.logging.log4j.Logger; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@AConstraint( + mappings = Mappings.SEARGE, + version = @Versions(min = MinecraftVersion.V14, max = MinecraftVersion.V16_5)) +@Mixin(ServerLoginPacketListenerImpl.class) +public abstract class ServerLoginPacketListenerImplMixin + implements ServerLoginPacketListenerBridge { + // spotless:off + @Shadow @Final public Connection connection; + @Shadow @Nullable private GameProfile gameProfile; + @Shadow private ServerLoginPacketListenerImpl.State state; + @Shadow @Final private static Logger LOGGER; + @Shadow public abstract void shadow$disconnect(Component reason); + // spotless:on + + @Override + public @NonNull ConnectionBridge bridge$connection() { + return (ConnectionBridge) this.connection; + } + + @Override + public void bridge$disconnect(final @NonNull Object reason) { + this.shadow$disconnect((Component) reason); + } + + @Override + public void bridge$setGameProfile(final @NonNull GameProfile profile) { + this.gameProfile = profile; + } + + @Override + public void bridge$startClientVerification(final @NonNull GameProfile profile) { + this.gameProfile = profile; + this.state = ServerLoginPacketListenerImpl.State.NEGOTIATING; + } + + @Override + public void bridge$logger_info(final @NonNull String text, final Object... params) { + LOGGER.info(text, params); + } + + @Override + public void bridge$logger_error(final @NonNull String text, final Object... params) { + LOGGER.error(text, params); + } +} diff --git a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java similarity index 58% rename from modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java rename to modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java index 2d979d9c..172f9e6c 100644 --- a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java @@ -2,26 +2,18 @@ import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleHello; -import com.mojang.authlib.GameProfile; - import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; import dev.neuralnexus.taterapi.meta.anno.Versions; import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; import dev.neuralnexus.taterapi.meta.enums.Platform; -import net.minecraft.network.Connection; -import net.minecraft.network.chat.Component; import net.minecraft.server.network.ServerLoginPacketListenerImpl; -import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.apache.commons.lang3.Validate; -import org.apache.logging.log4j.Logger; import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; import org.objectweb.asm.Opcodes; -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; @@ -32,17 +24,11 @@ mappings = Mappings.SEARGE, version = @Versions(min = MinecraftVersion.V14, max = MinecraftVersion.V16_5)) @Mixin(ServerLoginPacketListenerImpl.class) -public abstract class ServerLoginPacketListenerImplMixin +public abstract class ServerLoginPacketListenerImplHelloMixin implements ServerLoginPacketListenerBridge { // spotless:off - @Shadow @Final public Connection connection; - @Shadow @Nullable private GameProfile gameProfile; @Shadow private ServerLoginPacketListenerImpl.State state; - @Shadow @Final private static Logger LOGGER; - @Shadow public abstract void shadow$disconnect(Component reason); - // spotless:on - // spotless:off @AConstraint( platform = {Platform.ARCLIGHT, Platform.CATSERVER, Platform.MAGMA, Platform.MOHIST}, invert = true) @Inject(method = "handleHello", cancellable = true, at = @At(value = "FIELD", opcode = Opcodes.PUTFIELD, ordinal = 1, @@ -64,35 +50,4 @@ private void onHandleHelloHybrid(final @NonNull CallbackInfo ci) { this.state == ServerLoginPacketListenerImpl.State.HELLO, "Unexpected hello packet"); handleHello(this, ci); } - - @Override - public @NonNull ConnectionBridge bridge$connection() { - return (ConnectionBridge) this.connection; - } - - @Override - public void bridge$disconnect(final @NonNull Object reason) { - this.shadow$disconnect((Component) reason); - } - - @Override - public void bridge$setGameProfile(final @NonNull GameProfile profile) { - this.gameProfile = profile; - } - - @Override - public void bridge$startClientVerification(final @NonNull GameProfile profile) { - this.gameProfile = profile; - this.state = ServerLoginPacketListenerImpl.State.NEGOTIATING; - } - - @Override - public void bridge$logger_info(final @NonNull String text, final Object... params) { - LOGGER.info(text, params); - } - - @Override - public void bridge$logger_error(final @NonNull String text, final Object... params) { - LOGGER.error(text, params); - } } diff --git a/modern/v16_5/src/forge/resources/pcf.mixins.v16_5.forge.json b/modern/v16_5/src/forge/resources/pcf.mixins.v16_5.forge.json index 1b3365fe..22288958 100644 --- a/modern/v16_5/src/forge/resources/pcf.mixins.v16_5.forge.json +++ b/modern/v16_5/src/forge/resources/pcf.mixins.v16_5.forge.json @@ -12,6 +12,7 @@ "v16_5.forge.crossstitch.ArgumentTypesEntryMixin", "v16_5.forge.crossstitch.CommandsPacketMixin", "v16_5.forge.forwarding.ConnectionMixin", - "v16_5.forge.forwarding.modern.ServerLoginPacketListenerImplMixin" + "v16_5.forge.forwarding.ServerLoginPacketListenerImplMixin", + "v16_5.forge.forwarding.modern.ServerLoginPacketListenerImplHelloMixin" ] } diff --git a/modern/v17_1/src/forge/java/org/adde0109/pcf/mixin/v17_1/forge/forwarding/modern/ServerLoginPacketListenerImplLoggerMixin.java b/modern/v17_1/src/forge/java/org/adde0109/pcf/mixin/v17_1/forge/forwarding/modern/ServerLoginPacketListenerImplLoggerMixin.java index 77ca441c..a3c595dd 100644 --- a/modern/v17_1/src/forge/java/org/adde0109/pcf/mixin/v17_1/forge/forwarding/modern/ServerLoginPacketListenerImplLoggerMixin.java +++ b/modern/v17_1/src/forge/java/org/adde0109/pcf/mixin/v17_1/forge/forwarding/modern/ServerLoginPacketListenerImplLoggerMixin.java @@ -7,7 +7,7 @@ import net.minecraft.server.network.ServerLoginPacketListenerImpl; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.apache.logging.log4j.Logger; import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.Final; diff --git a/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ServerLoginPacketListenerImplStartClientVerificationMixin.java b/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/ServerLoginPacketListenerImplStartClientVerificationMixin.java similarity index 90% rename from modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ServerLoginPacketListenerImplStartClientVerificationMixin.java rename to modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/ServerLoginPacketListenerImplStartClientVerificationMixin.java index b8aa4ad7..b00b5c3a 100644 --- a/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ServerLoginPacketListenerImplStartClientVerificationMixin.java +++ b/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/ServerLoginPacketListenerImplStartClientVerificationMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v19_2.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v19_2.forge.forwarding; import com.mojang.authlib.GameProfile; @@ -9,7 +9,7 @@ import net.minecraft.server.network.ServerLoginPacketListenerImpl; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; diff --git a/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ServerLoginPacketListenerImplKeyV1Mixin.java b/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ServerLoginPacketListenerImplKeyV1Mixin.java index 088db0f2..3652bc8b 100644 --- a/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ServerLoginPacketListenerImplKeyV1Mixin.java +++ b/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ServerLoginPacketListenerImplKeyV1Mixin.java @@ -10,7 +10,7 @@ import net.minecraft.server.network.ServerLoginPacketListenerImpl; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; diff --git a/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ServerLoginPacketListenerImplKeyV2Mixin.java b/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ServerLoginPacketListenerImplKeyV2Mixin.java index 24b08bfc..13f67cdd 100644 --- a/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ServerLoginPacketListenerImplKeyV2Mixin.java +++ b/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/modern/ServerLoginPacketListenerImplKeyV2Mixin.java @@ -13,7 +13,7 @@ import net.minecraft.server.network.ServerLoginPacketListenerImpl; import net.minecraft.util.SignatureValidator; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; diff --git a/modern/v19_2/src/forge/resources/pcf.mixins.v19_2.forge.json b/modern/v19_2/src/forge/resources/pcf.mixins.v19_2.forge.json index 133aed07..4bbd6f8a 100644 --- a/modern/v19_2/src/forge/resources/pcf.mixins.v19_2.forge.json +++ b/modern/v19_2/src/forge/resources/pcf.mixins.v19_2.forge.json @@ -9,11 +9,11 @@ "package": "org.adde0109.pcf.mixin", "server": [ "v19_2.forge.forwarding.ConnectionMixin", + "v19_2.forge.forwarding.ServerLoginPacketListenerImplStartClientVerificationMixin", "v19_2.forge.forwarding.modern.LastSeenMessagesValidatorMixin", "v19_2.forge.forwarding.modern.PlayerChatMessageMixin", "v19_2.forge.forwarding.modern.ServerLoginPacketListenerImplKeyV1Mixin", "v19_2.forge.forwarding.modern.ServerLoginPacketListenerImplKeyV2Mixin", - "v19_2.forge.forwarding.modern.ServerLoginPacketListenerImplStartClientVerificationMixin", "v19_2.forge.forwarding.modern.SignedMessageChainMixin" ] } diff --git a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplLoggerMixin.java b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ServerLoginPacketListenerImplLoggerMixin.java similarity index 88% rename from modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplLoggerMixin.java rename to modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ServerLoginPacketListenerImplLoggerMixin.java index b62f2076..3cf5a308 100644 --- a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplLoggerMixin.java +++ b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ServerLoginPacketListenerImplLoggerMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v20_4.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v20_4.forge.forwarding; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; @@ -7,7 +7,7 @@ import net.minecraft.server.network.ServerLoginPacketListenerImpl; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import org.slf4j.Logger; import org.spongepowered.asm.mixin.Final; diff --git a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ServerLoginPacketListenerImplMixin.java similarity index 93% rename from modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java rename to modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ServerLoginPacketListenerImplMixin.java index 3e290c3c..7c4986e1 100644 --- a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/modern/ServerLoginPacketListenerImplMixin.java +++ b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ServerLoginPacketListenerImplMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v20_4.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v20_4.forge.forwarding; import com.mojang.authlib.GameProfile; @@ -12,7 +12,7 @@ import net.minecraft.server.network.ServerLoginPacketListenerImpl; import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.adde0109.pcf.forwarding.modern.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.Final; diff --git a/modern/v20_4/src/forge/resources/pcf.mixins.v20_4.forge.json b/modern/v20_4/src/forge/resources/pcf.mixins.v20_4.forge.json index b404d10e..ab27487d 100644 --- a/modern/v20_4/src/forge/resources/pcf.mixins.v20_4.forge.json +++ b/modern/v20_4/src/forge/resources/pcf.mixins.v20_4.forge.json @@ -11,7 +11,7 @@ "v20_4.forge.crossstitch.ArgumentNodeStubMixin", "v20_4.forge.crossstitch.ArgumentTypeInfoMixin", "v20_4.forge.forwarding.ConnectionMixin", - "v20_4.forge.forwarding.modern.ServerLoginPacketListenerImplLoggerMixin", - "v20_4.forge.forwarding.modern.ServerLoginPacketListenerImplMixin" + "v20_4.forge.forwarding.ServerLoginPacketListenerImplLoggerMixin", + "v20_4.forge.forwarding.ServerLoginPacketListenerImplMixin" ] } From a47be7be5dc5a3073ec2030477b492fc50231b6b Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 07:37:11 -0600 Subject: [PATCH 37/71] Pulled profile parsing and util methods into LegacyForwarding --- .../{modern => }/ReflectionUtils.java | 4 +- .../forwarding/legacy/LegacyForwarding.java | 42 ++++++++++++++++ .../forwarding/modern/ModernForwarding.java | 2 +- .../pcf/forwarding/modern/VelocityProxy.java | 2 +- ...rverLoginPacketListenerImplHelloMixin.java | 49 ++----------------- 5 files changed, 49 insertions(+), 50 deletions(-) rename common/src/main/java/org/adde0109/pcf/forwarding/{modern => }/ReflectionUtils.java (97%) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ReflectionUtils.java b/common/src/main/java/org/adde0109/pcf/forwarding/ReflectionUtils.java similarity index 97% rename from common/src/main/java/org/adde0109/pcf/forwarding/modern/ReflectionUtils.java rename to common/src/main/java/org/adde0109/pcf/forwarding/ReflectionUtils.java index 7618448f..9a4cf828 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ReflectionUtils.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/ReflectionUtils.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.forwarding.modern; +package org.adde0109.pcf.forwarding; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.PropertyMap; @@ -77,7 +77,7 @@ private ReflectionUtils() {} ENFORCE_SECURE_PROFILE = enforceSecureProfileHandle; } - static boolean enforceSecureProfile() { + public static boolean enforceSecureProfile() { if (ENFORCE_SECURE_PROFILE == null) { return false; } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java index 40ad081d..2a0062d7 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java @@ -2,12 +2,19 @@ import static dev.neuralnexus.taterapi.network.chat.Component.literal; +import static org.adde0109.pcf.forwarding.ReflectionUtils.getProperties; + +import com.google.common.collect.ImmutableMultimap; import com.google.common.net.InetAddresses; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; +import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; +import dev.neuralnexus.taterapi.meta.Constraint; +import dev.neuralnexus.taterapi.meta.MinecraftVersions; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; import dev.neuralnexus.taterapi.network.protocol.handshake.ClientIntent; @@ -45,6 +52,7 @@ public final class LegacyForwarding { literal("This server requires you to connect with Velocity or BungeeCord."); private static final Object BG_CONFIG_ERR = literal("This server requires the proxy to be configured for BungeeGuard forwarding."); + private static final Object PLAYER_INFO_ERR = literal("Unable to verify player details."); // https://hub.spigotmc.org/stash/projects/SPIGOT/repos/spigot/browse/CraftBukkit-Patches/0024-BungeeCord-Support.patch // https://github.com/caunt/BungeeForge/blob/1.20.2/src/main/java/ua/caunt/bungeeforge/mixin/network/protocol/handshake/ClientIntentionPacket.java#L51-L54 @@ -120,4 +128,38 @@ private static boolean isFmlMarker(final @NonNull Property property) { return Objects.equals(property.name(), "extraData") && property.value().startsWith("\u0001FORGE"); } + + private static final Pattern PROP_PATTERN = Pattern.compile("\\w{0,16}"); + + public static GameProfile createProfile( + final @NonNull ConnectionBridge conn, final @NonNull String name) { + final UUID uuid; + if (conn.bridge$channel().attr(SPOOFED_UUID).get() != null) { + uuid = conn.bridge$channel().attr(SPOOFED_UUID).get(); + } else { + throw new ThrowingComponent(PLAYER_INFO_ERR); + } + + final Collection properties = conn.bridge$channel().attr(SPOOFED_PROFILE).get(); + if (properties == null) { + return new GameProfile(uuid, name); + // com.mojang:authlib:7.0.0 or newer + } else if (Constraint.noLessThan(MinecraftVersions.V21_9).result()) { + final ImmutableMultimap.Builder propertiesBuilder = + ImmutableMultimap.builder(); + for (final Property property : properties) { + if (!PROP_PATTERN.matcher(property.name()).matches()) continue; + propertiesBuilder.put(property.name(), property); + } + return new GameProfile(uuid, name, new PropertyMap(propertiesBuilder.build())); + } else { + final GameProfile profile = new GameProfile(uuid, name); + final PropertyMap propertiesMap = getProperties(profile); + for (final Property property : properties) { + if (!PROP_PATTERN.matcher(property.name()).matches()) continue; + propertiesMap.put(property.name(), property); + } + return profile; + } + } } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index 3ecf92e2..1a2fe090 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -3,7 +3,7 @@ import static dev.neuralnexus.taterapi.network.chat.Component.literal; import static dev.neuralnexus.taterapi.network.chat.Component.translatable; -import static org.adde0109.pcf.forwarding.modern.ReflectionUtils.enforceSecureProfile; +import static org.adde0109.pcf.forwarding.ReflectionUtils.enforceSecureProfile; import static org.adde0109.pcf.forwarding.modern.VelocityProxy.MODERN_MAX_VERSION; import static org.adde0109.pcf.forwarding.modern.VelocityProxy.PLAYER_INFO_PAYLOAD; import static org.adde0109.pcf.forwarding.modern.VelocityProxy.checkIntegrity; diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/VelocityProxy.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/VelocityProxy.java index b5f8be1a..b82ce9d9 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/VelocityProxy.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/VelocityProxy.java @@ -2,7 +2,7 @@ import static dev.neuralnexus.taterapi.resources.Identifier.identifier; -import static org.adde0109.pcf.forwarding.modern.ReflectionUtils.getProperties; +import static org.adde0109.pcf.forwarding.ReflectionUtils.getProperties; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.Multimap; diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java index 86c6dbc6..b6c686fd 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java @@ -1,12 +1,8 @@ package org.adde0109.pcf.mixin.v26_1.forwarding.legacy; -import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.SPOOFED_PROFILE; -import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.SPOOFED_UUID; -import static org.adde0109.pcf.forwarding.modern.ReflectionUtils.getProperties; +import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.createProfile; import com.mojang.authlib.GameProfile; -import com.mojang.authlib.properties.Property; -import com.mojang.authlib.properties.PropertyMap; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; @@ -23,66 +19,27 @@ import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.nio.charset.StandardCharsets; -import java.util.UUID; -import java.util.regex.Pattern; - // https://hub.spigotmc.org/stash/projects/SPIGOT/repos/spigot/browse/CraftBukkit-Patches/0024-BungeeCord-Support.patch @Mixin(ServerLoginPacketListenerImpl.class) public abstract class ServerLoginPacketListenerImplHelloMixin implements ServerLoginPacketListenerBridge { // spotless:off @Shadow @Final private Connection connection; - @Shadow protected abstract void startClientVerification(GameProfile profile); - @Unique private static final Pattern pcf$PROP_PATTERN = Pattern.compile("\\w{0,16}"); - @AConstraint(mappings = Mappings.MOJANG, version = @Versions(min = MinecraftVersion.V20_2)) @Inject(method = "handleHello", cancellable = true, at = @At(value = "INVOKE", ordinal = 1, target = "Lnet/minecraft/server/network/ServerLoginPacketListenerImpl;startClientVerification(Lcom/mojang/authlib/GameProfile;)V")) // spotless:on private void onHandleHello_20_M( final ServerboundHelloPacket packet, final @NonNull CallbackInfo ci) { - final ConnectionBridge conn = (ConnectionBridge) this.connection; - - if (conn.bridge$channel().attr(SPOOFED_UUID).get() == null) { - return; // TODO: Provide client-bound disconnect error - } - // TODO: PostProcessors - this.startClientVerification(this.pcf$createOfflineProfile(packet.name())); + this.startClientVerification( + createProfile((ConnectionBridge) this.connection, packet.name())); ci.cancel(); } - - // Spigot start - @Unique protected GameProfile pcf$createOfflineProfile(String name) { - final ConnectionBridge conn = (ConnectionBridge) this.connection; - - final UUID uuid; - if (conn.bridge$channel().attr(SPOOFED_UUID).get() != null) { - uuid = conn.bridge$channel().attr(SPOOFED_UUID).get(); - } else { - uuid = - UUID.nameUUIDFromBytes( - ("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8)); - } - - // TODO: Add 1.21.9 support - final GameProfile profile = new GameProfile(uuid, name); - final PropertyMap propertiesMap = getProperties(profile); - if (conn.bridge$channel().attr(SPOOFED_PROFILE).get() != null) { - for (final Property property : conn.bridge$channel().attr(SPOOFED_PROFILE).get()) { - if (!pcf$PROP_PATTERN.matcher(property.name()).matches()) continue; - propertiesMap.put(property.name(), property); - } - } - return profile; - } - // Spigot end } From 40f48297fb0ef1f198bb3daf3bd8c06948075900 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 20:46:19 -0600 Subject: [PATCH 38/71] Move error future listener to ConnectionBridge --- .../adde0109/pcf/forwarding/ConnectionBridge.java | 15 +++++++++++++-- .../pcf/forwarding/modern/ModernForwarding.java | 12 ------------ 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java b/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java index 8e40c1b6..7df41abf 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java @@ -4,9 +4,9 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; +import io.netty.util.concurrent.Future; import org.adde0109.pcf.PCF; -import org.adde0109.pcf.forwarding.modern.ModernForwarding; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; @@ -28,7 +28,7 @@ public interface ConnectionBridge { @Nullable Protocol bridge$protocol(); default void bridge$send(final @NonNull Object packet) { - this.bridge$channel().writeAndFlush(packet).addListener(ModernForwarding::errorListener); + this.bridge$channel().writeAndFlush(packet).addListener(ConnectionBridge::errorListener); } /** @@ -48,4 +48,15 @@ static void injectIntoPipeline(final @NonNull ChannelHandlerContext ctx) { .addAfter(HANDLER_SPLITTER, PacketDecoder.NAME, new PacketDecoder()) .addAfter(HANDLER_PREPENDER, PacketEncoder.NAME, new PacketEncoder()); } + + /** + * Listener for logging errors during packet handling + * + * @param future the future to check for success or failure + */ + static void errorListener(Future future) { + if (!future.isSuccess()) { + PCF.logger.error("An error occurred during packet handling", future.cause()); + } + } } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index 1a2fe090..4f590473 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -21,7 +21,6 @@ import io.netty.handler.codec.DecoderException; import io.netty.util.AttributeKey; -import io.netty.util.concurrent.Future; import org.adde0109.pcf.PCF; import org.adde0109.pcf.forwarding.ConnectionBridge; @@ -59,17 +58,6 @@ public final class ModernForwarding { private static final Object REJECTED_PROXY_ERR = literal("Unapproved proxy host."); - /** - * Listener for logging errors during packet handling - * - * @param future the future to check for success or failure - */ - public static void errorListener(Future future) { - if (!future.isSuccess()) { - PCF.logger.error("An error occurred during packet handling", future.cause()); - } - } - /** * Abstract implementation of the hello packet handler * From 0f09b95210f9689ec91a4bee35683291b22fc9e2 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 21:07:10 -0600 Subject: [PATCH 39/71] Removed forwarding mode NONE, as it's somewhat redundant on the backend --- common/src/main/java/org/adde0109/pcf/forwarding/Mode.java | 1 - 1 file changed, 1 deletion(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/Mode.java b/common/src/main/java/org/adde0109/pcf/forwarding/Mode.java index 3cf087d8..cabd387b 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/Mode.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/Mode.java @@ -2,7 +2,6 @@ /** Forwarding types supported by PCF */ public enum Mode { - NONE, LEGACY, BUNGEEGUARD, MODERN From 719e444feca314aabb5a8145dc6901df016896c4 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 21:08:55 -0600 Subject: [PATCH 40/71] Renamed PostProcessor to PreLoginHandler to better describe its purpose and relocated it for common usage --- .../src/main/java/org/adde0109/pcf/PCF.java | 55 ++++++++++--------- .../pcf/forwarding/PreLoginHandler.java | 39 +++++++++++++ .../forwarding/modern/ModernForwarding.java | 37 +------------ 3 files changed, 70 insertions(+), 61 deletions(-) create mode 100644 common/src/main/java/org/adde0109/pcf/forwarding/PreLoginHandler.java diff --git a/common/src/main/java/org/adde0109/pcf/PCF.java b/common/src/main/java/org/adde0109/pcf/PCF.java index 24bd9d7d..b5f43402 100644 --- a/common/src/main/java/org/adde0109/pcf/PCF.java +++ b/common/src/main/java/org/adde0109/pcf/PCF.java @@ -2,6 +2,8 @@ import static dev.neuralnexus.taterapi.network.Protocol.map; +import static org.adde0109.pcf.forwarding.PreLoginHandler.HANDLERS; + import dev.neuralnexus.taterapi.loader.EntrypointLoader; import dev.neuralnexus.taterapi.meta.Constraint; import dev.neuralnexus.taterapi.meta.Constraints; @@ -19,7 +21,6 @@ import org.adde0109.pcf.forwarding.compatibility.prelogin.MohistPreLogin; import org.adde0109.pcf.forwarding.compatibility.prelogin.SpigotPreLogin; import org.adde0109.pcf.forwarding.compatibility.prelogin.SpongePreLogin; -import org.adde0109.pcf.forwarding.modern.ModernForwarding; import org.adde0109.pcf.forwarding.modern.PlayerInfoQueryPayload; import org.adde0109.pcf.forwarding.modern.VelocityProxy; import org.jetbrains.annotations.ApiStatus; @@ -79,37 +80,40 @@ void onInit() { loader.onInit(); // Modern forwarding init - if (this.forwarding().enabled() && this.forwarding().mode().equals(Mode.MODERN)) { + if (this.forwarding().enabled() && this.forwarding().mode() == Mode.MODERN) { PayloadRegistry.register( PlayerInfoQueryPayload.TYPE, map(PlayerInfoQueryPayload.IDENTIFIER, MinecraftVersions.V7_2)); + } + // Forwarding init + if (this.forwarding().enabled()) { if (Constraint.builder().platform(Platforms.ARCLIGHT).result()) { logger.debug("Arclight detected, applying pre-login post processor"); if (Constraint.range(MinecraftVersions.V14, MinecraftVersions.V20_1).result()) { - ModernForwarding.postProcessors.removeFirst(); - ModernForwarding.postProcessors.add( - (slpl, profile, c) -> { + HANDLERS.removeFirst(); + HANDLERS.add( + (slpl, profile, _) -> { slpl.bridge$setGameProfile(profile); ArclightPreLogin.V14.preLogin(slpl); }); } else if (Constraint.builder().version(MinecraftVersions.V20_2).result()) { - ModernForwarding.postProcessors.removeFirst(); - ModernForwarding.postProcessors.add( - (slpl, profile, c) -> ArclightPreLogin.V20_2.preLogin(slpl, profile)); + HANDLERS.removeFirst(); + HANDLERS.add( + (slpl, profile, _) -> ArclightPreLogin.V20_2.preLogin(slpl, profile)); } else if (Constraint.noLessThan(MinecraftVersions.V20_3).result()) { - ModernForwarding.postProcessors.removeFirst(); - ModernForwarding.postProcessors.add( - (slpl, profile, c) -> ArclightPreLogin.V20_4.preLogin(slpl, profile)); + HANDLERS.removeFirst(); + HANDLERS.add( + (slpl, profile, _) -> ArclightPreLogin.V20_4.preLogin(slpl, profile)); } } else if (Constraint.builder() .platform(Platforms.MOHIST) .version(MinecraftVersions.V20_1) .result()) { logger.debug("Mohist detected, applying pre-login post processor"); - ModernForwarding.postProcessors.removeFirst(); - ModernForwarding.postProcessors.add( - (slpl, profile, c) -> { + HANDLERS.removeFirst(); + HANDLERS.add( + (slpl, profile, _) -> { slpl.bridge$setGameProfile(profile); MohistPreLogin.V20_1.fireEvents(slpl); }); @@ -118,9 +122,9 @@ void onInit() { .version(MinecraftVersions.V21_1) .result()) { logger.debug("Youer detected, applying pre-login post processor"); - ModernForwarding.postProcessors.removeFirst(); - ModernForwarding.postProcessors.add( - (slpl, profile, c) -> { + HANDLERS.removeFirst(); + HANDLERS.add( + (slpl, profile, _) -> { MohistPreLogin.Youer.fireEvents(slpl, profile); slpl.bridge$startClientVerification(profile); }); @@ -136,9 +140,9 @@ void onInit() { .version(MinecraftVersions.V20_1)) .result()) { logger.debug("Forge+Bukkit hybrid detected, applying pre-login post processor"); - ModernForwarding.postProcessors.removeFirst(); - ModernForwarding.postProcessors.add( - (slpl, profile, c) -> { + HANDLERS.removeFirst(); + HANDLERS.add( + (slpl, profile, _) -> { slpl.bridge$setGameProfile(profile); SpigotPreLogin.Legacy.fireEvents(slpl); }); @@ -152,9 +156,8 @@ void onInit() { .result()) { logger.debug( "[Neo]Forge+Bukkit hybrid detected, applying pre-login post processor"); - ModernForwarding.postProcessors.removeFirst(); - ModernForwarding.postProcessors.add( - (slpl, profile, c) -> SpigotPreLogin.V20_2.fireEvents(slpl, profile)); + HANDLERS.removeFirst(); + HANDLERS.add((slpl, profile, _) -> SpigotPreLogin.V20_2.fireEvents(slpl, profile)); } else if (Constraints.builder() .or( Constraint.builder() @@ -171,8 +174,8 @@ void onInit() { .result()) { logger.debug( "[Neo]Forge+Bukkit hybrid detected, applying pre-login post processor"); - ModernForwarding.postProcessors.addFirst( - (slpl, profile, c) -> + HANDLERS.addFirst( + (slpl, profile, _) -> SpigotPreLogin.V20_5.callPlayerPreLoginEvents(slpl, profile)); } @@ -180,7 +183,7 @@ void onInit() { .platform(Platforms.SPONGE) .result()) { logger.debug("SpongeAPI 8 or 9 detected, applying pre-login post processor"); - ModernForwarding.postProcessors.addFirst( + HANDLERS.addFirst( (slpl, profile, c) -> { slpl.bridge$setGameProfile(profile); c.setCancelled(SpongePreLogin.API8.fireAuthEvent(slpl)); diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PreLoginHandler.java b/common/src/main/java/org/adde0109/pcf/forwarding/PreLoginHandler.java new file mode 100644 index 00000000..c3c5b2d8 --- /dev/null +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PreLoginHandler.java @@ -0,0 +1,39 @@ +package org.adde0109.pcf.forwarding; + +import com.mojang.authlib.GameProfile; + +import dev.neuralnexus.taterapi.event.Cancellable; +import dev.neuralnexus.taterapi.mc.server.players.NameAndId; + +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NonNull; + +import java.util.ArrayList; +import java.util.List; + +@ApiStatus.Internal +@FunctionalInterface +public interface PreLoginHandler { + PreLoginHandler DEFAULT_HANDLER = + (slpl, profile, _) -> { + final NameAndId nameAndId = new NameAndId(profile); + slpl.bridge$logger_info( + "UUID of player {} is {}", nameAndId.name(), nameAndId.id()); + slpl.bridge$startClientVerification(profile); + }; + @ApiStatus.Internal List HANDLERS = new ArrayList<>(List.of(DEFAULT_HANDLER)); + + /** + * Process the forwarded profile + * + * @param slpl the ServerLoginPacketListener + * @param profile the forwarded GameProfile + * @param c the cancellable wrapper + * @throws Exception if an error occurs + */ + void process( + final @NonNull ServerLoginPacketListenerBridge slpl, + final @NonNull GameProfile profile, + final @NonNull Cancellable c) + throws Exception; +} diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index 4f590473..0bc2194e 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -8,8 +8,6 @@ import static org.adde0109.pcf.forwarding.modern.VelocityProxy.PLAYER_INFO_PAYLOAD; import static org.adde0109.pcf.forwarding.modern.VelocityProxy.checkIntegrity; -import com.mojang.authlib.GameProfile; - import dev.neuralnexus.taterapi.event.Cancellable; import dev.neuralnexus.taterapi.mc.server.players.NameAndId; import dev.neuralnexus.taterapi.meta.Constraint; @@ -25,14 +23,13 @@ import org.adde0109.pcf.PCF; import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.Mode; +import org.adde0109.pcf.forwarding.PreLoginHandler; import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; -import org.jetbrains.annotations.ApiStatus; import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.net.InetSocketAddress; import java.security.InvalidKeyException; -import java.util.ArrayList; import java.util.List; import java.util.concurrent.ThreadLocalRandom; @@ -97,36 +94,6 @@ public static void handleHello( ci.cancel(); } - @ApiStatus.Internal - @FunctionalInterface - public interface PostProcessor { - /** - * Process the forwarded profile - * - * @param slpl the ServerLoginPacketListener - * @param profile the forwarded GameProfile - * @param c the cancellable wrapper - * @throws Exception if an error occurs - */ - void process( - final @NonNull ServerLoginPacketListenerBridge slpl, - final @NonNull GameProfile profile, - final @NonNull Cancellable c) - throws Exception; - } - - private static final PostProcessor DEFAULT_POST_PROCESSOR = - (slpl, profile, _) -> { - final NameAndId nameAndId = new NameAndId(profile); - slpl.bridge$logger_info( - "UUID of player {} is {}", nameAndId.name(), nameAndId.id()); - slpl.bridge$startClientVerification(profile); - }; - - @ApiStatus.Internal - public static final List postProcessors = - new ArrayList<>(List.of(DEFAULT_POST_PROCESSOR)); - private static final Object DIRECT_CONNECT_ERR = literal("This server requires you to connect with Velocity."); private static final Object EMPTY_PAYLOAD_ERR = @@ -246,7 +213,7 @@ public static void handleCustomQueryPacket( // Proceed with login try { final Cancellable cancellable = Cancellable.simple(); - for (final PostProcessor processor : postProcessors) { + for (final PreLoginHandler processor : PreLoginHandler.HANDLERS) { processor.process(slpl, payload.profile(), cancellable); if (cancellable.cancelled()) { break; From a49d2a104a1d589aebbbaca62df01e06763a5186 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 22 Apr 2026 21:16:40 -0600 Subject: [PATCH 41/71] Added helper methods to Mode to aid with differentiating between Legacy and Modern forwarding types --- common/src/main/java/org/adde0109/pcf/PCF.java | 2 +- .../main/java/org/adde0109/pcf/forwarding/Mode.java | 10 +++++++++- .../org/adde0109/pcf/forwarding/PacketDecoder.java | 7 +++---- .../pcf/forwarding/modern/ModernForwarding.java | 5 ++--- .../org/adde0109/pcf/mixin/plugin/PCFMixinPlugin.java | 10 ++++++---- 5 files changed, 21 insertions(+), 13 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/PCF.java b/common/src/main/java/org/adde0109/pcf/PCF.java index b5f43402..261f05a9 100644 --- a/common/src/main/java/org/adde0109/pcf/PCF.java +++ b/common/src/main/java/org/adde0109/pcf/PCF.java @@ -80,7 +80,7 @@ void onInit() { loader.onInit(); // Modern forwarding init - if (this.forwarding().enabled() && this.forwarding().mode() == Mode.MODERN) { + if (this.forwarding().enabled() && this.forwarding().mode().isModern()) { PayloadRegistry.register( PlayerInfoQueryPayload.TYPE, map(PlayerInfoQueryPayload.IDENTIFIER, MinecraftVersions.V7_2)); diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/Mode.java b/common/src/main/java/org/adde0109/pcf/forwarding/Mode.java index cabd387b..7f2c7478 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/Mode.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/Mode.java @@ -4,5 +4,13 @@ public enum Mode { LEGACY, BUNGEEGUARD, - MODERN + MODERN; + + public boolean isLegacy() { + return this == LEGACY || this == BUNGEEGUARD; + } + + public boolean isModern() { + return this == MODERN; + } } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 8bdac86f..92460449 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -37,9 +37,8 @@ protected void decode( switch (connection.bridge$protocol()) { case null -> {} case HANDSHAKING -> { - if (!PCF.instance().forwarding().enabled() - || (PCF.instance().forwarding().mode() != Mode.LEGACY - && PCF.instance().forwarding().mode() != Mode.BUNGEEGUARD)) { + if (!(PCF.instance().forwarding().enabled() + && PCF.instance().forwarding().mode().isLegacy())) { out.add(msg.retain()); return; } @@ -76,7 +75,7 @@ protected void decode( } case LOGIN -> { if (!PCF.instance().forwarding().enabled() - || !PCF.instance().forwarding().mode().equals(Mode.MODERN)) { + || !PCF.instance().forwarding().mode().isModern()) { out.add(msg.retain()); return; } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index 0bc2194e..ede7208a 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -22,7 +22,6 @@ import org.adde0109.pcf.PCF; import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.adde0109.pcf.forwarding.Mode; import org.adde0109.pcf.forwarding.PreLoginHandler; import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; @@ -63,8 +62,8 @@ public final class ModernForwarding { */ public static void handleHello( final @NonNull ServerLoginPacketListenerBridge slpl, final @NonNull CallbackInfo ci) { - if (!PCF.instance().forwarding().enabled() - || !PCF.instance().forwarding().mode().equals(Mode.MODERN)) { + if (!(PCF.instance().forwarding().enabled() + && PCF.instance().forwarding().mode().isModern())) { return; } final ConnectionBridge connection = slpl.bridge$connection(); diff --git a/common/src/main/java/org/adde0109/pcf/mixin/plugin/PCFMixinPlugin.java b/common/src/main/java/org/adde0109/pcf/mixin/plugin/PCFMixinPlugin.java index 234aaec8..a1f9d797 100644 --- a/common/src/main/java/org/adde0109/pcf/mixin/plugin/PCFMixinPlugin.java +++ b/common/src/main/java/org/adde0109/pcf/mixin/plugin/PCFMixinPlugin.java @@ -10,7 +10,6 @@ import dev.neuralnexus.taterapi.muxins.Muxins; import org.adde0109.pcf.PCF; -import org.adde0109.pcf.forwarding.Mode; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.objectweb.asm.tree.ClassNode; @@ -82,12 +81,15 @@ private static boolean shouldApplyMixin( PCF.logger.debug("Skipping mixin " + m + " because forwarding is disabled."); return false; } - if (forwarding.mode() != Mode.MODERN && m.contains(".forwarding.modern.")) { + if (!forwarding.mode().isModern() && m.contains(".forwarding.modern.")) { PCF.logger.debug("Skipping mixin " + m + " because forwarding mode is not MODERN."); return false; } - if (forwarding.mode() != Mode.LEGACY && m.contains(".forwarding.legacy.")) { - PCF.logger.debug("Skipping mixin " + m + " because forwarding mode is not LEGACY."); + if (!forwarding.mode().isLegacy() && m.contains(".forwarding.legacy.")) { + PCF.logger.debug( + "Skipping mixin " + + m + + " because forwarding mode is not LEGACY or BUNGEEGUARD."); return false; } if (advanced.modernForwardingVersion() != NO_OVERRIDE From 8f07bb4d15ae4965bf938e5d21f82230facdacb8 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Thu, 23 Apr 2026 00:37:09 -0600 Subject: [PATCH 42/71] Legacy and BungeeGuard forwarding implemented --- .../src/main/java/org/adde0109/pcf/PCF.java | 6 + .../pcf/forwarding/PacketDecoder.java | 28 +++++ .../pcf/forwarding/ReflectionUtils.java | 59 +++++++++- .../forwarding/bungeeguard/BungeeGuard.java | 55 +++++++++ .../forwarding/legacy/LegacyForwarding.java | 108 +++++++++++++++--- ...rverLoginPacketListenerImplHelloMixin.java | 26 ++--- 6 files changed, 250 insertions(+), 32 deletions(-) create mode 100644 common/src/main/java/org/adde0109/pcf/forwarding/bungeeguard/BungeeGuard.java diff --git a/common/src/main/java/org/adde0109/pcf/PCF.java b/common/src/main/java/org/adde0109/pcf/PCF.java index 261f05a9..8fc5f65f 100644 --- a/common/src/main/java/org/adde0109/pcf/PCF.java +++ b/common/src/main/java/org/adde0109/pcf/PCF.java @@ -17,6 +17,7 @@ import dev.neuralnexus.taterapi.network.PayloadRegistry; import org.adde0109.pcf.forwarding.Mode; +import org.adde0109.pcf.forwarding.bungeeguard.BungeeGuard; import org.adde0109.pcf.forwarding.compatibility.prelogin.ArclightPreLogin; import org.adde0109.pcf.forwarding.compatibility.prelogin.MohistPreLogin; import org.adde0109.pcf.forwarding.compatibility.prelogin.SpigotPreLogin; @@ -189,6 +190,11 @@ void onInit() { c.setCancelled(SpongePreLogin.API8.fireAuthEvent(slpl)); }); } + + if (this.forwarding().mode() == Mode.BUNGEEGUARD) { + logger.debug("BungeeGuard detected, applying pre-login post processor"); + HANDLERS.addFirst(BungeeGuard::validateToken); + } } Constraint.Evaluator.DEBUG = debug; diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 92460449..0ed1693d 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -1,6 +1,7 @@ package org.adde0109.pcf.forwarding; import static org.adde0109.pcf.forwarding.ConnectionBridge.HANDLER_PACKET; +import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.PLAYER_NAME; import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.handleClientIntentionPacket; import static org.adde0109.pcf.forwarding.modern.ModernForwarding.LOGIN_MESSAGE_ID; import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleCustomQueryPacket; @@ -74,6 +75,33 @@ protected void decode( } } case LOGIN -> { + // TODO: Clean this up + if (PCF.instance().forwarding().enabled() + && PCF.instance().forwarding().mode().isLegacy()) { + final int readerIndex = msg.readerIndex(); + final FriendlyByteBuf data = new FriendlyByteBuf(msg); + final int id = data.readVarInt(); + PCF.logger.debug( + "Received packet with ID 0x" + + Integer.toHexString(id) + + " from " + + ctx.channel().remoteAddress()); + + //noinspection SwitchStatementWithTooFewBranches + switch (id) { + case 0x00 -> { + PCF.logger.debug( + "Handling ServerBoundHello from " + + ctx.channel().remoteAddress()); + final String name = data.readUtf(16); + ctx.channel().attr(PLAYER_NAME).set(name); + msg.readerIndex(readerIndex); + } + default -> msg.readerIndex(readerIndex); + } + break; + } + if (!PCF.instance().forwarding().enabled() || !PCF.instance().forwarding().mode().isModern()) { out.add(msg.retain()); diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/ReflectionUtils.java b/common/src/main/java/org/adde0109/pcf/forwarding/ReflectionUtils.java index 9a4cf828..0197fec1 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/ReflectionUtils.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/ReflectionUtils.java @@ -1,6 +1,7 @@ package org.adde0109.pcf.forwarding; import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import dev.neuralnexus.taterapi.meta.Constraint; @@ -20,14 +21,42 @@ public final class ReflectionUtils { private ReflectionUtils() {} private static final MethodHandle profilePropertiesHandle; + private static final MethodHandle profilePropertyNameHandle; + private static final MethodHandle profilePropertyValueHandle; static { + final MethodHandles.Lookup lookup = MethodHandles.lookup(); + + // com.mojang:authlib:5.0.0 or newer + final String profilePropertyNameString; + final String profilePropertyValueString; + if (Constraint.noLessThan(MinecraftVersions.V20_2).result()) { + profilePropertyNameString = "name"; + profilePropertyValueString = "value"; + } else { + profilePropertyNameString = "getName"; + profilePropertyValueString = "getValue"; + } + try { + profilePropertyNameHandle = + lookup.findVirtual( + Property.class, + profilePropertyNameString, + MethodType.methodType(String.class)); + profilePropertyValueHandle = + lookup.findVirtual( + Property.class, + profilePropertyValueString, + MethodType.methodType(String.class)); + } catch (final NoSuchMethodException | IllegalAccessException e) { + throw new IllegalStateException("Failed to initialize GameProfile method handles", e); + } + // com.mojang:authlib:7.0.0 or newer if (Constraint.noLessThan(MinecraftVersions.V21_9).result()) { profilePropertiesHandle = null; } else { try { - MethodHandles.Lookup lookup = MethodHandles.lookup(); //noinspection JavaLangInvokeHandleSignature profilePropertiesHandle = lookup.findVirtual( @@ -41,6 +70,34 @@ private ReflectionUtils() {} } } + /** + * Gets the name of a Property + * + * @param property the property + * @return the name + */ + public static @NonNull String getName(final @NonNull Property property) { + try { + return (String) profilePropertyNameHandle.invokeExact(property); + } catch (final Throwable e) { + throw new IllegalStateException("Failed to get name from Property", e); + } + } + + /** + * Gets the value of a Property + * + * @param property the property + * @return the value + */ + public static @NonNull String getValue(final @NonNull Property property) { + try { + return (String) profilePropertyValueHandle.invokeExact(property); + } catch (final Throwable e) { + throw new IllegalStateException("Failed to get value from Property", e); + } + } + /** * Gets the properties from the given GameProfile - 1.21.8 and older * diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/bungeeguard/BungeeGuard.java b/common/src/main/java/org/adde0109/pcf/forwarding/bungeeguard/BungeeGuard.java new file mode 100644 index 00000000..6b54a839 --- /dev/null +++ b/common/src/main/java/org/adde0109/pcf/forwarding/bungeeguard/BungeeGuard.java @@ -0,0 +1,55 @@ +package org.adde0109.pcf.forwarding.bungeeguard; + +import static dev.neuralnexus.taterapi.network.chat.Component.literal; + +import com.mojang.authlib.GameProfile; + +import dev.neuralnexus.taterapi.event.Cancellable; +import dev.neuralnexus.taterapi.mc.server.players.NameAndId; +import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; + +import io.netty.util.AttributeKey; + +import org.adde0109.pcf.PCF; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; +import org.jspecify.annotations.NonNull; + +import java.util.Collection; + +// https://github.com/lucko/BungeeGuard +public final class BungeeGuard { + public static final String BUNGEE_GUARD_TOKEN_PROPERTY_NAME = "bungeeguard-token"; + public static final AttributeKey> BUNGEE_GUARD_TOKEN = + AttributeKey.valueOf("pcf-bungeeguard-token"); + + private static final Object NO_DATA = + literal("&cUnable to authenticate - no data was forwarded by the proxy."); + private static final Object INVALID_TOKEN = literal("&cUnable to authenticate."); + + public static void validateToken( + final @NonNull ServerLoginPacketListenerBridge slpl, + final @NonNull GameProfile profile, + final @NonNull Cancellable ignored) { + final NameAndId nameAndId = new NameAndId(profile); + final String connectionDescription = + nameAndId.id() + " @ " + slpl.bridge$connection().bridge$address().getHostString(); + final Collection bungeeGuardTokens = + slpl.bridge$connection().bridge$channel().attr(BUNGEE_GUARD_TOKEN).getAndSet(null); + if (bungeeGuardTokens.size() > 1) { + PCF.logger.warn( + "Denying connection from " + connectionDescription + " - more than one token"); + throw new ThrowingComponent(INVALID_TOKEN); + } + final String bungeeGuardToken = bungeeGuardTokens.stream().findFirst().orElse(null); + + // TODO: Consider supporting multiple in PCF's config + if (!PCF.instance().forwarding().secret().equals(bungeeGuardToken)) { + final String reason = bungeeGuardToken == null ? "No Token" : "Invalid token"; + PCF.logger.warn( + "Denying connection from " + connectionDescription + " - reason: " + reason); + throw new ThrowingComponent(bungeeGuardToken == null ? NO_DATA : INVALID_TOKEN); + } + + PCF.logger.debug("Successfully validated BungeeGuard token for " + connectionDescription); + } +} diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java index 2a0062d7..c5acbb09 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java @@ -1,8 +1,13 @@ package org.adde0109.pcf.forwarding.legacy; import static dev.neuralnexus.taterapi.network.chat.Component.literal; +import static dev.neuralnexus.taterapi.network.chat.Component.translatable; +import static org.adde0109.pcf.forwarding.ReflectionUtils.getName; import static org.adde0109.pcf.forwarding.ReflectionUtils.getProperties; +import static org.adde0109.pcf.forwarding.ReflectionUtils.getValue; +import static org.adde0109.pcf.forwarding.bungeeguard.BungeeGuard.BUNGEE_GUARD_TOKEN; +import static org.adde0109.pcf.forwarding.bungeeguard.BungeeGuard.BUNGEE_GUARD_TOKEN_PROPERTY_NAME; import com.google.common.collect.ImmutableMultimap; import com.google.common.net.InetAddresses; @@ -13,6 +18,8 @@ import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; +import dev.neuralnexus.taterapi.event.Cancellable; +import dev.neuralnexus.taterapi.mc.server.players.NameAndId; import dev.neuralnexus.taterapi.meta.Constraint; import dev.neuralnexus.taterapi.meta.MinecraftVersions; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; @@ -20,15 +27,20 @@ import dev.neuralnexus.taterapi.network.protocol.handshake.ClientIntent; import dev.neuralnexus.taterapi.network.protocol.handshake.ClientIntentionPacket; +import io.netty.channel.Channel; import io.netty.util.AttributeKey; import org.adde0109.pcf.PCF; import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.Mode; +import org.adde0109.pcf.forwarding.PreLoginHandler; +import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.net.InetSocketAddress; import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -36,12 +48,14 @@ import java.util.regex.Pattern; public final class LegacyForwarding { + private static final Object REJECTED_PROXY_ERR = literal("Unapproved proxy host."); + + public static final AttributeKey PLAYER_NAME = AttributeKey.valueOf("pcf-player-name"); public static final AttributeKey SPOOFED_UUID = AttributeKey.valueOf("pcf-spoofed-uuid"); public static final AttributeKey> SPOOFED_PROFILE = AttributeKey.valueOf("pcf-spoofed-profile"); private static final char LEGACY_SEPARATOR = '\0'; - private static final String BUNGEE_GUARD_TOKEN_PROPERTY_NAME = "bungeeguard-token"; private static final Gson GSON = new GsonBuilder().create(); private static final TypeToken> profileTypeToken = new TypeToken<>() {}; @@ -66,11 +80,29 @@ public static void handleClientIntentionPacket( return; } + // Check if the connection is from an approved proxy + final List approved = PCF.instance().forwarding().approvedProxyHosts(); + if (!approved.isEmpty()) { + final InetSocketAddress address = connection.bridge$address(); + final String host = address.getHostString(); + final String ip = address.getAddress().getHostAddress(); + if (!approved.contains(host) && !approved.contains(ip)) { + PCF.logger.warn( + "Rejected connection from unapproved proxy host: " + + host + + " (IP: " + + ip + + ")"); + throw new ThrowingComponent(REJECTED_PROXY_ERR); + } + } + final String[] split = hostName.split("\00"); - if ((split.length < 3) || !(HOST_PATTERN.matcher(split[1]).matches())) { + if (split.length < 3 || !(HOST_PATTERN.matcher(split[1]).matches())) { throw new ThrowingComponent(DIRECT_CONNECT_ERR); } - if (PCF.instance().forwarding().mode() != Mode.BUNGEEGUARD && (split.length < 4)) { + if (PCF.instance().forwarding().mode() == Mode.BUNGEEGUARD + && (split.length < 4 || !split[3].contains(BUNGEE_GUARD_TOKEN_PROPERTY_NAME))) { throw new ThrowingComponent(BG_CONFIG_ERR); } @@ -129,19 +161,69 @@ private static boolean isFmlMarker(final @NonNull Property property) { && property.value().startsWith("\u0001FORGE"); } + private static final Object FAILED_TO_VERIFY = + translatable("multiplayer.disconnect.unverified_username"); + + public static void handleHello( + final @NonNull ServerLoginPacketListenerBridge slpl, final @NonNull CallbackInfo ci) { + if (!(PCF.instance().forwarding().enabled() + && PCF.instance().forwarding().mode().isLegacy())) { + return; + } + final GameProfile profile = createProfile(slpl.bridge$connection().bridge$channel()); + + // Proceed with login + try { + final Cancellable cancellable = Cancellable.simple(); + for (final PreLoginHandler processor : PreLoginHandler.HANDLERS) { + processor.process(slpl, profile, cancellable); + if (cancellable.cancelled()) { + break; + } + } + } catch (final ThrowingComponent e) { + throw e; + } catch (final Exception e) { + final NameAndId nameAndId = new NameAndId(profile); + PCF.logger.warn("Exception while forwarding user " + nameAndId.name()); + e.printStackTrace(); + throw new ThrowingComponent(FAILED_TO_VERIFY, e); + } finally { + ci.cancel(); + } + } + private static final Pattern PROP_PATTERN = Pattern.compile("\\w{0,16}"); - public static GameProfile createProfile( - final @NonNull ConnectionBridge conn, final @NonNull String name) { - final UUID uuid; - if (conn.bridge$channel().attr(SPOOFED_UUID).get() != null) { - uuid = conn.bridge$channel().attr(SPOOFED_UUID).get(); - } else { + public static @NonNull GameProfile createProfile(final @NonNull Channel channel) { + final String name = channel.attr(PLAYER_NAME).getAndSet(null); + final UUID uuid = channel.attr(SPOOFED_UUID).getAndSet(null); + if (name == null || uuid == null) { throw new ThrowingComponent(PLAYER_INFO_ERR); } - final Collection properties = conn.bridge$channel().attr(SPOOFED_PROFILE).get(); - if (properties == null) { + final Collection properties = channel.attr(SPOOFED_PROFILE).getAndSet(null); + + // Check for BungeeGuard tokens + if (PCF.instance().forwarding().mode() == Mode.BUNGEEGUARD + && properties != null + && !properties.isEmpty()) { + final Collection bungeeGuardTokens = new HashSet<>(); + for (final Property property : properties) { + if (getName(property).equals(BUNGEE_GUARD_TOKEN_PROPERTY_NAME)) { + bungeeGuardTokens.add(getValue(property)); + } + } + channel.attr(BUNGEE_GUARD_TOKEN).set(bungeeGuardTokens); + + // Remove BungeeGuard token(s) from properties. + // They're filtered out by PROP_PATTERN, but might as well remove them now. + properties.removeIf( + property -> getName(property).equals(BUNGEE_GUARD_TOKEN_PROPERTY_NAME)); + } + + // Create the profile + if (properties == null || properties.isEmpty()) { return new GameProfile(uuid, name); // com.mojang:authlib:7.0.0 or newer } else if (Constraint.noLessThan(MinecraftVersions.V21_9).result()) { @@ -156,8 +238,8 @@ public static GameProfile createProfile( final GameProfile profile = new GameProfile(uuid, name); final PropertyMap propertiesMap = getProperties(profile); for (final Property property : properties) { - if (!PROP_PATTERN.matcher(property.name()).matches()) continue; - propertiesMap.put(property.name(), property); + if (!PROP_PATTERN.matcher(getName(property)).matches()) continue; + propertiesMap.put(getName(property), property); } return profile; } diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java index b6c686fd..76125a67 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java @@ -1,24 +1,17 @@ package org.adde0109.pcf.mixin.v26_1.forwarding.legacy; -import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.createProfile; - -import com.mojang.authlib.GameProfile; - import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; import dev.neuralnexus.taterapi.meta.anno.Versions; import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; +import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; -import net.minecraft.network.Connection; -import net.minecraft.network.protocol.login.ServerboundHelloPacket; import net.minecraft.server.network.ServerLoginPacketListenerImpl; -import org.adde0109.pcf.forwarding.ConnectionBridge; import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; +import org.adde0109.pcf.forwarding.legacy.LegacyForwarding; import org.jspecify.annotations.NonNull; -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; @@ -28,18 +21,15 @@ public abstract class ServerLoginPacketListenerImplHelloMixin implements ServerLoginPacketListenerBridge { // spotless:off - @Shadow @Final private Connection connection; - @Shadow protected abstract void startClientVerification(GameProfile profile); - @AConstraint(mappings = Mappings.MOJANG, version = @Versions(min = MinecraftVersion.V20_2)) @Inject(method = "handleHello", cancellable = true, at = @At(value = "INVOKE", ordinal = 1, target = "Lnet/minecraft/server/network/ServerLoginPacketListenerImpl;startClientVerification(Lcom/mojang/authlib/GameProfile;)V")) // spotless:on - private void onHandleHello_20_M( - final ServerboundHelloPacket packet, final @NonNull CallbackInfo ci) { - // TODO: PostProcessors - this.startClientVerification( - createProfile((ConnectionBridge) this.connection, packet.name())); - ci.cancel(); + private void onHandleHello_20_M(final @NonNull CallbackInfo ci) { + try { + LegacyForwarding.handleHello(this, ci); + } catch (final ThrowingComponent e) { + this.bridge$disconnect(e.getComponent()); + } } } From 0a675c72214208bd8042d3050805902040878ec6 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Thu, 23 Apr 2026 00:59:05 -0600 Subject: [PATCH 43/71] Reorganize init --- .../src/main/java/org/adde0109/pcf/PCF.java | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/PCF.java b/common/src/main/java/org/adde0109/pcf/PCF.java index 8fc5f65f..e9f29e3d 100644 --- a/common/src/main/java/org/adde0109/pcf/PCF.java +++ b/common/src/main/java/org/adde0109/pcf/PCF.java @@ -80,17 +80,10 @@ void onInit() { } loader.onInit(); - // Modern forwarding init - if (this.forwarding().enabled() && this.forwarding().mode().isModern()) { - PayloadRegistry.register( - PlayerInfoQueryPayload.TYPE, - map(PlayerInfoQueryPayload.IDENTIFIER, MinecraftVersions.V7_2)); - } - // Forwarding init if (this.forwarding().enabled()) { if (Constraint.builder().platform(Platforms.ARCLIGHT).result()) { - logger.debug("Arclight detected, applying pre-login post processor"); + logger.debug("Arclight detected, applying pre-login handler"); if (Constraint.range(MinecraftVersions.V14, MinecraftVersions.V20_1).result()) { HANDLERS.removeFirst(); HANDLERS.add( @@ -111,7 +104,7 @@ void onInit() { .platform(Platforms.MOHIST) .version(MinecraftVersions.V20_1) .result()) { - logger.debug("Mohist detected, applying pre-login post processor"); + logger.debug("Mohist detected, applying pre-login handler"); HANDLERS.removeFirst(); HANDLERS.add( (slpl, profile, _) -> { @@ -122,7 +115,7 @@ void onInit() { .platform(Platforms.YOUER) .version(MinecraftVersions.V21_1) .result()) { - logger.debug("Youer detected, applying pre-login post processor"); + logger.debug("Youer detected, applying pre-login handler"); HANDLERS.removeFirst(); HANDLERS.add( (slpl, profile, _) -> { @@ -140,7 +133,7 @@ void onInit() { .platform(Platforms.MAGMA, Platforms.KETTING) .version(MinecraftVersions.V20_1)) .result()) { - logger.debug("Forge+Bukkit hybrid detected, applying pre-login post processor"); + logger.debug("Forge+Bukkit hybrid detected, applying pre-login handler"); HANDLERS.removeFirst(); HANDLERS.add( (slpl, profile, _) -> { @@ -155,8 +148,7 @@ void onInit() { .platform(Platforms.MOHIST) .version(MinecraftVersions.V20_2)) .result()) { - logger.debug( - "[Neo]Forge+Bukkit hybrid detected, applying pre-login post processor"); + logger.debug("[Neo]Forge+Bukkit hybrid detected, applying pre-login handler"); HANDLERS.removeFirst(); HANDLERS.add((slpl, profile, _) -> SpigotPreLogin.V20_2.fireEvents(slpl, profile)); } else if (Constraints.builder() @@ -173,8 +165,7 @@ void onInit() { .platform(Platforms.NEOTENET) .version(MinecraftVersions.V21_1, MinecraftVersions.V21_10)) .result()) { - logger.debug( - "[Neo]Forge+Bukkit hybrid detected, applying pre-login post processor"); + logger.debug("[Neo]Forge+Bukkit hybrid detected, applying pre-login handler"); HANDLERS.addFirst( (slpl, profile, _) -> SpigotPreLogin.V20_5.callPlayerPreLoginEvents(slpl, profile)); @@ -183,18 +174,26 @@ void onInit() { if (Constraint.range(MinecraftVersions.V16, MinecraftVersions.V18_2) .platform(Platforms.SPONGE) .result()) { - logger.debug("SpongeAPI 8 or 9 detected, applying pre-login post processor"); + logger.debug("SpongeAPI 8 or 9 detected, applying pre-login handler"); HANDLERS.addFirst( (slpl, profile, c) -> { slpl.bridge$setGameProfile(profile); c.setCancelled(SpongePreLogin.API8.fireAuthEvent(slpl)); }); } + } - if (this.forwarding().mode() == Mode.BUNGEEGUARD) { - logger.debug("BungeeGuard detected, applying pre-login post processor"); - HANDLERS.addFirst(BungeeGuard::validateToken); - } + // Modern forwarding init + if (this.forwarding().enabled() && this.forwarding().mode().isModern()) { + PayloadRegistry.register( + PlayerInfoQueryPayload.TYPE, + map(PlayerInfoQueryPayload.IDENTIFIER, MinecraftVersions.V7_2)); + } + + // BungeeGuard forwarding init + if (this.forwarding().enabled() && this.forwarding().mode() == Mode.BUNGEEGUARD) { + logger.debug("BungeeGuard detected, applying pre-login handler"); + HANDLERS.addFirst(BungeeGuard::validateToken); } Constraint.Evaluator.DEBUG = debug; From 01dab565195adb6485bdbb87db3467efbe2d5b2f Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Thu, 23 Apr 2026 01:04:04 -0600 Subject: [PATCH 44/71] Remove frivolous forwarding type checks --- .../java/org/adde0109/pcf/forwarding/PacketDecoder.java | 9 +++------ .../adde0109/pcf/forwarding/legacy/LegacyForwarding.java | 4 ---- .../adde0109/pcf/forwarding/modern/ModernForwarding.java | 4 ---- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 0ed1693d..5b7d6e42 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -38,8 +38,7 @@ protected void decode( switch (connection.bridge$protocol()) { case null -> {} case HANDSHAKING -> { - if (!(PCF.instance().forwarding().enabled() - && PCF.instance().forwarding().mode().isLegacy())) { + if (!PCF.instance().forwarding().mode().isLegacy()) { out.add(msg.retain()); return; } @@ -76,8 +75,7 @@ protected void decode( } case LOGIN -> { // TODO: Clean this up - if (PCF.instance().forwarding().enabled() - && PCF.instance().forwarding().mode().isLegacy()) { + if (PCF.instance().forwarding().mode().isLegacy()) { final int readerIndex = msg.readerIndex(); final FriendlyByteBuf data = new FriendlyByteBuf(msg); final int id = data.readVarInt(); @@ -102,8 +100,7 @@ protected void decode( break; } - if (!PCF.instance().forwarding().enabled() - || !PCF.instance().forwarding().mode().isModern()) { + if (!PCF.instance().forwarding().mode().isModern()) { out.add(msg.retain()); return; } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java index c5acbb09..40ed5880 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java @@ -166,10 +166,6 @@ private static boolean isFmlMarker(final @NonNull Property property) { public static void handleHello( final @NonNull ServerLoginPacketListenerBridge slpl, final @NonNull CallbackInfo ci) { - if (!(PCF.instance().forwarding().enabled() - && PCF.instance().forwarding().mode().isLegacy())) { - return; - } final GameProfile profile = createProfile(slpl.bridge$connection().bridge$channel()); // Proceed with login diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index ede7208a..daeb7682 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -62,10 +62,6 @@ public final class ModernForwarding { */ public static void handleHello( final @NonNull ServerLoginPacketListenerBridge slpl, final @NonNull CallbackInfo ci) { - if (!(PCF.instance().forwarding().enabled() - && PCF.instance().forwarding().mode().isModern())) { - return; - } final ConnectionBridge connection = slpl.bridge$connection(); final List approved = PCF.instance().forwarding().approvedProxyHosts(); From bc756e9dc67101c226ea8dae18570fc60c48f409 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Thu, 23 Apr 2026 01:16:21 -0600 Subject: [PATCH 45/71] Clean up PreLoginHandler init --- common/src/main/java/org/adde0109/pcf/PCF.java | 18 +++++++++--------- .../pcf/forwarding/PreLoginHandler.java | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/PCF.java b/common/src/main/java/org/adde0109/pcf/PCF.java index e9f29e3d..a288129e 100644 --- a/common/src/main/java/org/adde0109/pcf/PCF.java +++ b/common/src/main/java/org/adde0109/pcf/PCF.java @@ -17,6 +17,7 @@ import dev.neuralnexus.taterapi.network.PayloadRegistry; import org.adde0109.pcf.forwarding.Mode; +import org.adde0109.pcf.forwarding.PreLoginHandler; import org.adde0109.pcf.forwarding.bungeeguard.BungeeGuard; import org.adde0109.pcf.forwarding.compatibility.prelogin.ArclightPreLogin; import org.adde0109.pcf.forwarding.compatibility.prelogin.MohistPreLogin; @@ -85,18 +86,15 @@ void onInit() { if (Constraint.builder().platform(Platforms.ARCLIGHT).result()) { logger.debug("Arclight detected, applying pre-login handler"); if (Constraint.range(MinecraftVersions.V14, MinecraftVersions.V20_1).result()) { - HANDLERS.removeFirst(); HANDLERS.add( (slpl, profile, _) -> { slpl.bridge$setGameProfile(profile); ArclightPreLogin.V14.preLogin(slpl); }); } else if (Constraint.builder().version(MinecraftVersions.V20_2).result()) { - HANDLERS.removeFirst(); HANDLERS.add( (slpl, profile, _) -> ArclightPreLogin.V20_2.preLogin(slpl, profile)); } else if (Constraint.noLessThan(MinecraftVersions.V20_3).result()) { - HANDLERS.removeFirst(); HANDLERS.add( (slpl, profile, _) -> ArclightPreLogin.V20_4.preLogin(slpl, profile)); } @@ -105,7 +103,6 @@ void onInit() { .version(MinecraftVersions.V20_1) .result()) { logger.debug("Mohist detected, applying pre-login handler"); - HANDLERS.removeFirst(); HANDLERS.add( (slpl, profile, _) -> { slpl.bridge$setGameProfile(profile); @@ -116,7 +113,6 @@ void onInit() { .version(MinecraftVersions.V21_1) .result()) { logger.debug("Youer detected, applying pre-login handler"); - HANDLERS.removeFirst(); HANDLERS.add( (slpl, profile, _) -> { MohistPreLogin.Youer.fireEvents(slpl, profile); @@ -134,7 +130,6 @@ void onInit() { .version(MinecraftVersions.V20_1)) .result()) { logger.debug("Forge+Bukkit hybrid detected, applying pre-login handler"); - HANDLERS.removeFirst(); HANDLERS.add( (slpl, profile, _) -> { slpl.bridge$setGameProfile(profile); @@ -149,7 +144,6 @@ void onInit() { .version(MinecraftVersions.V20_2)) .result()) { logger.debug("[Neo]Forge+Bukkit hybrid detected, applying pre-login handler"); - HANDLERS.removeFirst(); HANDLERS.add((slpl, profile, _) -> SpigotPreLogin.V20_2.fireEvents(slpl, profile)); } else if (Constraints.builder() .or( @@ -166,9 +160,15 @@ void onInit() { .version(MinecraftVersions.V21_1, MinecraftVersions.V21_10)) .result()) { logger.debug("[Neo]Forge+Bukkit hybrid detected, applying pre-login handler"); - HANDLERS.addFirst( + HANDLERS.add( (slpl, profile, _) -> SpigotPreLogin.V20_5.callPlayerPreLoginEvents(slpl, profile)); + HANDLERS.add(PreLoginHandler.DEFAULT_HANDLER); + } + + // Serves both as a fallback and to populate the default + if (HANDLERS.isEmpty()) { + HANDLERS.add(PreLoginHandler.DEFAULT_HANDLER); } if (Constraint.range(MinecraftVersions.V16, MinecraftVersions.V18_2) @@ -192,7 +192,7 @@ void onInit() { // BungeeGuard forwarding init if (this.forwarding().enabled() && this.forwarding().mode() == Mode.BUNGEEGUARD) { - logger.debug("BungeeGuard detected, applying pre-login handler"); + logger.debug("Forwarding mode set to BungeeGuard, applying pre-login handler"); HANDLERS.addFirst(BungeeGuard::validateToken); } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PreLoginHandler.java b/common/src/main/java/org/adde0109/pcf/forwarding/PreLoginHandler.java index c3c5b2d8..0baf0075 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PreLoginHandler.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PreLoginHandler.java @@ -21,7 +21,7 @@ public interface PreLoginHandler { "UUID of player {} is {}", nameAndId.name(), nameAndId.id()); slpl.bridge$startClientVerification(profile); }; - @ApiStatus.Internal List HANDLERS = new ArrayList<>(List.of(DEFAULT_HANDLER)); + @ApiStatus.Internal List HANDLERS = new ArrayList<>(); /** * Process the forwarded profile From f69b2229b4e4cd4e837ebc47c0123a28f6e17354 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Thu, 23 Apr 2026 01:36:24 -0600 Subject: [PATCH 46/71] Pull handleHello mixins up a level and create a common delegate that invokes modern or legacy forwarding depending on the config --- .../adde0109/pcf/forwarding/Forwarding.java | 42 +++++++++++++++++++ ...ginPacketListenerImplHelloHybridMixin.java | 4 +- ...rverLoginPacketListenerImplHelloMixin.java | 4 +- ...rverLoginPacketListenerImplHelloMixin.java | 35 ---------------- .../src/main/resources/pcf.mixins.v26_1.json | 5 +-- ...rverLoginPacketListenerImplHelloMixin.java | 4 +- .../resources/pcf.mixins.v12_2.forge.json | 2 +- .../ServerLoginPacketListenerImplMixin.java | 2 +- ...rverLoginPacketListenerImplHelloMixin.java | 4 +- .../resources/pcf.mixins.v16_5.forge.json | 2 +- ...verLoginPacketListenerImplLoggerMixin.java | 2 +- .../resources/pcf.mixins.v17_1.forge.json | 2 +- 12 files changed, 57 insertions(+), 51 deletions(-) create mode 100644 common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java rename deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/{modern => }/ServerLoginPacketListenerImplHelloHybridMixin.java (94%) rename deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/{modern => }/ServerLoginPacketListenerImplHelloMixin.java (96%) delete mode 100644 deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java rename legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/{modern => }/ServerLoginPacketListenerImplHelloMixin.java (90%) rename modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/{modern => }/ServerLoginPacketListenerImplHelloMixin.java (94%) rename modern/v17_1/src/forge/java/org/adde0109/pcf/mixin/v17_1/forge/forwarding/{modern => }/ServerLoginPacketListenerImplLoggerMixin.java (95%) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java new file mode 100644 index 00000000..2294247f --- /dev/null +++ b/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java @@ -0,0 +1,42 @@ +package org.adde0109.pcf.forwarding; + +import static dev.neuralnexus.taterapi.network.chat.Component.translatable; + +import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; + +import org.adde0109.pcf.PCF; +import org.adde0109.pcf.forwarding.legacy.LegacyForwarding; +import org.adde0109.pcf.forwarding.modern.ModernForwarding; +import org.jspecify.annotations.NonNull; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +public final class Forwarding { + private static final Object FAILED_TO_VERIFY = + translatable("multiplayer.disconnect.unverified_username"); + + /** + * Abstract implementation of the hello packet handler + * + * @param slpl The ServerLoginPacketListenerImpl + * @param ci The callback info + */ + public static void handleHello( + final @NonNull ServerLoginPacketListenerBridge slpl, final @NonNull CallbackInfo ci) { + try { + switch (PCF.instance().forwarding().mode()) { + case LEGACY, BUNGEEGUARD -> LegacyForwarding.handleHello(slpl, ci); + case MODERN -> ModernForwarding.handleHello(slpl, ci); + } + } catch (final ThrowingComponent e) { + slpl.bridge$disconnect(e.getComponent()); + } catch (final Exception e) { + // final NameAndId nameAndId = new NameAndId(profile); + // PCF.logger.warn("Exception while forwarding user " + nameAndId.name()); + // throw new ThrowingComponent(FAILED_TO_VERIFY, e); + e.printStackTrace(); + slpl.bridge$disconnect(FAILED_TO_VERIFY); + } finally { + ci.cancel(); + } + } +} diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloHybridMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ServerLoginPacketListenerImplHelloHybridMixin.java similarity index 94% rename from deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloHybridMixin.java rename to deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ServerLoginPacketListenerImplHelloHybridMixin.java index a0b0fc3d..859901b4 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloHybridMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ServerLoginPacketListenerImplHelloHybridMixin.java @@ -1,6 +1,6 @@ -package org.adde0109.pcf.mixin.v26_1.forwarding.modern; +package org.adde0109.pcf.mixin.v26_1.forwarding; -import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleHello; +import static org.adde0109.pcf.forwarding.Forwarding.handleHello; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ServerLoginPacketListenerImplHelloMixin.java similarity index 96% rename from deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java rename to deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ServerLoginPacketListenerImplHelloMixin.java index 0e19a4ff..2d6d44c7 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ServerLoginPacketListenerImplHelloMixin.java @@ -1,6 +1,6 @@ -package org.adde0109.pcf.mixin.v26_1.forwarding.modern; +package org.adde0109.pcf.mixin.v26_1.forwarding; -import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleHello; +import static org.adde0109.pcf.forwarding.Forwarding.handleHello; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java deleted file mode 100644 index 76125a67..00000000 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/legacy/ServerLoginPacketListenerImplHelloMixin.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.adde0109.pcf.mixin.v26_1.forwarding.legacy; - -import dev.neuralnexus.taterapi.meta.Mappings; -import dev.neuralnexus.taterapi.meta.anno.AConstraint; -import dev.neuralnexus.taterapi.meta.anno.Versions; -import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; -import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; - -import net.minecraft.server.network.ServerLoginPacketListenerImpl; - -import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; -import org.adde0109.pcf.forwarding.legacy.LegacyForwarding; -import org.jspecify.annotations.NonNull; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -// https://hub.spigotmc.org/stash/projects/SPIGOT/repos/spigot/browse/CraftBukkit-Patches/0024-BungeeCord-Support.patch -@Mixin(ServerLoginPacketListenerImpl.class) -public abstract class ServerLoginPacketListenerImplHelloMixin - implements ServerLoginPacketListenerBridge { - // spotless:off - @AConstraint(mappings = Mappings.MOJANG, version = @Versions(min = MinecraftVersion.V20_2)) - @Inject(method = "handleHello", cancellable = true, at = @At(value = "INVOKE", ordinal = 1, - target = "Lnet/minecraft/server/network/ServerLoginPacketListenerImpl;startClientVerification(Lcom/mojang/authlib/GameProfile;)V")) - // spotless:on - private void onHandleHello_20_M(final @NonNull CallbackInfo ci) { - try { - LegacyForwarding.handleHello(this, ci); - } catch (final ThrowingComponent e) { - this.bridge$disconnect(e.getComponent()); - } - } -} diff --git a/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json b/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json index 9a4c345a..334c7601 100644 --- a/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json +++ b/deobsf/v26_1/src/main/resources/pcf.mixins.v26_1.json @@ -12,8 +12,7 @@ "v26_1.crossstich.ArgumentTypeInfoMixin", "v26_1.forwarding.ConnectionMixin", "v26_1.forwarding.ServerLoginPacketListenerImplMixin", - "v26_1.forwarding.legacy.ServerLoginPacketListenerImplHelloMixin", - "v26_1.forwarding.modern.ServerLoginPacketListenerImplHelloHybridMixin", - "v26_1.forwarding.modern.ServerLoginPacketListenerImplHelloMixin" + "v26_1.forwarding.ServerLoginPacketListenerImplHelloHybridMixin", + "v26_1.forwarding.ServerLoginPacketListenerImplHelloMixin" ] } diff --git a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ServerLoginPacketListenerImplHelloMixin.java similarity index 90% rename from legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java rename to legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ServerLoginPacketListenerImplHelloMixin.java index 568299df..c3d50b3f 100644 --- a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java +++ b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ServerLoginPacketListenerImplHelloMixin.java @@ -1,6 +1,6 @@ -package org.adde0109.pcf.mixin.v12_2.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v12_2.forge.forwarding; -import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleHello; +import static org.adde0109.pcf.forwarding.Forwarding.handleHello; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; diff --git a/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json b/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json index e85722f5..c23e0002 100644 --- a/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json +++ b/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json @@ -11,6 +11,6 @@ "v12_2.forge.forwarding.ConnectionMixin", "v12_2.forge.forwarding.ServerLoginPacketListenerImplMixin", "v12_2.forge.forwarding.ServerLoginPacketListenerImplMixin$SLPLIMixin_12", - "v12_2.forge.forwarding.modern.ServerLoginPacketListenerImplHelloMixin" + "v12_2.forge.forwarding.ServerLoginPacketListenerImplHelloMixin" ] } diff --git a/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ServerLoginPacketListenerImplMixin.java b/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ServerLoginPacketListenerImplMixin.java index 21bdd1af..60ca66af 100644 --- a/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ServerLoginPacketListenerImplMixin.java +++ b/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ServerLoginPacketListenerImplMixin.java @@ -1,6 +1,6 @@ package org.adde0109.pcf.mixin.v13_2.forge.forwarding; -import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleHello; +import static org.adde0109.pcf.forwarding.Forwarding.handleHello; import com.mojang.authlib.GameProfile; diff --git a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ServerLoginPacketListenerImplHelloMixin.java similarity index 94% rename from modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java rename to modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ServerLoginPacketListenerImplHelloMixin.java index 172f9e6c..b63946f2 100644 --- a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/modern/ServerLoginPacketListenerImplHelloMixin.java +++ b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ServerLoginPacketListenerImplHelloMixin.java @@ -1,6 +1,6 @@ -package org.adde0109.pcf.mixin.v16_5.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v16_5.forge.forwarding; -import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleHello; +import static org.adde0109.pcf.forwarding.Forwarding.handleHello; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; diff --git a/modern/v16_5/src/forge/resources/pcf.mixins.v16_5.forge.json b/modern/v16_5/src/forge/resources/pcf.mixins.v16_5.forge.json index 22288958..b61ea358 100644 --- a/modern/v16_5/src/forge/resources/pcf.mixins.v16_5.forge.json +++ b/modern/v16_5/src/forge/resources/pcf.mixins.v16_5.forge.json @@ -13,6 +13,6 @@ "v16_5.forge.crossstitch.CommandsPacketMixin", "v16_5.forge.forwarding.ConnectionMixin", "v16_5.forge.forwarding.ServerLoginPacketListenerImplMixin", - "v16_5.forge.forwarding.modern.ServerLoginPacketListenerImplHelloMixin" + "v16_5.forge.forwarding.ServerLoginPacketListenerImplHelloMixin" ] } diff --git a/modern/v17_1/src/forge/java/org/adde0109/pcf/mixin/v17_1/forge/forwarding/modern/ServerLoginPacketListenerImplLoggerMixin.java b/modern/v17_1/src/forge/java/org/adde0109/pcf/mixin/v17_1/forge/forwarding/ServerLoginPacketListenerImplLoggerMixin.java similarity index 95% rename from modern/v17_1/src/forge/java/org/adde0109/pcf/mixin/v17_1/forge/forwarding/modern/ServerLoginPacketListenerImplLoggerMixin.java rename to modern/v17_1/src/forge/java/org/adde0109/pcf/mixin/v17_1/forge/forwarding/ServerLoginPacketListenerImplLoggerMixin.java index a3c595dd..ce1441e0 100644 --- a/modern/v17_1/src/forge/java/org/adde0109/pcf/mixin/v17_1/forge/forwarding/modern/ServerLoginPacketListenerImplLoggerMixin.java +++ b/modern/v17_1/src/forge/java/org/adde0109/pcf/mixin/v17_1/forge/forwarding/ServerLoginPacketListenerImplLoggerMixin.java @@ -1,4 +1,4 @@ -package org.adde0109.pcf.mixin.v17_1.forge.forwarding.modern; +package org.adde0109.pcf.mixin.v17_1.forge.forwarding; import dev.neuralnexus.taterapi.meta.Mappings; import dev.neuralnexus.taterapi.meta.anno.AConstraint; diff --git a/modern/v17_1/src/forge/resources/pcf.mixins.v17_1.forge.json b/modern/v17_1/src/forge/resources/pcf.mixins.v17_1.forge.json index 5c783ef5..2fbab5ad 100644 --- a/modern/v17_1/src/forge/resources/pcf.mixins.v17_1.forge.json +++ b/modern/v17_1/src/forge/resources/pcf.mixins.v17_1.forge.json @@ -11,6 +11,6 @@ "v17_1.forge.crossstitch.ArgumentTypesAccessor", "v17_1.forge.crossstitch.ArgumentTypesEntryMixin", "v17_1.forge.crossstitch.CommandsPacketMixin", - "v17_1.forge.forwarding.modern.ServerLoginPacketListenerImplLoggerMixin" + "v17_1.forge.forwarding.ServerLoginPacketListenerImplLoggerMixin" ] } From 4bf230ca1e779dd59b37c448be8958f47a3b4bca Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Thu, 23 Apr 2026 03:19:01 -0600 Subject: [PATCH 47/71] Added bridge$disconnect to ConnectionBridge to allow for disconnects during handshake --- .../pcf/forwarding/ConnectionBridge.java | 13 +++++ .../adde0109/pcf/forwarding/Forwarding.java | 4 +- .../pcf/forwarding/PacketDecoder.java | 5 +- .../forwarding/modern/ModernForwarding.java | 2 +- .../v26_1/forwarding/ConnectionMixin.java | 7 +++ .../forge/forwarding/ConnectionMixin.java | 46 ++---------------- .../forge/forwarding/ConnectionMixin.java | 25 ++++++++++ .../resources/pcf.mixins.v7_10.forge.json | 1 + .../forge/forwarding/ConnectionMixin.java | 48 +++++++++++++++++++ .../resources/pcf.mixins.v13_2.forge.json | 1 + .../forge/forwarding/ConnectionMixin.java | 17 +++++-- .../forge/forwarding/ConnectionMixin.java | 4 +- .../forge/forwarding/ConnectionMixin.java | 7 +++ 13 files changed, 127 insertions(+), 53 deletions(-) create mode 100644 legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ConnectionMixin.java create mode 100644 modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ConnectionMixin.java diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java b/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java index 7df41abf..e0d60fdf 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java @@ -27,10 +27,23 @@ public interface ConnectionBridge { @Nullable Protocol bridge$protocol(); + @NonNull Object bridge$disconnectPacket(final @NonNull Object reason); + default void bridge$send(final @NonNull Object packet) { this.bridge$channel().writeAndFlush(packet).addListener(ConnectionBridge::errorListener); } + default void bridge$disconnect(final @NonNull Object reason) { + if (this.bridge$getPacketListener() instanceof ServerLoginPacketListenerBridge slpl) { + slpl.bridge$disconnect(reason); + return; + } + if (this.bridge$channel() != null && this.bridge$channel().isOpen()) { + this.bridge$send(this.bridge$disconnectPacket(reason)); + this.bridge$channel().close().awaitUninterruptibly(); + } + } + /** * Injects the packet encoder and decoder into the pipeline to handle login query packets * diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java index 2294247f..0cb0ea0e 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java @@ -28,13 +28,13 @@ public static void handleHello( case MODERN -> ModernForwarding.handleHello(slpl, ci); } } catch (final ThrowingComponent e) { - slpl.bridge$disconnect(e.getComponent()); + slpl.bridge$connection().bridge$disconnect(e.getComponent()); } catch (final Exception e) { // final NameAndId nameAndId = new NameAndId(profile); // PCF.logger.warn("Exception while forwarding user " + nameAndId.name()); // throw new ThrowingComponent(FAILED_TO_VERIFY, e); e.printStackTrace(); - slpl.bridge$disconnect(FAILED_TO_VERIFY); + slpl.bridge$connection().bridge$disconnect(FAILED_TO_VERIFY); } finally { ci.cancel(); } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 5b7d6e42..4f9ba639 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -62,8 +62,7 @@ protected void decode( try { handleClientIntentionPacket(connection, data); } catch (final ThrowingComponent e) { - throw e; - // connection.bridge$disconnect(e.getComponent()); + connection.bridge$disconnect(e.getComponent()); } finally { // Reset reader index and pass it along msg.readerIndex(readerIndex); @@ -139,7 +138,7 @@ protected void decode( try { handleCustomQueryPacket(slpl, packet); } catch (final ThrowingComponent e) { - slpl.bridge$disconnect(e.getComponent()); + slpl.bridge$connection().bridge$disconnect(e.getComponent()); } finally { msg.clear(); } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index daeb7682..9d42498b 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -76,7 +76,7 @@ public static void handleHello( + " (IP: " + ip + ")"); - slpl.bridge$disconnect(REJECTED_PROXY_ERR); + slpl.bridge$connection().bridge$disconnect(REJECTED_PROXY_ERR); ci.cancel(); return; } diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ConnectionMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ConnectionMixin.java index 0a96af26..d0fac8ae 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ConnectionMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ConnectionMixin.java @@ -6,6 +6,8 @@ import net.minecraft.network.Connection; import net.minecraft.network.PacketListener; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket; import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; @@ -47,4 +49,9 @@ public abstract class ConnectionMixin implements ConnectionBridge { } return Protocol.fromId(listener.protocol().id()); } + + @Override + public @NonNull Object bridge$disconnectPacket(final @NonNull Object reason) { + return new ClientboundLoginDisconnectPacket((Component) reason); + } } diff --git a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ConnectionMixin.java b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ConnectionMixin.java index 84609d2e..36c7b49e 100644 --- a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ConnectionMixin.java +++ b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ConnectionMixin.java @@ -4,58 +4,22 @@ import dev.neuralnexus.taterapi.meta.anno.AConstraint; import dev.neuralnexus.taterapi.meta.anno.Versions; import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; -import dev.neuralnexus.taterapi.network.Protocol; -import io.netty.util.AttributeKey; - -import net.minecraft.network.EnumConnectionState; -import net.minecraft.network.INetHandler; import net.minecraft.network.NetworkManager; +import net.minecraft.network.login.server.SPacketDisconnect; +import net.minecraft.util.text.ITextComponent; import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import java.net.InetSocketAddress; -import java.net.SocketAddress; @AConstraint( mappings = Mappings.SEARGE, - version = @Versions(min = MinecraftVersion.V7, max = MinecraftVersion.V12_2)) + version = @Versions(min = MinecraftVersion.V8, max = MinecraftVersion.V12_2)) @Mixin(NetworkManager.class) public abstract class ConnectionMixin implements ConnectionBridge { - // spotless:off - @Shadow private SocketAddress socketAddress; - @Shadow public abstract INetHandler shadow$getNetHandler(); - // spotless:on - - @Shadow @Final public static AttributeKey PROTOCOL_ATTRIBUTE_KEY; - - @Override - public @NonNull InetSocketAddress bridge$address() { - return (InetSocketAddress) this.socketAddress; - } - - @Override - public void bridge$address(final @NonNull InetSocketAddress address) { - this.socketAddress = address; - } - - @Override - public @Nullable Object bridge$getPacketListener() { - return this.shadow$getNetHandler(); - } - @Override - public Protocol bridge$protocol() { - final INetHandler listener = this.shadow$getNetHandler(); - if (listener == null) { - return null; - } - return Protocol.fromLegacyId( - this.bridge$channel().attr(PROTOCOL_ATTRIBUTE_KEY).get().getId()); + public @NonNull Object bridge$disconnectPacket(final @NonNull Object reason) { + return new SPacketDisconnect((ITextComponent) reason); } } diff --git a/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ConnectionMixin.java b/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ConnectionMixin.java new file mode 100644 index 00000000..b7f1c427 --- /dev/null +++ b/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ConnectionMixin.java @@ -0,0 +1,25 @@ +package org.adde0109.pcf.mixin.v7_10.forge.forwarding; + +import dev.neuralnexus.taterapi.meta.Mappings; +import dev.neuralnexus.taterapi.meta.anno.AConstraint; +import dev.neuralnexus.taterapi.meta.anno.Versions; +import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; + +import net.minecraft.network.NetworkManager; +import net.minecraft.network.login.server.S00PacketDisconnect; +import net.minecraft.util.IChatComponent; + +import org.adde0109.pcf.forwarding.ConnectionBridge; +import org.jspecify.annotations.NonNull; +import org.spongepowered.asm.mixin.Mixin; + +@AConstraint( + mappings = Mappings.SEARGE, + version = @Versions(min = MinecraftVersion.V7, max = MinecraftVersion.V7_10)) +@Mixin(NetworkManager.class) +public abstract class ConnectionMixin implements ConnectionBridge { + @Override + public @NonNull Object bridge$disconnectPacket(final @NonNull Object reason) { + return new S00PacketDisconnect((IChatComponent) reason); + } +} diff --git a/legacy/v7_10/src/forge/resources/pcf.mixins.v7_10.forge.json b/legacy/v7_10/src/forge/resources/pcf.mixins.v7_10.forge.json index 9a947598..b622d1a4 100644 --- a/legacy/v7_10/src/forge/resources/pcf.mixins.v7_10.forge.json +++ b/legacy/v7_10/src/forge/resources/pcf.mixins.v7_10.forge.json @@ -8,6 +8,7 @@ "plugin": "org.adde0109.pcf.mixin.plugin.PCFMixinPlugin", "package": "org.adde0109.pcf.mixin", "server": [ + "v7_10.forge.forwarding.ConnectionMixin", "v7_10.forge.forwarding.MessageSerializerMixin", "v7_10.forge.forwarding.ServerLoginPacketListenerImplMixin" ] diff --git a/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ConnectionMixin.java b/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ConnectionMixin.java new file mode 100644 index 00000000..4d54a370 --- /dev/null +++ b/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ConnectionMixin.java @@ -0,0 +1,48 @@ +package org.adde0109.pcf.mixin.v13_2.forge.forwarding; + +import dev.neuralnexus.taterapi.meta.Mappings; +import dev.neuralnexus.taterapi.meta.anno.AConstraint; +import dev.neuralnexus.taterapi.meta.anno.Versions; +import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; +import dev.neuralnexus.taterapi.network.Protocol; + +import io.netty.util.AttributeKey; + +import net.minecraft.network.EnumConnectionState; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.login.server.SPacketDisconnectLogin; +import net.minecraft.util.text.ITextComponent; + +import org.adde0109.pcf.forwarding.ConnectionBridge; +import org.jspecify.annotations.NonNull; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@AConstraint( + mappings = Mappings.SEARGE, + version = @Versions(min = MinecraftVersion.V7, max = MinecraftVersion.V13_2)) +@Mixin(NetworkManager.class) +public abstract class ConnectionMixin implements ConnectionBridge { + // spotless:off + @Shadow @Final public static AttributeKey PROTOCOL_ATTRIBUTE_KEY; + // spotless:on + + @Override + public Protocol bridge$protocol() { + final Object listener = this.bridge$getPacketListener(); + if (listener == null) { + return null; + } + return Protocol.fromLegacyId( + this.bridge$channel().attr(PROTOCOL_ATTRIBUTE_KEY).get().getId()); + } + + @AConstraint( + mappings = Mappings.SEARGE, + version = @Versions(min = MinecraftVersion.V13, max = MinecraftVersion.V13_2)) + @Override + public @NonNull Object bridge$disconnectPacket(final @NonNull Object reason) { + return new SPacketDisconnectLogin((ITextComponent) reason); + } +} diff --git a/modern/v13_2/src/forge/resources/pcf.mixins.v13_2.forge.json b/modern/v13_2/src/forge/resources/pcf.mixins.v13_2.forge.json index ecf6f0a0..8329255a 100644 --- a/modern/v13_2/src/forge/resources/pcf.mixins.v13_2.forge.json +++ b/modern/v13_2/src/forge/resources/pcf.mixins.v13_2.forge.json @@ -9,6 +9,7 @@ "package": "org.adde0109.pcf.mixin", "server": [ "v13_2.forge.crossstitch.CommandsPacketMixin", + "v13_2.forge.forwarding.ConnectionMixin", "v13_2.forge.forwarding.ServerLoginPacketListenerImplMixin" ] } diff --git a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ConnectionMixin.java b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ConnectionMixin.java index 246fe622..b13b17fe 100644 --- a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ConnectionMixin.java +++ b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ConnectionMixin.java @@ -11,6 +11,8 @@ import net.minecraft.network.Connection; import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.PacketListener; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket; import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; @@ -24,13 +26,15 @@ @AConstraint( mappings = Mappings.SEARGE, - version = @Versions(min = MinecraftVersion.V13, max = MinecraftVersion.V16_5)) + version = @Versions(min = MinecraftVersion.V7, max = MinecraftVersion.V16_5)) @Mixin(Connection.class) public abstract class ConnectionMixin implements ConnectionBridge { // spotless:off @Shadow private SocketAddress address; - @Shadow @Final public static AttributeKey ATTRIBUTE_PROTOCOL; @Shadow public abstract PacketListener shadow$getPacketListener(); + + @AConstraint(version = @Versions(min = MinecraftVersion.V14, max = MinecraftVersion.V16_5)) + @Shadow @Final public static AttributeKey ATTRIBUTE_PROTOCOL; // spotless:on @Override @@ -48,12 +52,19 @@ public abstract class ConnectionMixin implements ConnectionBridge { return this.shadow$getPacketListener(); } + @AConstraint(version = @Versions(min = MinecraftVersion.V14, max = MinecraftVersion.V16_5)) @Override public Protocol bridge$protocol() { - final PacketListener listener = this.shadow$getPacketListener(); + final Object listener = this.bridge$getPacketListener(); if (listener == null) { return null; } return Protocol.fromLegacyId(this.bridge$channel().attr(ATTRIBUTE_PROTOCOL).get().getId()); } + + @AConstraint(version = @Versions(min = MinecraftVersion.V14, max = MinecraftVersion.V16_5)) + @Override + public @NonNull Object bridge$disconnectPacket(final @NonNull Object reason) { + return new ClientboundLoginDisconnectPacket((Component) reason); + } } diff --git a/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/ConnectionMixin.java b/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/ConnectionMixin.java index 6791bd75..a15645ee 100644 --- a/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/ConnectionMixin.java +++ b/modern/v19_2/src/forge/java/org/adde0109/pcf/mixin/v19_2/forge/forwarding/ConnectionMixin.java @@ -10,7 +10,6 @@ import net.minecraft.network.Connection; import net.minecraft.network.ConnectionProtocol; -import net.minecraft.network.PacketListener; import org.adde0109.pcf.forwarding.ConnectionBridge; import org.spongepowered.asm.mixin.Final; @@ -24,12 +23,11 @@ public abstract class ConnectionMixin implements ConnectionBridge { // spotless:off @Shadow @Final public static AttributeKey ATTRIBUTE_PROTOCOL; - @Shadow public abstract PacketListener shadow$getPacketListener(); // spotless:on @Override public Protocol bridge$protocol() { - final PacketListener listener = this.shadow$getPacketListener(); + final Object listener = this.bridge$getPacketListener(); if (listener == null) { return null; } diff --git a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ConnectionMixin.java b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ConnectionMixin.java index e4d2e8bb..cdd51539 100644 --- a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ConnectionMixin.java +++ b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ConnectionMixin.java @@ -8,6 +8,8 @@ import net.minecraft.network.Connection; import net.minecraft.network.PacketListener; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket; import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; @@ -54,4 +56,9 @@ public abstract class ConnectionMixin implements ConnectionBridge { } return Protocol.fromId(listener.protocol().id()); } + + @Override + public @NonNull Object bridge$disconnectPacket(final @NonNull Object reason) { + return new ClientboundLoginDisconnectPacket((Component) reason); + } } From e742b782ddc8113357379ea70337249405fb9dc5 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Thu, 23 Apr 2026 06:04:03 -0600 Subject: [PATCH 48/71] Didn't work as expected due to handing the handshake too early, now deferring disconnects to handleHello --- .../adde0109/pcf/forwarding/Forwarding.java | 4 +- .../pcf/forwarding/PacketDecoder.java | 15 ++-- .../forwarding/legacy/LegacyForwarding.java | 81 ++++++++++++------- .../forwarding/modern/ModernForwarding.java | 2 +- 4 files changed, 59 insertions(+), 43 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java index 0cb0ea0e..2294247f 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java @@ -28,13 +28,13 @@ public static void handleHello( case MODERN -> ModernForwarding.handleHello(slpl, ci); } } catch (final ThrowingComponent e) { - slpl.bridge$connection().bridge$disconnect(e.getComponent()); + slpl.bridge$disconnect(e.getComponent()); } catch (final Exception e) { // final NameAndId nameAndId = new NameAndId(profile); // PCF.logger.warn("Exception while forwarding user " + nameAndId.name()); // throw new ThrowingComponent(FAILED_TO_VERIFY, e); e.printStackTrace(); - slpl.bridge$connection().bridge$disconnect(FAILED_TO_VERIFY); + slpl.bridge$disconnect(FAILED_TO_VERIFY); } finally { ci.cancel(); } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 4f9ba639..18f2fed4 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -59,14 +59,11 @@ protected void decode( "Handling ClientIntentionPacket from " + ctx.channel().remoteAddress()); - try { - handleClientIntentionPacket(connection, data); - } catch (final ThrowingComponent e) { - connection.bridge$disconnect(e.getComponent()); - } finally { - // Reset reader index and pass it along - msg.readerIndex(readerIndex); - } + // Rewrite the packet + handleClientIntentionPacket(connection, data); + + // Reset reader index and pass it along + msg.readerIndex(readerIndex); } // Reset reader index for unhandled packets default -> msg.readerIndex(readerIndex); @@ -138,7 +135,7 @@ protected void decode( try { handleCustomQueryPacket(slpl, packet); } catch (final ThrowingComponent e) { - slpl.bridge$connection().bridge$disconnect(e.getComponent()); + slpl.bridge$disconnect(e.getComponent()); } finally { msg.clear(); } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java index 40ed5880..e9174d0b 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java @@ -38,6 +38,7 @@ import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.Collection; import java.util.HashSet; @@ -50,6 +51,10 @@ public final class LegacyForwarding { private static final Object REJECTED_PROXY_ERR = literal("Unapproved proxy host."); + public static final AttributeKey DEFERRED_DISCONNECT = + AttributeKey.valueOf("pcf-deferred-disconnect"); + public static final AttributeKey FORWARDED_ADDRESS = + AttributeKey.valueOf("pcf-forwarded-address"); public static final AttributeKey PLAYER_NAME = AttributeKey.valueOf("pcf-player-name"); public static final AttributeKey SPOOFED_UUID = AttributeKey.valueOf("pcf-spoofed-uuid"); public static final AttributeKey> SPOOFED_PROFILE = @@ -74,63 +79,43 @@ public static void handleClientIntentionPacket( final @NonNull ConnectionBridge connection, final @NonNull FriendlyByteBuf data) { final int protocolVersion = data.readVarInt(); final String hostName = data.readUtf(Short.MAX_VALUE); - final int _ = data.readUnsignedShort(); + final int hostPort = data.readUnsignedShort(); final ClientIntent intention = ClientIntent.byId(data.readVarInt()); if (intention != ClientIntent.LOGIN) { return; } - - // Check if the connection is from an approved proxy - final List approved = PCF.instance().forwarding().approvedProxyHosts(); - if (!approved.isEmpty()) { - final InetSocketAddress address = connection.bridge$address(); - final String host = address.getHostString(); - final String ip = address.getAddress().getHostAddress(); - if (!approved.contains(host) && !approved.contains(ip)) { - PCF.logger.warn( - "Rejected connection from unapproved proxy host: " - + host - + " (IP: " - + ip - + ")"); - throw new ThrowingComponent(REJECTED_PROXY_ERR); - } - } + final Channel channel = connection.bridge$channel(); final String[] split = hostName.split("\00"); if (split.length < 3 || !(HOST_PATTERN.matcher(split[1]).matches())) { - throw new ThrowingComponent(DIRECT_CONNECT_ERR); + channel.attr(DEFERRED_DISCONNECT).set(DIRECT_CONNECT_ERR); + return; } if (PCF.instance().forwarding().mode() == Mode.BUNGEEGUARD && (split.length < 4 || !split[3].contains(BUNGEE_GUARD_TOKEN_PROPERTY_NAME))) { - throw new ThrowingComponent(BG_CONFIG_ERR); + channel.attr(DEFERRED_DISCONNECT).set(BG_CONFIG_ERR); } final String originalHost = split[0]; final String forwardedAddress = split[1]; final UUID uuid = fromStringLenient(split[2]); - PCF.logger.debug( - "Player " + uuid + " is connecting with forwarded address " + forwardedAddress); - // Update the proxied address - final int port = connection.bridge$address().getPort(); - final InetSocketAddress address = - new InetSocketAddress(InetAddresses.forString(forwardedAddress), port); - connection.bridge$address(address); + // Save the forwarded address + channel.attr(FORWARDED_ADDRESS).set(InetAddresses.forString(forwardedAddress)); // Save the UUID - connection.bridge$channel().attr(SPOOFED_UUID).set(uuid); + channel.attr(SPOOFED_UUID).set(uuid); // Save the properties if present final Optional fmlMarker; - if (split.length == 4) { + if (split.length >= 4) { final String profileJSON = split[3]; final List properties = GSON.fromJson(profileJSON, profileTypeToken); // Pop out the FML marker if present fmlMarker = properties.stream().filter(LegacyForwarding::isFmlMarker).findFirst(); properties.removeIf(LegacyForwarding::isFmlMarker); - connection.bridge$channel().attr(SPOOFED_PROFILE).set(properties); + channel.attr(SPOOFED_PROFILE).set(properties); } else { fmlMarker = Optional.empty(); } @@ -144,7 +129,7 @@ public static void handleClientIntentionPacket( // Write the original address back into packet final ClientIntentionPacket newPacket = - new ClientIntentionPacket(protocolVersion, host, port, intention); + new ClientIntentionPacket(protocolVersion, host, hostPort, intention); data.clear(); data.writeVarInt(0x00); ClientIntentionPacket.STREAM_CODEC.encode(data, newPacket); @@ -166,6 +151,40 @@ private static boolean isFmlMarker(final @NonNull Property property) { public static void handleHello( final @NonNull ServerLoginPacketListenerBridge slpl, final @NonNull CallbackInfo ci) { + final ConnectionBridge connection = slpl.bridge$connection(); + final Channel channel = connection.bridge$channel(); + + // Handle any deferred disconnects from the handshake phase + final Object deferredDisconnect = channel.attr(DEFERRED_DISCONNECT).getAndSet(null); + if (deferredDisconnect != null) { + slpl.bridge$disconnect(deferredDisconnect); + return; + } + + // Check if the connection is from an approved proxy + final List approved = PCF.instance().forwarding().approvedProxyHosts(); + if (!approved.isEmpty()) { + final InetSocketAddress address = connection.bridge$address(); + final String host = address.getHostString(); + final String ip = address.getAddress().getHostAddress(); + if (!approved.contains(host) && !approved.contains(ip)) { + PCF.logger.warn( + "Rejected connection from unapproved proxy host: " + + host + + " (IP: " + + ip + + ")"); + throw new ThrowingComponent(REJECTED_PROXY_ERR); + } + } + + // Update the address to the forwarded address + final InetAddress address = connection.bridge$channel().attr(FORWARDED_ADDRESS).get(); + final int port = connection.bridge$address().getPort(); + final InetSocketAddress socketAddress = new InetSocketAddress(address, port); + connection.bridge$address(socketAddress); + + // Create the profile final GameProfile profile = createProfile(slpl.bridge$connection().bridge$channel()); // Proceed with login diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index 9d42498b..daeb7682 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -76,7 +76,7 @@ public static void handleHello( + " (IP: " + ip + ")"); - slpl.bridge$connection().bridge$disconnect(REJECTED_PROXY_ERR); + slpl.bridge$disconnect(REJECTED_PROXY_ERR); ci.cancel(); return; } From 65c894b96b0421b8037e5238d102ff83c0559e8f Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Thu, 23 Apr 2026 06:08:02 -0600 Subject: [PATCH 49/71] Removed ConnectionBridge disconnect helper method --- .../pcf/forwarding/ConnectionBridge.java | 13 ---------- .../v26_1/forwarding/ConnectionMixin.java | 7 ------ .../forge/forwarding/ConnectionMixin.java | 25 ------------------- .../resources/pcf.mixins.v12_2.forge.json | 1 - .../forge/forwarding/ConnectionMixin.java | 25 ------------------- .../resources/pcf.mixins.v7_10.forge.json | 1 - .../forge/forwarding/ConnectionMixin.java | 11 -------- .../forge/forwarding/ConnectionMixin.java | 8 ------ .../forge/forwarding/ConnectionMixin.java | 7 ------ 9 files changed, 98 deletions(-) delete mode 100644 legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ConnectionMixin.java delete mode 100644 legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ConnectionMixin.java diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java b/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java index e0d60fdf..7df41abf 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java @@ -27,23 +27,10 @@ public interface ConnectionBridge { @Nullable Protocol bridge$protocol(); - @NonNull Object bridge$disconnectPacket(final @NonNull Object reason); - default void bridge$send(final @NonNull Object packet) { this.bridge$channel().writeAndFlush(packet).addListener(ConnectionBridge::errorListener); } - default void bridge$disconnect(final @NonNull Object reason) { - if (this.bridge$getPacketListener() instanceof ServerLoginPacketListenerBridge slpl) { - slpl.bridge$disconnect(reason); - return; - } - if (this.bridge$channel() != null && this.bridge$channel().isOpen()) { - this.bridge$send(this.bridge$disconnectPacket(reason)); - this.bridge$channel().close().awaitUninterruptibly(); - } - } - /** * Injects the packet encoder and decoder into the pipeline to handle login query packets * diff --git a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ConnectionMixin.java b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ConnectionMixin.java index d0fac8ae..0a96af26 100644 --- a/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ConnectionMixin.java +++ b/deobsf/v26_1/src/main/java/org/adde0109/pcf/mixin/v26_1/forwarding/ConnectionMixin.java @@ -6,8 +6,6 @@ import net.minecraft.network.Connection; import net.minecraft.network.PacketListener; -import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket; import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; @@ -49,9 +47,4 @@ public abstract class ConnectionMixin implements ConnectionBridge { } return Protocol.fromId(listener.protocol().id()); } - - @Override - public @NonNull Object bridge$disconnectPacket(final @NonNull Object reason) { - return new ClientboundLoginDisconnectPacket((Component) reason); - } } diff --git a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ConnectionMixin.java b/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ConnectionMixin.java deleted file mode 100644 index 36c7b49e..00000000 --- a/legacy/v12_2/src/forge/java/org/adde0109/pcf/mixin/v12_2/forge/forwarding/ConnectionMixin.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.adde0109.pcf.mixin.v12_2.forge.forwarding; - -import dev.neuralnexus.taterapi.meta.Mappings; -import dev.neuralnexus.taterapi.meta.anno.AConstraint; -import dev.neuralnexus.taterapi.meta.anno.Versions; -import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; - -import net.minecraft.network.NetworkManager; -import net.minecraft.network.login.server.SPacketDisconnect; -import net.minecraft.util.text.ITextComponent; - -import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.jspecify.annotations.NonNull; -import org.spongepowered.asm.mixin.Mixin; - -@AConstraint( - mappings = Mappings.SEARGE, - version = @Versions(min = MinecraftVersion.V8, max = MinecraftVersion.V12_2)) -@Mixin(NetworkManager.class) -public abstract class ConnectionMixin implements ConnectionBridge { - @Override - public @NonNull Object bridge$disconnectPacket(final @NonNull Object reason) { - return new SPacketDisconnect((ITextComponent) reason); - } -} diff --git a/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json b/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json index c23e0002..996f37cd 100644 --- a/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json +++ b/legacy/v12_2/src/forge/resources/pcf.mixins.v12_2.forge.json @@ -8,7 +8,6 @@ "plugin": "org.adde0109.pcf.mixin.plugin.PCFMixinPlugin", "package": "org.adde0109.pcf.mixin", "server": [ - "v12_2.forge.forwarding.ConnectionMixin", "v12_2.forge.forwarding.ServerLoginPacketListenerImplMixin", "v12_2.forge.forwarding.ServerLoginPacketListenerImplMixin$SLPLIMixin_12", "v12_2.forge.forwarding.ServerLoginPacketListenerImplHelloMixin" diff --git a/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ConnectionMixin.java b/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ConnectionMixin.java deleted file mode 100644 index b7f1c427..00000000 --- a/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ConnectionMixin.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.adde0109.pcf.mixin.v7_10.forge.forwarding; - -import dev.neuralnexus.taterapi.meta.Mappings; -import dev.neuralnexus.taterapi.meta.anno.AConstraint; -import dev.neuralnexus.taterapi.meta.anno.Versions; -import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; - -import net.minecraft.network.NetworkManager; -import net.minecraft.network.login.server.S00PacketDisconnect; -import net.minecraft.util.IChatComponent; - -import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.jspecify.annotations.NonNull; -import org.spongepowered.asm.mixin.Mixin; - -@AConstraint( - mappings = Mappings.SEARGE, - version = @Versions(min = MinecraftVersion.V7, max = MinecraftVersion.V7_10)) -@Mixin(NetworkManager.class) -public abstract class ConnectionMixin implements ConnectionBridge { - @Override - public @NonNull Object bridge$disconnectPacket(final @NonNull Object reason) { - return new S00PacketDisconnect((IChatComponent) reason); - } -} diff --git a/legacy/v7_10/src/forge/resources/pcf.mixins.v7_10.forge.json b/legacy/v7_10/src/forge/resources/pcf.mixins.v7_10.forge.json index b622d1a4..9a947598 100644 --- a/legacy/v7_10/src/forge/resources/pcf.mixins.v7_10.forge.json +++ b/legacy/v7_10/src/forge/resources/pcf.mixins.v7_10.forge.json @@ -8,7 +8,6 @@ "plugin": "org.adde0109.pcf.mixin.plugin.PCFMixinPlugin", "package": "org.adde0109.pcf.mixin", "server": [ - "v7_10.forge.forwarding.ConnectionMixin", "v7_10.forge.forwarding.MessageSerializerMixin", "v7_10.forge.forwarding.ServerLoginPacketListenerImplMixin" ] diff --git a/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ConnectionMixin.java b/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ConnectionMixin.java index 4d54a370..3f86b0c4 100644 --- a/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ConnectionMixin.java +++ b/modern/v13_2/src/forge/java/org/adde0109/pcf/mixin/v13_2/forge/forwarding/ConnectionMixin.java @@ -10,11 +10,8 @@ import net.minecraft.network.EnumConnectionState; import net.minecraft.network.NetworkManager; -import net.minecraft.network.login.server.SPacketDisconnectLogin; -import net.minecraft.util.text.ITextComponent; import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -37,12 +34,4 @@ public abstract class ConnectionMixin implements ConnectionBridge { return Protocol.fromLegacyId( this.bridge$channel().attr(PROTOCOL_ATTRIBUTE_KEY).get().getId()); } - - @AConstraint( - mappings = Mappings.SEARGE, - version = @Versions(min = MinecraftVersion.V13, max = MinecraftVersion.V13_2)) - @Override - public @NonNull Object bridge$disconnectPacket(final @NonNull Object reason) { - return new SPacketDisconnectLogin((ITextComponent) reason); - } } diff --git a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ConnectionMixin.java b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ConnectionMixin.java index b13b17fe..9fe073d3 100644 --- a/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ConnectionMixin.java +++ b/modern/v16_5/src/forge/java/org/adde0109/pcf/mixin/v16_5/forge/forwarding/ConnectionMixin.java @@ -11,8 +11,6 @@ import net.minecraft.network.Connection; import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.PacketListener; -import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket; import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; @@ -61,10 +59,4 @@ public abstract class ConnectionMixin implements ConnectionBridge { } return Protocol.fromLegacyId(this.bridge$channel().attr(ATTRIBUTE_PROTOCOL).get().getId()); } - - @AConstraint(version = @Versions(min = MinecraftVersion.V14, max = MinecraftVersion.V16_5)) - @Override - public @NonNull Object bridge$disconnectPacket(final @NonNull Object reason) { - return new ClientboundLoginDisconnectPacket((Component) reason); - } } diff --git a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ConnectionMixin.java b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ConnectionMixin.java index cdd51539..e4d2e8bb 100644 --- a/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ConnectionMixin.java +++ b/modern/v20_4/src/forge/java/org/adde0109/pcf/mixin/v20_4/forge/forwarding/ConnectionMixin.java @@ -8,8 +8,6 @@ import net.minecraft.network.Connection; import net.minecraft.network.PacketListener; -import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket; import org.adde0109.pcf.forwarding.ConnectionBridge; import org.jspecify.annotations.NonNull; @@ -56,9 +54,4 @@ public abstract class ConnectionMixin implements ConnectionBridge { } return Protocol.fromId(listener.protocol().id()); } - - @Override - public @NonNull Object bridge$disconnectPacket(final @NonNull Object reason) { - return new ClientboundLoginDisconnectPacket((Component) reason); - } } From b13f4ff09f467acbba5a10fa8b54762b0a3f60e4 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Thu, 23 Apr 2026 08:08:04 -0600 Subject: [PATCH 50/71] Cleaned up forwarding impls and pulled out common code --- .../adde0109/pcf/forwarding/Forwarding.java | 83 +++++++- .../pcf/forwarding/PacketDecoder.java | 8 +- .../forwarding/bungeeguard/BungeeGuard.java | 13 +- .../forwarding/legacy/LegacyForwarding.java | 187 +++++++++--------- .../forwarding/modern/ModernForwarding.java | 74 ++----- 5 files changed, 206 insertions(+), 159 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java index 2294247f..7d0ffb46 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java @@ -1,7 +1,12 @@ package org.adde0109.pcf.forwarding; +import static dev.neuralnexus.taterapi.network.chat.Component.literal; import static dev.neuralnexus.taterapi.network.chat.Component.translatable; +import com.mojang.authlib.GameProfile; + +import dev.neuralnexus.taterapi.event.Cancellable; +import dev.neuralnexus.taterapi.mc.server.players.NameAndId; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; import org.adde0109.pcf.PCF; @@ -10,9 +15,16 @@ import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.Collection; + public final class Forwarding { + public static final Object PLAYER_INFO_ERR = literal("Unable to verify player details."); + private static final Object FAILED_TO_VERIFY = translatable("multiplayer.disconnect.unverified_username"); + private static final Object REJECTED_PROXY_ERR = literal("Unapproved proxy host."); /** * Abstract implementation of the hello packet handler @@ -30,13 +42,78 @@ public static void handleHello( } catch (final ThrowingComponent e) { slpl.bridge$disconnect(e.getComponent()); } catch (final Exception e) { - // final NameAndId nameAndId = new NameAndId(profile); - // PCF.logger.warn("Exception while forwarding user " + nameAndId.name()); - // throw new ThrowingComponent(FAILED_TO_VERIFY, e); e.printStackTrace(); slpl.bridge$disconnect(FAILED_TO_VERIFY); } finally { ci.cancel(); } } + + /** + * Checks if the connection is coming from an approved proxy host + * + * @param connection The connection + */ + public static void checkProxy(final @NonNull ConnectionBridge connection) { + final Collection approved = PCF.instance().forwarding().approvedProxyHosts(); + if (!approved.isEmpty()) { + final InetSocketAddress address = connection.bridge$address(); + final String host = address.getHostString(); + final String ip = address.getAddress().getHostAddress(); + if (!approved.contains(host) && !approved.contains(ip)) { + PCF.logger.warn( + "Rejected connection from unapproved proxy host: " + + host + + " (IP: " + + ip + + ")"); + throw new ThrowingComponent(REJECTED_PROXY_ERR); + } + } + } + + /** + * Set the connection's address to the forwarded address from the proxy. + * + * @param connection The connection + * @param forwardedAddress The forwarded address + */ + public static void ipForwarding( + final @NonNull ConnectionBridge connection, + final @NonNull InetAddress forwardedAddress) { + final int port = connection.bridge$address().getPort(); + final InetSocketAddress address = new InetSocketAddress(forwardedAddress, port); + connection.bridge$address(address); + } + + /** + * Pre-login handler that invokes registered {@link PreLoginHandler}s + * + * @param profile The player's GameProfile + * @param slpl The ServerLoginPacketListenerImpl + * @param c Cancellable + */ + public static void preLogin( + final @NonNull GameProfile profile, + final @NonNull ServerLoginPacketListenerBridge slpl, + final @NonNull Cancellable c) { + try { + final Cancellable cancellable = Cancellable.simple(); + for (final PreLoginHandler processor : PreLoginHandler.HANDLERS) { + processor.process(slpl, profile, cancellable); + if (cancellable.cancelled()) { + break; + } + } + } catch (final ThrowingComponent e) { + throw e; + } catch (final Exception e) { + final NameAndId nameAndId = new NameAndId(profile); + PCF.logger.warn("Exception while forwarding user " + nameAndId.name()); + e.printStackTrace(); + throw new ThrowingComponent(FAILED_TO_VERIFY, e); + } finally { + c.cancel(); + } + } } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 18f2fed4..36fc5e9d 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -2,9 +2,9 @@ import static org.adde0109.pcf.forwarding.ConnectionBridge.HANDLER_PACKET; import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.PLAYER_NAME; -import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.handleClientIntentionPacket; +import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.handleClientIntention; import static org.adde0109.pcf.forwarding.modern.ModernForwarding.LOGIN_MESSAGE_ID; -import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleCustomQueryPacket; +import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleCustomQueryAnswer; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; @@ -60,7 +60,7 @@ protected void decode( + ctx.channel().remoteAddress()); // Rewrite the packet - handleClientIntentionPacket(connection, data); + handleClientIntention(connection, data); // Reset reader index and pass it along msg.readerIndex(readerIndex); @@ -133,7 +133,7 @@ protected void decode( + ctx.channel().remoteAddress()); try { - handleCustomQueryPacket(slpl, packet); + handleCustomQueryAnswer(slpl, packet); } catch (final ThrowingComponent e) { slpl.bridge$disconnect(e.getComponent()); } finally { diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/bungeeguard/BungeeGuard.java b/common/src/main/java/org/adde0109/pcf/forwarding/bungeeguard/BungeeGuard.java index 6b54a839..abb75d9c 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/bungeeguard/BungeeGuard.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/bungeeguard/BungeeGuard.java @@ -16,7 +16,7 @@ import java.util.Collection; -// https://github.com/lucko/BungeeGuard +/** Adapted from BungeeGuard */ public final class BungeeGuard { public static final String BUNGEE_GUARD_TOKEN_PROPERTY_NAME = "bungeeguard-token"; public static final AttributeKey> BUNGEE_GUARD_TOKEN = @@ -26,10 +26,17 @@ public final class BungeeGuard { literal("&cUnable to authenticate - no data was forwarded by the proxy."); private static final Object INVALID_TOKEN = literal("&cUnable to authenticate."); + /** + * Validates the BungeeGuard token for the given connection + * + * @param slpl The ServerLoginPacketListenerImpl + * @param profile The player's GameProfile + * @param c Cancellable + */ public static void validateToken( final @NonNull ServerLoginPacketListenerBridge slpl, final @NonNull GameProfile profile, - final @NonNull Cancellable ignored) { + final @NonNull Cancellable c) { final NameAndId nameAndId = new NameAndId(profile); final String connectionDescription = nameAndId.id() + " @ " + slpl.bridge$connection().bridge$address().getHostString(); @@ -38,6 +45,7 @@ public static void validateToken( if (bungeeGuardTokens.size() > 1) { PCF.logger.warn( "Denying connection from " + connectionDescription + " - more than one token"); + c.cancel(); throw new ThrowingComponent(INVALID_TOKEN); } final String bungeeGuardToken = bungeeGuardTokens.stream().findFirst().orElse(null); @@ -47,6 +55,7 @@ public static void validateToken( final String reason = bungeeGuardToken == null ? "No Token" : "Invalid token"; PCF.logger.warn( "Denying connection from " + connectionDescription + " - reason: " + reason); + c.cancel(); throw new ThrowingComponent(bungeeGuardToken == null ? NO_DATA : INVALID_TOKEN); } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java index e9174d0b..ed0f2b8d 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java @@ -1,8 +1,8 @@ package org.adde0109.pcf.forwarding.legacy; import static dev.neuralnexus.taterapi.network.chat.Component.literal; -import static dev.neuralnexus.taterapi.network.chat.Component.translatable; +import static org.adde0109.pcf.forwarding.Forwarding.PLAYER_INFO_ERR; import static org.adde0109.pcf.forwarding.ReflectionUtils.getName; import static org.adde0109.pcf.forwarding.ReflectionUtils.getProperties; import static org.adde0109.pcf.forwarding.ReflectionUtils.getValue; @@ -18,10 +18,9 @@ import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; -import dev.neuralnexus.taterapi.event.Cancellable; -import dev.neuralnexus.taterapi.mc.server.players.NameAndId; import dev.neuralnexus.taterapi.meta.Constraint; import dev.neuralnexus.taterapi.meta.MinecraftVersions; +import dev.neuralnexus.taterapi.mixin.CancellableMixin; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; import dev.neuralnexus.taterapi.network.protocol.handshake.ClientIntent; @@ -32,14 +31,14 @@ import org.adde0109.pcf.PCF; import org.adde0109.pcf.forwarding.ConnectionBridge; +import org.adde0109.pcf.forwarding.Forwarding; import org.adde0109.pcf.forwarding.Mode; -import org.adde0109.pcf.forwarding.PreLoginHandler; import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.net.InetAddress; -import java.net.InetSocketAddress; import java.util.Collection; import java.util.HashSet; import java.util.List; @@ -48,9 +47,13 @@ import java.util.UUID; import java.util.regex.Pattern; +/** + * Adapted from Spigot + * and BungeeForge + */ public final class LegacyForwarding { - private static final Object REJECTED_PROXY_ERR = literal("Unapproved proxy host."); - public static final AttributeKey DEFERRED_DISCONNECT = AttributeKey.valueOf("pcf-deferred-disconnect"); public static final AttributeKey FORWARDED_ADDRESS = @@ -60,23 +63,27 @@ public final class LegacyForwarding { public static final AttributeKey> SPOOFED_PROFILE = AttributeKey.valueOf("pcf-spoofed-profile"); - private static final char LEGACY_SEPARATOR = '\0'; + private static final Object LEGACY_DIRECT_CONNECT_ERR = + literal("This server requires you to connect with Velocity or BungeeCord."); + private static final Object BG_CONFIG_ERR = + literal("This server requires the proxy to be configured for BungeeGuard forwarding."); private static final Gson GSON = new GsonBuilder().create(); private static final TypeToken> profileTypeToken = new TypeToken<>() {}; private static final Pattern HOST_PATTERN = Pattern.compile("[0-9a-f.:]{0,45}"); + private static final Pattern PROP_PATTERN = Pattern.compile("\\w{0,16}"); + private static final char LEGACY_SEPARATOR = '\0'; - private static final Object DIRECT_CONNECT_ERR = // TODO: Consider two different messages - literal("This server requires you to connect with Velocity or BungeeCord."); - private static final Object BG_CONFIG_ERR = - literal("This server requires the proxy to be configured for BungeeGuard forwarding."); - private static final Object PLAYER_INFO_ERR = literal("Unable to verify player details."); - - // https://hub.spigotmc.org/stash/projects/SPIGOT/repos/spigot/browse/CraftBukkit-Patches/0024-BungeeCord-Support.patch - // https://github.com/caunt/BungeeForge/blob/1.20.2/src/main/java/ua/caunt/bungeeforge/mixin/network/protocol/handshake/ClientIntentionPacket.java#L51-L54 - public static void handleClientIntentionPacket( + /** + * Handle the client intention packet and extract player info + * + * @param connection The connection + * @param data The packet buffer + */ + public static void handleClientIntention( final @NonNull ConnectionBridge connection, final @NonNull FriendlyByteBuf data) { + // Read the original packet final int protocolVersion = data.readVarInt(); final String hostName = data.readUtf(Short.MAX_VALUE); final int hostPort = data.readUnsignedShort(); @@ -86,9 +93,10 @@ public static void handleClientIntentionPacket( } final Channel channel = connection.bridge$channel(); + // Parse the host name for forwarded data final String[] split = hostName.split("\00"); if (split.length < 3 || !(HOST_PATTERN.matcher(split[1]).matches())) { - channel.attr(DEFERRED_DISCONNECT).set(DIRECT_CONNECT_ERR); + channel.attr(DEFERRED_DISCONNECT).set(LEGACY_DIRECT_CONNECT_ERR); return; } if (PCF.instance().forwarding().mode() == Mode.BUNGEEGUARD @@ -100,19 +108,16 @@ public static void handleClientIntentionPacket( final String forwardedAddress = split[1]; final UUID uuid = fromStringLenient(split[2]); - // Save the forwarded address + // Save forwarded data channel.attr(FORWARDED_ADDRESS).set(InetAddresses.forString(forwardedAddress)); - - // Save the UUID channel.attr(SPOOFED_UUID).set(uuid); - // Save the properties if present final Optional fmlMarker; if (split.length >= 4) { final String profileJSON = split[3]; final List properties = GSON.fromJson(profileJSON, profileTypeToken); - // Pop out the FML marker if present + // Pop out the FML marker fmlMarker = properties.stream().filter(LegacyForwarding::isFmlMarker).findFirst(); properties.removeIf(LegacyForwarding::isFmlMarker); channel.attr(SPOOFED_PROFILE).set(properties); @@ -125,9 +130,10 @@ public static void handleClientIntentionPacket( + LEGACY_SEPARATOR + property.value().split("\u0001")[1] + LEGACY_SEPARATOR).orElse(originalHost); + PCF.logger.debug("Parsed forwarded data - Host: " + host + ", UUID: " + uuid); // spotless:on - // Write the original address back into packet + // Write the original address (and Forge marker) back into packet final ClientIntentionPacket newPacket = new ClientIntentionPacket(protocolVersion, host, hostPort, intention); data.clear(); @@ -135,20 +141,12 @@ public static void handleClientIntentionPacket( ClientIntentionPacket.STREAM_CODEC.encode(data, newPacket); } - private static @NonNull UUID fromStringLenient(final @NonNull String string) { - return UUID.fromString( - string.replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5")); - } - - // https://github.com/caunt/BungeeForge/blob/1.20.2/src/main/java/ua/caunt/bungeeforge/mixin/network/protocol/handshake/ClientIntentionPacket.java#L51-L54 - private static boolean isFmlMarker(final @NonNull Property property) { - return Objects.equals(property.name(), "extraData") - && property.value().startsWith("\u0001FORGE"); - } - - private static final Object FAILED_TO_VERIFY = - translatable("multiplayer.disconnect.unverified_username"); - + /** + * Hello packet handler for legacy forwarding + * + * @param slpl The ServerLoginPacketListenerImpl + * @param ci The callback info + */ public static void handleHello( final @NonNull ServerLoginPacketListenerBridge slpl, final @NonNull CallbackInfo ci) { final ConnectionBridge connection = slpl.bridge$connection(); @@ -157,72 +155,26 @@ public static void handleHello( // Handle any deferred disconnects from the handshake phase final Object deferredDisconnect = channel.attr(DEFERRED_DISCONNECT).getAndSet(null); if (deferredDisconnect != null) { - slpl.bridge$disconnect(deferredDisconnect); - return; + throw new ThrowingComponent(deferredDisconnect); } // Check if the connection is from an approved proxy - final List approved = PCF.instance().forwarding().approvedProxyHosts(); - if (!approved.isEmpty()) { - final InetSocketAddress address = connection.bridge$address(); - final String host = address.getHostString(); - final String ip = address.getAddress().getHostAddress(); - if (!approved.contains(host) && !approved.contains(ip)) { - PCF.logger.warn( - "Rejected connection from unapproved proxy host: " - + host - + " (IP: " - + ip - + ")"); - throw new ThrowingComponent(REJECTED_PROXY_ERR); - } - } - - // Update the address to the forwarded address - final InetAddress address = connection.bridge$channel().attr(FORWARDED_ADDRESS).get(); - final int port = connection.bridge$address().getPort(); - final InetSocketAddress socketAddress = new InetSocketAddress(address, port); - connection.bridge$address(socketAddress); - - // Create the profile - final GameProfile profile = createProfile(slpl.bridge$connection().bridge$channel()); - - // Proceed with login - try { - final Cancellable cancellable = Cancellable.simple(); - for (final PreLoginHandler processor : PreLoginHandler.HANDLERS) { - processor.process(slpl, profile, cancellable); - if (cancellable.cancelled()) { - break; - } - } - } catch (final ThrowingComponent e) { - throw e; - } catch (final Exception e) { - final NameAndId nameAndId = new NameAndId(profile); - PCF.logger.warn("Exception while forwarding user " + nameAndId.name()); - e.printStackTrace(); - throw new ThrowingComponent(FAILED_TO_VERIFY, e); - } finally { - ci.cancel(); - } - } + Forwarding.checkProxy(connection); - private static final Pattern PROP_PATTERN = Pattern.compile("\\w{0,16}"); + // Apply IP forwarding + final InetAddress address = channel.attr(FORWARDED_ADDRESS).get(); + Forwarding.ipForwarding(connection, address); - public static @NonNull GameProfile createProfile(final @NonNull Channel channel) { + // Query player info from channel final String name = channel.attr(PLAYER_NAME).getAndSet(null); final UUID uuid = channel.attr(SPOOFED_UUID).getAndSet(null); if (name == null || uuid == null) { throw new ThrowingComponent(PLAYER_INFO_ERR); } - final Collection properties = channel.attr(SPOOFED_PROFILE).getAndSet(null); // Check for BungeeGuard tokens - if (PCF.instance().forwarding().mode() == Mode.BUNGEEGUARD - && properties != null - && !properties.isEmpty()) { + if (PCF.instance().forwarding().mode() == Mode.BUNGEEGUARD && properties != null) { final Collection bungeeGuardTokens = new HashSet<>(); for (final Property property : properties) { if (getName(property).equals(BUNGEE_GUARD_TOKEN_PROPERTY_NAME)) { @@ -238,14 +190,60 @@ public static void handleHello( } // Create the profile + final GameProfile profile = createProfile(name, uuid, properties); + + // Proceed with login + Forwarding.preLogin(profile, slpl, new CancellableMixin(ci)); + } + + /** + * Parse a UUID from a string, leniently accepting both dashed and non-dashed formats + * + * @param string The string to parse + * @return The parsed UUID + */ + private static @NonNull UUID fromStringLenient(final @NonNull String string) { + return UUID.fromString( + string.replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5")); + } + + /** + * Check if a property is the FML marker used by Forge to indicate a modded client. + * + * @param property The property to check + * @return True if the property is the FML marker, false otherwise + */ + private static boolean isFmlMarker(final @NonNull Property property) { + return Objects.equals(property.name(), "extraData") + && property.value().startsWith("\u0001FORGE"); + } + + /** + * Creates a new GameProfile + * + * @param name The player's name + * @param uuid The player's UUID + * @param properties The player's properties, if any + * @return The created GameProfile + */ + public static @NonNull GameProfile createProfile( + final @NonNull String name, + final @NonNull UUID uuid, + final @Nullable Collection properties) { + // Exit early if there are no properties if (properties == null || properties.isEmpty()) { return new GameProfile(uuid, name); - // com.mojang:authlib:7.0.0 or newer - } else if (Constraint.noLessThan(MinecraftVersions.V21_9).result()) { + } + + // Filter out invalid properties + properties.removeIf(property -> !PROP_PATTERN.matcher(getName(property)).matches()); + + // Create the profile + if (Constraint.noLessThan(MinecraftVersions.V21_9) + .result()) { // com.mojang:authlib:7.0.0 or newer final ImmutableMultimap.Builder propertiesBuilder = ImmutableMultimap.builder(); for (final Property property : properties) { - if (!PROP_PATTERN.matcher(property.name()).matches()) continue; propertiesBuilder.put(property.name(), property); } return new GameProfile(uuid, name, new PropertyMap(propertiesBuilder.build())); @@ -253,7 +251,6 @@ public static void handleHello( final GameProfile profile = new GameProfile(uuid, name); final PropertyMap propertiesMap = getProperties(profile); for (final Property property : properties) { - if (!PROP_PATTERN.matcher(getName(property)).matches()) continue; propertiesMap.put(getName(property), property); } return profile; diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index daeb7682..4e0dde88 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -3,13 +3,13 @@ import static dev.neuralnexus.taterapi.network.chat.Component.literal; import static dev.neuralnexus.taterapi.network.chat.Component.translatable; +import static org.adde0109.pcf.forwarding.Forwarding.PLAYER_INFO_ERR; import static org.adde0109.pcf.forwarding.ReflectionUtils.enforceSecureProfile; import static org.adde0109.pcf.forwarding.modern.VelocityProxy.MODERN_MAX_VERSION; import static org.adde0109.pcf.forwarding.modern.VelocityProxy.PLAYER_INFO_PAYLOAD; import static org.adde0109.pcf.forwarding.modern.VelocityProxy.checkIntegrity; import dev.neuralnexus.taterapi.event.Cancellable; -import dev.neuralnexus.taterapi.mc.server.players.NameAndId; import dev.neuralnexus.taterapi.meta.Constraint; import dev.neuralnexus.taterapi.meta.MinecraftVersions; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; @@ -22,14 +22,12 @@ import org.adde0109.pcf.PCF; import org.adde0109.pcf.forwarding.ConnectionBridge; -import org.adde0109.pcf.forwarding.PreLoginHandler; +import org.adde0109.pcf.forwarding.Forwarding; import org.adde0109.pcf.forwarding.ServerLoginPacketListenerBridge; import org.jspecify.annotations.NonNull; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.net.InetSocketAddress; import java.security.InvalidKeyException; -import java.util.List; import java.util.concurrent.ThreadLocalRandom; /** @@ -52,10 +50,17 @@ public final class ModernForwarding { public static final AttributeKey LOGIN_MESSAGE_ID = AttributeKey.valueOf("pcf-login-message-id"); - private static final Object REJECTED_PROXY_ERR = literal("Unapproved proxy host."); + private static final Object MODERN_DIRECT_CONNECT_ERR = + literal("This server requires you to connect with Velocity."); + private static final Object EMPTY_PAYLOAD_ERR = + literal("Received empty player info payload from the proxy."); + private static final Object MISSING_PROFILE_PUBLIC_KEY = + translatable("multiplayer.disconnect.missing_public_key"); + private static final Object INVALID_SIGNATURE = + translatable("multiplayer.disconnect.invalid_public_key_signature"); /** - * Abstract implementation of the hello packet handler + * Hello packet handler for modern forwarding * * @param slpl The ServerLoginPacketListenerImpl * @param ci The callback info @@ -64,24 +69,10 @@ public static void handleHello( final @NonNull ServerLoginPacketListenerBridge slpl, final @NonNull CallbackInfo ci) { final ConnectionBridge connection = slpl.bridge$connection(); - final List approved = PCF.instance().forwarding().approvedProxyHosts(); - if (!approved.isEmpty()) { - final InetSocketAddress address = connection.bridge$address(); - final String host = address.getHostString(); - final String ip = address.getAddress().getHostAddress(); - if (!approved.contains(host) && !approved.contains(ip)) { - PCF.logger.warn( - "Rejected connection from unapproved proxy host: " - + host - + " (IP: " - + ip - + ")"); - slpl.bridge$disconnect(REJECTED_PROXY_ERR); - ci.cancel(); - return; - } - } + // Check if the connection is from an approved proxy + Forwarding.checkProxy(connection); + // Send forwarding request final int messageId = ThreadLocalRandom.current().nextInt(); connection.bridge$channel().attr(LOGIN_MESSAGE_ID).set(messageId); connection.bridge$send(new ClientboundCustomQueryPacket(messageId, PLAYER_INFO_PAYLOAD)); @@ -89,25 +80,13 @@ public static void handleHello( ci.cancel(); } - private static final Object DIRECT_CONNECT_ERR = - literal("This server requires you to connect with Velocity."); - private static final Object EMPTY_PAYLOAD_ERR = - literal("Received empty player info payload from the proxy."); - private static final Object PLAYER_INFO_ERR = literal("Unable to verify player details."); - private static final Object FAILED_TO_VERIFY = - translatable("multiplayer.disconnect.unverified_username"); - private static final Object MISSING_PROFILE_PUBLIC_KEY = - translatable("multiplayer.disconnect.missing_public_key"); - private static final Object INVALID_SIGNATURE = - translatable("multiplayer.disconnect.invalid_public_key_signature"); - /** - * Abstract implementation of the custom query packet handler + * CustomQueryAnswer packet handler for modern forwarding * * @param slpl The ServerLoginPacketListenerImpl * @param packet The Minecraft packet */ - public static void handleCustomQueryPacket( + public static void handleCustomQueryAnswer( final @NonNull ServerLoginPacketListenerBridge slpl, final @NonNull ServerboundCustomQueryAnswerPacket packet) { final CustomQueryAnswerPayload.Raw rawPayload = @@ -115,7 +94,7 @@ public static void handleCustomQueryPacket( // Validate payload presence if (rawPayload == null) { - throw new ThrowingComponent(DIRECT_CONNECT_ERR); + throw new ThrowingComponent(MODERN_DIRECT_CONNECT_ERR); } else if (rawPayload.data().readableBytes() == 0) { PCF.logger.error( "Received empty forwarding payload. Has Velocity been configured to use modern forwarding?"); @@ -162,9 +141,7 @@ public static void handleCustomQueryPacket( PCF.logger.debug("Using modern forwarding version: " + version); // Apply IP forwarding - final int port = slpl.bridge$connection().bridge$address().getPort(); - final InetSocketAddress address = new InetSocketAddress(payload.address(), port); - slpl.bridge$connection().bridge$address(address); + Forwarding.ipForwarding(slpl.bridge$connection(), payload.address()); // Handle profile key switch (version) { @@ -206,19 +183,6 @@ public static void handleCustomQueryPacket( } // Proceed with login - try { - final Cancellable cancellable = Cancellable.simple(); - for (final PreLoginHandler processor : PreLoginHandler.HANDLERS) { - processor.process(slpl, payload.profile(), cancellable); - if (cancellable.cancelled()) { - break; - } - } - } catch (final Exception e) { - final NameAndId nameAndId = new NameAndId(payload.profile()); - PCF.logger.warn("Exception while forwarding user " + nameAndId.name()); - e.printStackTrace(); - throw new ThrowingComponent(FAILED_TO_VERIFY, e); - } + Forwarding.preLogin(payload.profile(), slpl, Cancellable.simple()); } } From cb0dc9259dd2724031f8e1807ca1d063e48aa765 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Thu, 23 Apr 2026 21:48:53 -0600 Subject: [PATCH 51/71] Tidied things up some more --- .../adde0109/pcf/forwarding/Forwarding.java | 12 +- .../pcf/forwarding/PacketDecoder.java | 117 +++++++----------- .../forwarding/legacy/LegacyForwarding.java | 4 +- .../forwarding/modern/ModernForwarding.java | 23 +++- 4 files changed, 68 insertions(+), 88 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java index 7d0ffb46..33707b74 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java @@ -89,19 +89,17 @@ public static void ipForwarding( /** * Pre-login handler that invokes registered {@link PreLoginHandler}s * - * @param profile The player's GameProfile * @param slpl The ServerLoginPacketListenerImpl - * @param c Cancellable + * @param profile The player's GameProfile */ public static void preLogin( - final @NonNull GameProfile profile, final @NonNull ServerLoginPacketListenerBridge slpl, - final @NonNull Cancellable c) { + final @NonNull GameProfile profile) { + final Cancellable c = Cancellable.simple(); try { - final Cancellable cancellable = Cancellable.simple(); for (final PreLoginHandler processor : PreLoginHandler.HANDLERS) { - processor.process(slpl, profile, cancellable); - if (cancellable.cancelled()) { + processor.process(slpl, profile, c); + if (c.cancelled()) { break; } } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 36fc5e9d..8de12152 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -1,14 +1,15 @@ package org.adde0109.pcf.forwarding; +import static dev.neuralnexus.taterapi.network.protocol.login.ServerboundHelloPacket.MAX_NAME_LENGTH; + import static org.adde0109.pcf.forwarding.ConnectionBridge.HANDLER_PACKET; import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.PLAYER_NAME; import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.handleClientIntention; -import static org.adde0109.pcf.forwarding.modern.ModernForwarding.LOGIN_MESSAGE_ID; import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleCustomQueryAnswer; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; +import dev.neuralnexus.taterapi.network.Protocol; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; -import dev.neuralnexus.taterapi.network.protocol.login.ServerboundCustomQueryAnswerPacket; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; @@ -35,23 +36,30 @@ protected void decode( final ConnectionBridge connection = ((ConnectionBridge) ctx.channel().pipeline().get(HANDLER_PACKET)); + if (connection.bridge$protocol() != Protocol.HANDSHAKING + && connection.bridge$protocol() != Protocol.LOGIN) { + out.add(msg.retain()); + return; + } + + final int readerIndex = msg.readerIndex(); + final FriendlyByteBuf data = new FriendlyByteBuf(msg); + final int id = data.readVarInt(); + PCF.logger.debug( + "Received " + + connection.bridge$protocol() + + " packet with ID 0x" + + Integer.toHexString(id) + + " from " + + ctx.channel().remoteAddress()); + switch (connection.bridge$protocol()) { - case null -> {} case HANDSHAKING -> { if (!PCF.instance().forwarding().mode().isLegacy()) { - out.add(msg.retain()); - return; + msg.readerIndex(readerIndex); + break; } - final int readerIndex = msg.readerIndex(); - final FriendlyByteBuf data = new FriendlyByteBuf(msg); - final int id = data.readVarInt(); - PCF.logger.debug( - "Received packet with ID 0x" - + Integer.toHexString(id) - + " from " - + ctx.channel().remoteAddress()); - //noinspection SwitchStatementWithTooFewBranches switch (id) { case 0x00 -> { @@ -61,70 +69,35 @@ protected void decode( // Rewrite the packet handleClientIntention(connection, data); - - // Reset reader index and pass it along msg.readerIndex(readerIndex); } - // Reset reader index for unhandled packets default -> msg.readerIndex(readerIndex); } } case LOGIN -> { - // TODO: Clean this up - if (PCF.instance().forwarding().mode().isLegacy()) { - final int readerIndex = msg.readerIndex(); - final FriendlyByteBuf data = new FriendlyByteBuf(msg); - final int id = data.readVarInt(); - PCF.logger.debug( - "Received packet with ID 0x" - + Integer.toHexString(id) - + " from " - + ctx.channel().remoteAddress()); - - //noinspection SwitchStatementWithTooFewBranches - switch (id) { - case 0x00 -> { - PCF.logger.debug( - "Handling ServerBoundHello from " - + ctx.channel().remoteAddress()); - final String name = data.readUtf(16); - ctx.channel().attr(PLAYER_NAME).set(name); - msg.readerIndex(readerIndex); - } - default -> msg.readerIndex(readerIndex); - } - break; - } - - if (!PCF.instance().forwarding().mode().isModern()) { - out.add(msg.retain()); - return; - } - if (!(connection.bridge$getPacketListener() instanceof ServerLoginPacketListenerBridge slpl)) { - out.add(msg.retain()); - return; + msg.readerIndex(readerIndex); + break; } - final int readerIndex = msg.readerIndex(); - final FriendlyByteBuf data = new FriendlyByteBuf(msg); - final int id = data.readVarInt(); - PCF.logger.debug( - "Received packet with ID 0x" - + Integer.toHexString(id) - + " from " - + ctx.channel().remoteAddress()); - - //noinspection SwitchStatementWithTooFewBranches switch (id) { - case 0x02 -> { - final ServerboundCustomQueryAnswerPacket packet = - ServerboundCustomQueryAnswerPacket.STREAM_CODEC.decode(data); + case 0x00 -> { + if (!PCF.instance().forwarding().mode().isLegacy()) { + msg.readerIndex(readerIndex); + break; + } + PCF.logger.debug( + "Handling ServerBoundHelloPacket from " + + ctx.channel().remoteAddress()); - // Check if the packet should be handled - if (packet.transactionId() - != connection.bridge$channel().attr(LOGIN_MESSAGE_ID).get()) { + // Save player name + final String name = data.readUtf(MAX_NAME_LENGTH); + ctx.channel().attr(PLAYER_NAME).set(name); + msg.readerIndex(readerIndex); + } + case 0x02 -> { + if (!PCF.instance().forwarding().mode().isModern()) { msg.readerIndex(readerIndex); break; } @@ -132,22 +105,20 @@ protected void decode( "Handling ServerboundCustomQueryAnswerPacket from " + ctx.channel().remoteAddress()); + boolean handled = false; try { - handleCustomQueryAnswer(slpl, packet); + handled = handleCustomQueryAnswer(slpl, data); } catch (final ThrowingComponent e) { + handled = true; slpl.bridge$disconnect(e.getComponent()); } finally { - msg.clear(); + if (handled) msg.clear(); } } - // Reset reader index for unhandled packets default -> msg.readerIndex(readerIndex); } } - default -> { - out.add(msg.retain()); - return; - } + case null, default -> msg.readerIndex(readerIndex); } if (msg.isReadable()) { diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java index ed0f2b8d..50cea019 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java @@ -20,7 +20,6 @@ import dev.neuralnexus.taterapi.meta.Constraint; import dev.neuralnexus.taterapi.meta.MinecraftVersions; -import dev.neuralnexus.taterapi.mixin.CancellableMixin; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; import dev.neuralnexus.taterapi.network.protocol.handshake.ClientIntent; @@ -193,7 +192,8 @@ public static void handleHello( final GameProfile profile = createProfile(name, uuid, properties); // Proceed with login - Forwarding.preLogin(profile, slpl, new CancellableMixin(ci)); + ci.cancel(); + Forwarding.preLogin(slpl, profile); } /** diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index 4e0dde88..d05eec87 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -9,9 +9,9 @@ import static org.adde0109.pcf.forwarding.modern.VelocityProxy.PLAYER_INFO_PAYLOAD; import static org.adde0109.pcf.forwarding.modern.VelocityProxy.checkIntegrity; -import dev.neuralnexus.taterapi.event.Cancellable; import dev.neuralnexus.taterapi.meta.Constraint; import dev.neuralnexus.taterapi.meta.MinecraftVersions; +import dev.neuralnexus.taterapi.network.FriendlyByteBuf; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; import dev.neuralnexus.taterapi.network.protocol.login.ClientboundCustomQueryPacket; import dev.neuralnexus.taterapi.network.protocol.login.ServerboundCustomQueryAnswerPacket; @@ -84,11 +84,21 @@ public static void handleHello( * CustomQueryAnswer packet handler for modern forwarding * * @param slpl The ServerLoginPacketListenerImpl - * @param packet The Minecraft packet + * @param data The packet buffer */ - public static void handleCustomQueryAnswer( + public static boolean handleCustomQueryAnswer( final @NonNull ServerLoginPacketListenerBridge slpl, - final @NonNull ServerboundCustomQueryAnswerPacket packet) { + final @NonNull FriendlyByteBuf data) { + final ConnectionBridge connection = slpl.bridge$connection(); + final ServerboundCustomQueryAnswerPacket packet = + ServerboundCustomQueryAnswerPacket.STREAM_CODEC.decode(data); + + // Check if the packet should be handled + if (packet.transactionId() != connection.bridge$channel().attr(LOGIN_MESSAGE_ID).get()) { + return false; + } + + // Decode raw buffer final CustomQueryAnswerPayload.Raw rawPayload = packet.payload() instanceof CustomQueryAnswerPayload.Raw raw ? raw : null; @@ -141,7 +151,7 @@ public static void handleCustomQueryAnswer( PCF.logger.debug("Using modern forwarding version: " + version); // Apply IP forwarding - Forwarding.ipForwarding(slpl.bridge$connection(), payload.address()); + Forwarding.ipForwarding(connection, payload.address()); // Handle profile key switch (version) { @@ -183,6 +193,7 @@ public static void handleCustomQueryAnswer( } // Proceed with login - Forwarding.preLogin(payload.profile(), slpl, Cancellable.simple()); + Forwarding.preLogin(slpl, payload.profile()); + return true; } } From 9df36c843f7a7ae3ac8df46cdc613cc8d7d31819 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Thu, 23 Apr 2026 23:42:02 -0600 Subject: [PATCH 52/71] 1.7.10 doesn't have access to AttributeKey.valueOf --- .../pcf/forwarding/ReflectionUtils.java | 39 +++++++++++++++++++ .../forwarding/bungeeguard/BungeeGuard.java | 4 +- .../forwarding/legacy/LegacyForwarding.java | 11 +++--- .../forwarding/modern/ModernForwarding.java | 3 +- 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/ReflectionUtils.java b/common/src/main/java/org/adde0109/pcf/forwarding/ReflectionUtils.java index 0197fec1..359f4881 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/ReflectionUtils.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/ReflectionUtils.java @@ -7,6 +7,9 @@ import dev.neuralnexus.taterapi.meta.Constraint; import dev.neuralnexus.taterapi.meta.MetaAPI; import dev.neuralnexus.taterapi.meta.MinecraftVersions; +import dev.neuralnexus.taterapi.meta.enums.MinecraftVersion; + +import io.netty.util.AttributeKey; import net.minecraft.server.MinecraftServer; @@ -146,4 +149,40 @@ public static boolean enforceSecureProfile() { throw new RuntimeException(e); } } + + private static final MethodHandle ATTRIBUTE_KEY_VALUE_OF; + + static { + final MethodHandles.Lookup lookup = MethodHandles.lookup(); + MethodHandle attributeKeyValueOfHandle; + try { + if (Constraint.noLessThan(MinecraftVersion.V8).result()) { + final Class attributeKeyClass = Class.forName("io.netty.util.AttributeKey"); + attributeKeyValueOfHandle = + lookup.findStatic( + attributeKeyClass, + "valueOf", + MethodType.methodType(AttributeKey.class, String.class)); + } else { // Get old AttributeKey constructor: AttributeKey(String name) + final Class attributeKeyClass = Class.forName("io.netty.util.AttributeKey"); + //noinspection JavaLangInvokeHandleSignature + attributeKeyValueOfHandle = + lookup.findConstructor( + attributeKeyClass, MethodType.methodType(void.class, String.class)); + } + } catch (final Throwable e) { + throw new IllegalStateException( + "Failed to initialize AttributeKey.valueOf MethodHandle", e); + } + ATTRIBUTE_KEY_VALUE_OF = attributeKeyValueOfHandle; + } + + @SuppressWarnings("unchecked") + public static AttributeKey attributeKeyValueOf(final @NonNull String name) { + try { + return (AttributeKey) ATTRIBUTE_KEY_VALUE_OF.invokeExact(name); + } catch (final Throwable e) { + throw new IllegalStateException("Failed to create AttributeKey with name: " + name, e); + } + } } diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/bungeeguard/BungeeGuard.java b/common/src/main/java/org/adde0109/pcf/forwarding/bungeeguard/BungeeGuard.java index abb75d9c..77ca116d 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/bungeeguard/BungeeGuard.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/bungeeguard/BungeeGuard.java @@ -2,6 +2,8 @@ import static dev.neuralnexus.taterapi.network.chat.Component.literal; +import static org.adde0109.pcf.forwarding.ReflectionUtils.attributeKeyValueOf; + import com.mojang.authlib.GameProfile; import dev.neuralnexus.taterapi.event.Cancellable; @@ -20,7 +22,7 @@ public final class BungeeGuard { public static final String BUNGEE_GUARD_TOKEN_PROPERTY_NAME = "bungeeguard-token"; public static final AttributeKey> BUNGEE_GUARD_TOKEN = - AttributeKey.valueOf("pcf-bungeeguard-token"); + attributeKeyValueOf("pcf-bungeeguard-token"); private static final Object NO_DATA = literal("&cUnable to authenticate - no data was forwarded by the proxy."); diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java index 50cea019..46b13d2d 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java @@ -3,6 +3,7 @@ import static dev.neuralnexus.taterapi.network.chat.Component.literal; import static org.adde0109.pcf.forwarding.Forwarding.PLAYER_INFO_ERR; +import static org.adde0109.pcf.forwarding.ReflectionUtils.attributeKeyValueOf; import static org.adde0109.pcf.forwarding.ReflectionUtils.getName; import static org.adde0109.pcf.forwarding.ReflectionUtils.getProperties; import static org.adde0109.pcf.forwarding.ReflectionUtils.getValue; @@ -54,13 +55,13 @@ */ public final class LegacyForwarding { public static final AttributeKey DEFERRED_DISCONNECT = - AttributeKey.valueOf("pcf-deferred-disconnect"); + attributeKeyValueOf("pcf-deferred-disconnect"); public static final AttributeKey FORWARDED_ADDRESS = - AttributeKey.valueOf("pcf-forwarded-address"); - public static final AttributeKey PLAYER_NAME = AttributeKey.valueOf("pcf-player-name"); - public static final AttributeKey SPOOFED_UUID = AttributeKey.valueOf("pcf-spoofed-uuid"); + attributeKeyValueOf("pcf-forwarded-address"); + public static final AttributeKey PLAYER_NAME = attributeKeyValueOf("pcf-player-name"); + public static final AttributeKey SPOOFED_UUID = attributeKeyValueOf("pcf-spoofed-uuid"); public static final AttributeKey> SPOOFED_PROFILE = - AttributeKey.valueOf("pcf-spoofed-profile"); + attributeKeyValueOf("pcf-spoofed-profile"); private static final Object LEGACY_DIRECT_CONNECT_ERR = literal("This server requires you to connect with Velocity or BungeeCord."); diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index d05eec87..59d1caca 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -4,6 +4,7 @@ import static dev.neuralnexus.taterapi.network.chat.Component.translatable; import static org.adde0109.pcf.forwarding.Forwarding.PLAYER_INFO_ERR; +import static org.adde0109.pcf.forwarding.ReflectionUtils.attributeKeyValueOf; import static org.adde0109.pcf.forwarding.ReflectionUtils.enforceSecureProfile; import static org.adde0109.pcf.forwarding.modern.VelocityProxy.MODERN_MAX_VERSION; import static org.adde0109.pcf.forwarding.modern.VelocityProxy.PLAYER_INFO_PAYLOAD; @@ -48,7 +49,7 @@ */ public final class ModernForwarding { public static final AttributeKey LOGIN_MESSAGE_ID = - AttributeKey.valueOf("pcf-login-message-id"); + attributeKeyValueOf("pcf-login-message-id"); private static final Object MODERN_DIRECT_CONNECT_ERR = literal("This server requires you to connect with Velocity."); From 2b71205588067a5da9684e72df59774c83a9424e Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Fri, 24 Apr 2026 00:32:51 -0600 Subject: [PATCH 53/71] Fixed 1.7.10 chat component handling --- .../forge/forwarding/ServerLoginPacketListenerImplMixin.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ServerLoginPacketListenerImplMixin.java b/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ServerLoginPacketListenerImplMixin.java index 9702fc88..7ac1d8f4 100644 --- a/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ServerLoginPacketListenerImplMixin.java +++ b/legacy/v7_10/src/forge/java/org/adde0109/pcf/mixin/v7_10/forge/forwarding/ServerLoginPacketListenerImplMixin.java @@ -28,7 +28,8 @@ public abstract class ServerLoginPacketListenerImplMixin @Override public void bridge$disconnect(final @NonNull Object reason) { - this.shadow$closeConnection(((IChatComponent) reason).getFormattedText()); + // Note: IChatComponent.getFormattedText() is client-only + this.shadow$closeConnection(((IChatComponent) reason).getUnformattedTextForChat()); } @Override From a95d432b8311fabc4e2d3bfa5a999576234e13fc Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Sun, 26 Apr 2026 04:13:43 -0600 Subject: [PATCH 54/71] Setup online tests (to be reverted pre-merge) --- test/HeadlessMC/templates/server/ops.json | 6 ++++++ test/gradle.properties | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/test/HeadlessMC/templates/server/ops.json b/test/HeadlessMC/templates/server/ops.json index 45975348..8b00228c 100644 --- a/test/HeadlessMC/templates/server/ops.json +++ b/test/HeadlessMC/templates/server/ops.json @@ -4,5 +4,11 @@ "name": "dev", "level": 4, "bypassesPlayerLimit": false + }, + { + "uuid": "3cf69d1b-a45a-4c19-9ff7-ac1e3bafec6b", + "name": "metalcatian", + "level": 4, + "bypassesPlayerLimit": false } ] \ No newline at end of file diff --git a/test/gradle.properties b/test/gradle.properties index 6ecdb355..926ce8bc 100644 --- a/test/gradle.properties +++ b/test/gradle.properties @@ -1 +1 @@ -run_offline=true +run_offline=false From 9c271181f7756466f9524c37473abf7bc34b3f6f Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Sun, 26 Apr 2026 18:08:40 -0600 Subject: [PATCH 55/71] Bump TaterLibLite version to fix ffapi dual-platform detection when connector is not present --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 873a7cda..f570d05b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ netty = "4.1.128.Final" nightconfig = "3.8.4" shadow = "9.4.1" spotless = "8.4.0" -taterlib-lite = "0.3.0" +taterlib-lite = "0.3.1-SNAPSHOT" unimined = "1.3.16-SNAPSHOT" [libraries] From fed611eaca27762bf189d678c1e83e66851a5133 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Sun, 26 Apr 2026 18:09:10 -0600 Subject: [PATCH 56/71] Forgot to reset reader index when login query payload is unhandled --- .../java/org/adde0109/pcf/forwarding/PacketDecoder.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 8de12152..f6a0e53c 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -112,7 +112,11 @@ protected void decode( handled = true; slpl.bridge$disconnect(e.getComponent()); } finally { - if (handled) msg.clear(); + if (handled) { + msg.clear(); + } else { + msg.readerIndex(readerIndex); + } } } default -> msg.readerIndex(readerIndex); From 257d6b3913bf625d2943e164558e039241dbbc4e Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Sun, 26 Apr 2026 23:28:11 -0600 Subject: [PATCH 57/71] Added the ability to use either a JVM arg or env var to set the forwarding mode, making testing easier --- .../src/main/java/org/adde0109/pcf/PCF.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/common/src/main/java/org/adde0109/pcf/PCF.java b/common/src/main/java/org/adde0109/pcf/PCF.java index a288129e..dbfeb600 100644 --- a/common/src/main/java/org/adde0109/pcf/PCF.java +++ b/common/src/main/java/org/adde0109/pcf/PCF.java @@ -233,6 +233,30 @@ public Forwarding forwarding() { @ApiStatus.Internal public void setForwarding(final @NonNull Forwarding forwarding) { + final String modeProperty = System.getProperty("pcf.forwarding.mode"); + if (modeProperty != null) { + PCF.logger.debug("System property forwarding mode: " + modeProperty); + } + final String modeEnv = System.getenv("PCF_FORWARDING_MODE"); + if (modeEnv != null) { + PCF.logger.debug("Environment variable forwarding mode: " + modeEnv); + } + if (modeProperty != null || modeEnv != null) { + final String modeStr = modeEnv != null ? modeEnv : modeProperty; + try { + this.forwarding = + new Forwarding( + forwarding.enabled(), + Mode.valueOf(modeStr.toUpperCase()), + forwarding.secret(), + forwarding.approvedProxyHosts()); + return; + } catch (final IllegalArgumentException e) { + logger.warn( + "Invalid forwarding mode in environment variable, using config value", e); + } + } + this.forwarding = forwarding; } From d114d4a68c5833e810cdec5008904d016e24b0ea Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Sun, 26 Apr 2026 23:28:43 -0600 Subject: [PATCH 58/71] Overhauled the test system to support generating runs for modern, legacy, and bungeeguard forwarding --- .../velocity/bungeeguard/velocity.toml | 189 ++++++++++++++++++ .../velocity/{ => common}/forwarding.secret | 0 .../{ => common}/plugins/bStats/config.txt | 0 .../templates/velocity/legacy/velocity.toml | 189 ++++++++++++++++++ .../velocity/{ => modern}/velocity.toml | 4 +- test/build.gradle.kts | 128 +++++++----- 6 files changed, 458 insertions(+), 52 deletions(-) create mode 100644 test/HeadlessMC/templates/velocity/bungeeguard/velocity.toml rename test/HeadlessMC/templates/velocity/{ => common}/forwarding.secret (100%) rename test/HeadlessMC/templates/velocity/{ => common}/plugins/bStats/config.txt (100%) create mode 100644 test/HeadlessMC/templates/velocity/legacy/velocity.toml rename test/HeadlessMC/templates/velocity/{ => modern}/velocity.toml (99%) diff --git a/test/HeadlessMC/templates/velocity/bungeeguard/velocity.toml b/test/HeadlessMC/templates/velocity/bungeeguard/velocity.toml new file mode 100644 index 00000000..ab9f1538 --- /dev/null +++ b/test/HeadlessMC/templates/velocity/bungeeguard/velocity.toml @@ -0,0 +1,189 @@ +# Config version. Do not change this +config-version = "2.7" + +# What port should the proxy be bound to? By default, we'll bind to all addresses on port 25565. +bind = "0.0.0.0:25579" + +# What should be the MOTD? This gets displayed when the player adds your server to +# their server list. Only MiniMessage format is accepted. +motd = "<#09add3>A BungeeGuard Velocity Server" + +# What should we display for the maximum number of players? (Velocity does not support a cap +# on the number of players online.) +show-max-players = 500 + +# Should we authenticate players with Mojang? By default, this is on. +online-mode = false + +# Should the proxy enforce the new public key security standard? By default, this is on. +force-key-authentication = true + +# If client's ISP/AS sent from this proxy is different from the one from Mojang's +# authentication server, the player is kicked. This disallows some VPN and proxy +# connections but is a weak form of protection. +prevent-client-proxy-connections = false + +# Should we forward IP addresses and other data to backend servers? +# Available options: +# - "none": No forwarding will be done. All players will appear to be connecting +# from the proxy and will have offline-mode UUIDs. +# - "legacy": Forward player IPs and UUIDs in a BungeeCord-compatible format. Use this +# if you run servers using Minecraft 1.12 or lower. +# - "bungeeguard": Forward player IPs and UUIDs in a format supported by the BungeeGuard +# plugin. Use this if you run servers using Minecraft 1.12 or lower, and are +# unable to implement network level firewalling (on a shared host). +# - "modern": Forward player IPs and UUIDs as part of the login process using +# Velocity's native forwarding. Only applicable for Minecraft 1.13 or higher. +player-info-forwarding-mode = "BUNGEEGUARD" + +# If you are using modern or BungeeGuard IP forwarding, configure a file that contains a unique secret here. +# The file is expected to be UTF-8 encoded and not empty. +forwarding-secret-file = "forwarding.secret" + +# Announce whether or not your server supports Forge. If you run a modded server, we +# suggest turning this on. +# +# If your network runs one modpack consistently, consider using ping-passthrough = "mods" +# instead for a nicer display in the server list. +announce-forge = true + +# If enabled (default is false) and the proxy is in online mode, Velocity will kick +# any existing player who is online if a duplicate connection attempt is made. +kick-existing-players = false + +# Should Velocity pass server list ping requests to a backend server? +# Available options: +# - "disabled": No pass-through will be done. The velocity.toml and server-icon.png +# will determine the initial server list ping response. +# - "mods": Passes only the mod list from your backend server into the response. +# The first server in your try list (or forced host) with a mod list will be +# used. If no backend servers can be contacted, Velocity won't display any +# mod information. +# - "description": Uses the description and mod list from the backend server. The first +# server in the try (or forced host) list that responds is used for the +# description and mod list. +# - "all": Uses the backend server's response as the proxy response. The Velocity +# configuration is used if no servers could be contacted. +ping-passthrough = "MODS" + +# If enabled (default is false), then a sample of the online players on the proxy will be visible +# when hovering over the player count in the server list. +# This doesn't have any effect when ping passthrough is set to either "description" or "all". +sample-players-in-ping = false + +# If not enabled (default is true) player IP addresses will be replaced by in logs +enable-player-address-logging = true + +[packet-limiter] +interval = 7 +packets-per-second = 500 +bytes-per-second = -1 + +[servers] +# Configure your servers here. Each key represents the server's name, and the value +# represents the IP address of the server to connect to. +server1 = "127.0.0.1:25565" +server2 = "127.0.0.1:25565" + +# In what order we should try servers when a player logs in or is kicked from a server. +try = [ + "server1" +] + +[forced-hosts] +# Configure your forced hosts here. +"server1.example.com" = [ + "server1" +] + +[advanced] +# How large a Minecraft packet has to be before we compress it. Setting this to zero will +# compress all packets, and setting it to -1 will disable compression entirely. +compression-threshold = 256 + +# How much compression should be done (from 0-9). The default is -1, which uses the +# default level of 6. +compression-level = -1 + +# How fast (in milliseconds) are clients allowed to connect after the last connection? By +# default, this is three seconds. Disable this by setting this to 0. +login-ratelimit = 3000 + +# Specify a custom timeout for connection timeouts here. The default is five seconds. +connection-timeout = 5000 + +# Specify a read timeout for connections here. The default is 30 seconds. +read-timeout = 180000 + +# Enables compatibility with HAProxy's PROXY protocol. If you don't know what this is for, then +# don't enable it. +haproxy-protocol = false + +# Enables TCP fast open support on the proxy. Requires the proxy to run on Linux. +tcp-fast-open = false + +# Enables BungeeCord plugin messaging channel support on Velocity. +bungee-plugin-message-channel = true + +# Shows ping requests to the proxy from clients. +show-ping-requests = true + +# By default, Velocity will attempt to gracefully handle situations where the user unexpectedly +# loses connection to the server without an explicit disconnect message by attempting to fall the +# user back, except in the case of read timeouts. BungeeCord will disconnect the user instead. You +# can disable this setting to use the BungeeCord behavior. +failover-on-unexpected-server-disconnect = true + +# Declares the proxy commands to 1.13+ clients. +announce-proxy-commands = true + +# Enables the logging of commands +log-command-executions = true + +# Enables logging of player connections when connecting to the proxy, switching servers +# and disconnecting from the proxy. +log-player-connections = true + +# Allows players transferred from other hosts via the +# Transfer packet (Minecraft 1.20.5) to be received. +accepts-transfers = false + +# Enables support for SO_REUSEPORT. This may help the proxy scale better on multicore systems +# with a lot of incoming connections, and provide better CPU utilization than the existing +# strategy of having a single thread accepting connections and distributing them to worker +# threads. Disabled by default. Requires Linux or macOS. +enable-reuse-port = false + +# How fast (in milliseconds) are clients allowed to send commands after the last command +# By default this is 50ms (20 commands per second) +command-rate-limit = 50 + +# Should we forward commands to the backend upon being rate limited? +# This will forward the command to the server instead of processing it on the proxy. +# Since most server implementations have a rate limit, this will prevent the player +# from being able to send excessive commands to the server. +forward-commands-if-rate-limited = true + +# How many commands are allowed to be sent after the rate limit is hit before the player is kicked? +# Setting this to 0 or lower will disable this feature. +kick-after-rate-limited-commands = 0 + +# How fast (in milliseconds) are clients allowed to send tab completions after the last tab completion +tab-complete-rate-limit = 10 + +# How many tab completions are allowed to be sent after the rate limit is hit before the player is kicked? +# Setting this to 0 or lower will disable this feature. +kick-after-rate-limited-tab-completes = 0 + +[query] +# Whether to enable responding to GameSpy 4 query responses or not. +enabled = true + +# If query is enabled, on what port should the query protocol listen on? +port = 25579 + +# This is the map name that is reported to the query services. +map = "Velocity" + +# Whether plugins should be shown in query response by default or not +show-plugins = false diff --git a/test/HeadlessMC/templates/velocity/forwarding.secret b/test/HeadlessMC/templates/velocity/common/forwarding.secret similarity index 100% rename from test/HeadlessMC/templates/velocity/forwarding.secret rename to test/HeadlessMC/templates/velocity/common/forwarding.secret diff --git a/test/HeadlessMC/templates/velocity/plugins/bStats/config.txt b/test/HeadlessMC/templates/velocity/common/plugins/bStats/config.txt similarity index 100% rename from test/HeadlessMC/templates/velocity/plugins/bStats/config.txt rename to test/HeadlessMC/templates/velocity/common/plugins/bStats/config.txt diff --git a/test/HeadlessMC/templates/velocity/legacy/velocity.toml b/test/HeadlessMC/templates/velocity/legacy/velocity.toml new file mode 100644 index 00000000..3c186cd8 --- /dev/null +++ b/test/HeadlessMC/templates/velocity/legacy/velocity.toml @@ -0,0 +1,189 @@ +# Config version. Do not change this +config-version = "2.7" + +# What port should the proxy be bound to? By default, we'll bind to all addresses on port 25565. +bind = "0.0.0.0:25578" + +# What should be the MOTD? This gets displayed when the player adds your server to +# their server list. Only MiniMessage format is accepted. +motd = "<#09add3>A Legacy Velocity Server" + +# What should we display for the maximum number of players? (Velocity does not support a cap +# on the number of players online.) +show-max-players = 500 + +# Should we authenticate players with Mojang? By default, this is on. +online-mode = false + +# Should the proxy enforce the new public key security standard? By default, this is on. +force-key-authentication = true + +# If client's ISP/AS sent from this proxy is different from the one from Mojang's +# authentication server, the player is kicked. This disallows some VPN and proxy +# connections but is a weak form of protection. +prevent-client-proxy-connections = false + +# Should we forward IP addresses and other data to backend servers? +# Available options: +# - "none": No forwarding will be done. All players will appear to be connecting +# from the proxy and will have offline-mode UUIDs. +# - "legacy": Forward player IPs and UUIDs in a BungeeCord-compatible format. Use this +# if you run servers using Minecraft 1.12 or lower. +# - "bungeeguard": Forward player IPs and UUIDs in a format supported by the BungeeGuard +# plugin. Use this if you run servers using Minecraft 1.12 or lower, and are +# unable to implement network level firewalling (on a shared host). +# - "modern": Forward player IPs and UUIDs as part of the login process using +# Velocity's native forwarding. Only applicable for Minecraft 1.13 or higher. +player-info-forwarding-mode = "LEGACY" + +# If you are using modern or BungeeGuard IP forwarding, configure a file that contains a unique secret here. +# The file is expected to be UTF-8 encoded and not empty. +forwarding-secret-file = "forwarding.secret" + +# Announce whether or not your server supports Forge. If you run a modded server, we +# suggest turning this on. +# +# If your network runs one modpack consistently, consider using ping-passthrough = "mods" +# instead for a nicer display in the server list. +announce-forge = true + +# If enabled (default is false) and the proxy is in online mode, Velocity will kick +# any existing player who is online if a duplicate connection attempt is made. +kick-existing-players = false + +# Should Velocity pass server list ping requests to a backend server? +# Available options: +# - "disabled": No pass-through will be done. The velocity.toml and server-icon.png +# will determine the initial server list ping response. +# - "mods": Passes only the mod list from your backend server into the response. +# The first server in your try list (or forced host) with a mod list will be +# used. If no backend servers can be contacted, Velocity won't display any +# mod information. +# - "description": Uses the description and mod list from the backend server. The first +# server in the try (or forced host) list that responds is used for the +# description and mod list. +# - "all": Uses the backend server's response as the proxy response. The Velocity +# configuration is used if no servers could be contacted. +ping-passthrough = "MODS" + +# If enabled (default is false), then a sample of the online players on the proxy will be visible +# when hovering over the player count in the server list. +# This doesn't have any effect when ping passthrough is set to either "description" or "all". +sample-players-in-ping = false + +# If not enabled (default is true) player IP addresses will be replaced by in logs +enable-player-address-logging = true + +[packet-limiter] +interval = 7 +packets-per-second = 500 +bytes-per-second = -1 + +[servers] +# Configure your servers here. Each key represents the server's name, and the value +# represents the IP address of the server to connect to. +server1 = "127.0.0.1:25565" +server2 = "127.0.0.1:25565" + +# In what order we should try servers when a player logs in or is kicked from a server. +try = [ + "server1" +] + +[forced-hosts] +# Configure your forced hosts here. +"server1.example.com" = [ + "server1" +] + +[advanced] +# How large a Minecraft packet has to be before we compress it. Setting this to zero will +# compress all packets, and setting it to -1 will disable compression entirely. +compression-threshold = 256 + +# How much compression should be done (from 0-9). The default is -1, which uses the +# default level of 6. +compression-level = -1 + +# How fast (in milliseconds) are clients allowed to connect after the last connection? By +# default, this is three seconds. Disable this by setting this to 0. +login-ratelimit = 3000 + +# Specify a custom timeout for connection timeouts here. The default is five seconds. +connection-timeout = 5000 + +# Specify a read timeout for connections here. The default is 30 seconds. +read-timeout = 180000 + +# Enables compatibility with HAProxy's PROXY protocol. If you don't know what this is for, then +# don't enable it. +haproxy-protocol = false + +# Enables TCP fast open support on the proxy. Requires the proxy to run on Linux. +tcp-fast-open = false + +# Enables BungeeCord plugin messaging channel support on Velocity. +bungee-plugin-message-channel = true + +# Shows ping requests to the proxy from clients. +show-ping-requests = true + +# By default, Velocity will attempt to gracefully handle situations where the user unexpectedly +# loses connection to the server without an explicit disconnect message by attempting to fall the +# user back, except in the case of read timeouts. BungeeCord will disconnect the user instead. You +# can disable this setting to use the BungeeCord behavior. +failover-on-unexpected-server-disconnect = true + +# Declares the proxy commands to 1.13+ clients. +announce-proxy-commands = true + +# Enables the logging of commands +log-command-executions = true + +# Enables logging of player connections when connecting to the proxy, switching servers +# and disconnecting from the proxy. +log-player-connections = true + +# Allows players transferred from other hosts via the +# Transfer packet (Minecraft 1.20.5) to be received. +accepts-transfers = false + +# Enables support for SO_REUSEPORT. This may help the proxy scale better on multicore systems +# with a lot of incoming connections, and provide better CPU utilization than the existing +# strategy of having a single thread accepting connections and distributing them to worker +# threads. Disabled by default. Requires Linux or macOS. +enable-reuse-port = false + +# How fast (in milliseconds) are clients allowed to send commands after the last command +# By default this is 50ms (20 commands per second) +command-rate-limit = 50 + +# Should we forward commands to the backend upon being rate limited? +# This will forward the command to the server instead of processing it on the proxy. +# Since most server implementations have a rate limit, this will prevent the player +# from being able to send excessive commands to the server. +forward-commands-if-rate-limited = true + +# How many commands are allowed to be sent after the rate limit is hit before the player is kicked? +# Setting this to 0 or lower will disable this feature. +kick-after-rate-limited-commands = 0 + +# How fast (in milliseconds) are clients allowed to send tab completions after the last tab completion +tab-complete-rate-limit = 10 + +# How many tab completions are allowed to be sent after the rate limit is hit before the player is kicked? +# Setting this to 0 or lower will disable this feature. +kick-after-rate-limited-tab-completes = 0 + +[query] +# Whether to enable responding to GameSpy 4 query responses or not. +enabled = true + +# If query is enabled, on what port should the query protocol listen on? +port = 25578 + +# This is the map name that is reported to the query services. +map = "Velocity" + +# Whether plugins should be shown in query response by default or not +show-plugins = false diff --git a/test/HeadlessMC/templates/velocity/velocity.toml b/test/HeadlessMC/templates/velocity/modern/velocity.toml similarity index 99% rename from test/HeadlessMC/templates/velocity/velocity.toml rename to test/HeadlessMC/templates/velocity/modern/velocity.toml index f5b3cb4e..f80e95cd 100644 --- a/test/HeadlessMC/templates/velocity/velocity.toml +++ b/test/HeadlessMC/templates/velocity/modern/velocity.toml @@ -6,7 +6,7 @@ bind = "0.0.0.0:25577" # What should be the MOTD? This gets displayed when the player adds your server to # their server list. Only MiniMessage format is accepted. -motd = "<#09add3>A Velocity Server" +motd = "<#09add3>A Modern Velocity Server" # What should we display for the maximum number of players? (Velocity does not support a cap # on the number of players online.) @@ -64,7 +64,7 @@ kick-existing-players = false # description and mod list. # - "all": Uses the backend server's response as the proxy response. The Velocity # configuration is used if no servers could be contacted. -ping-passthrough = "ALL" +ping-passthrough = "MODS" # If enabled (default is false), then a sample of the online players on the proxy will be visible # when hovering over the player count in the server list. diff --git a/test/build.gradle.kts b/test/build.gradle.kts index 4456b8f5..c657f9e8 100644 --- a/test/build.gradle.kts +++ b/test/build.gradle.kts @@ -7,8 +7,10 @@ import java.util.Locale // Create new ./test/HeadlessMC/velocity folder // Download into new velocity folder: https://papermc.io/downloads/velocity // Rename to velocity-proxy.jar -// Create new ./test/HeadlessMC/velocity/plugins folder -// Download into velocity plugins folder: https://modrinth.com/plugin/ambassador + +// Create new ./test/HeadlessMC/velocity/modern/plugins folder +// Download into velocity/modern/plugins folder: https://modrinth.com/plugin/ambassador +// Repeat for "legacy" and "bungeeguard" if you plan to test them // If you're testing modern forwarding with 1.7.2-1.12.2 you'll need the Velocity fork which adds that functionality // Build from: https://github.com/p0t4t0sandwich/Velocity/tree/feat/modern-forwarding-legacy @@ -29,6 +31,12 @@ val versions: Map> = mapOf( ) ) +val forwardingModes = listOf( + "legacy", + "bungeeguard", + "modern" +) + val headlessJar: ConfigurableFileCollection = files("HeadlessMC/headlessmc-launcher-2.9.0.jar") val headlessMain: String = "io.github.headlesshq.headlessmc.launcher.Main" var headlessJavaArgs = listOf( @@ -38,8 +46,6 @@ var headlessJavaArgs = listOf( //"-Dhmc.always.lwjgl.flag=true", "-Dhmc.always.pauls.flag=true", - "-Dhmc.gameargs=--server 127.0.0.1 --port 25577 --quickPlayMultiplayer 127.0.0.1:25577", - "-Dhmc.server.accept.eula=true", "--enable-native-access=ALL-UNNAMED" ) @@ -121,49 +127,62 @@ versions.forEach { (platform, mcVersions) -> // Generate server run tasks for each platform and version versions.forEach { (platform, mcVersions) -> - mcVersions.forEach { mcVersion -> - val taskName = "run${taskSuffix(platform, mcVersion)}Server" - tasks.register(taskName) { - val finalJar = rootProject.tasks.getByName("finalJar") - dependsOn(finalJar) - doFirst { - val serverDir = file("HeadlessMC/servers/$platform/$mcVersion") - if (!serverDir.exists()) { - throw GradleException("Server for $platform $mcVersion not found. Please run setup task first.") - } - val parents = serverDir.walk().maxDepth(3) - .filter { it.isDirectory && it.name == "libraries" } - .map { it.parentFile } - .toList() - - parents.forEach { parent -> - val mods = parent.resolve("mods").apply { mkdirs() } - // Remove any proxy-compatible-forge jars from mods folder - parent.resolve("mods").listFiles()?.forEach { if (it.name.startsWith("proxy-compatible-forge-")) it.delete() } - copy { from(files(finalJar.archiveFile)); into(mods) } + forwardingModes.forEach { forwardingMode -> + val parsedMode = forwardingMode.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() } + mcVersions.forEach { mcVersion -> + val taskName = "run${taskSuffix(platform, mcVersion)}Server$parsedMode" + tasks.register(taskName) { + val finalJar = rootProject.tasks.getByName("finalJar") + dependsOn(finalJar) + doFirst { + val serverDir = file("HeadlessMC/servers/$platform/$mcVersion") + if (!serverDir.exists()) { + throw GradleException("Server for $platform $mcVersion not found. Please run setup task first.") + } + val parents = serverDir.walk().maxDepth(3) + .filter { it.isDirectory && it.name == "libraries" } + .map { it.parentFile } + .toList() + + parents.forEach { parent -> + val mods = parent.resolve("mods").apply { mkdirs() } + // Remove any proxy-compatible-forge jars from mods folder + parent.resolve("mods").listFiles() + ?.forEach { if (it.name.startsWith("proxy-compatible-forge-")) it.delete() } + copy { from(files(finalJar.archiveFile)); into(mods) } + } } + group = "run_server_$forwardingMode" + classpath += headlessJar + mainClass.set(headlessMain) + environment("PCF_FORWARDING_MODE", forwardingMode) + jvmArgs(headlessJavaArgs) + args("--command server launch pcf-$platform-$mcVersion".split(" ")) + standardInput = System.`in` } - group = "run_server" - classpath += headlessJar - mainClass.set(headlessMain) - jvmArgs(headlessJavaArgs) - args("--command server launch pcf-$platform-$mcVersion".split(" ")) - standardInput = System.`in` } } } // Generate client run tasks for each platform and version versions.forEach { (platform, mcVersions) -> - mcVersions.forEach { mcVersion -> - val taskName = "run${taskSuffix(platform, mcVersion)}Client" - tasks.register(taskName) { - group = "run_client" - classpath += headlessJar - mainClass.set(headlessMain) - jvmArgs(headlessJavaArgs) - args("--command launch $platform:$mcVersion".split(" ")) - standardInput = System.`in` + forwardingModes.forEach { forwardingMode -> + val parsedMode = forwardingMode.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() } + mcVersions.forEach { mcVersion -> + val taskName = "run${taskSuffix(platform, mcVersion)}Client$parsedMode" + tasks.register(taskName) { + group = "run_client_$forwardingMode" + classpath += headlessJar + mainClass.set(headlessMain) + jvmArgs(headlessJavaArgs) + when (forwardingMode) { + "legacy" -> jvmArgs("-Dhmc.gameargs=--server 127.0.0.1 --port 25578 --quickPlayMultiplayer 127.0.0.1:25578") + "bungeeguard" -> jvmArgs("-Dhmc.gameargs=--server 127.0.0.1 --port 25579 --quickPlayMultiplayer 127.0.0.1:25579") + "modern" -> jvmArgs("-Dhmc.gameargs=--server 127.0.0.1 --port 25577 --quickPlayMultiplayer 127.0.0.1:25577") + } + args("--command launch $platform:$mcVersion".split(" ")) + standardInput = System.`in` + } } } } @@ -179,18 +198,27 @@ val velocityJavaArgs = listOf( ) // Set up Velocity -tasks.register("setupVelocity") { - group = "setup_proxy" - from(file("HeadlessMC/templates/velocity")) - into(file("HeadlessMC/velocity")) +forwardingModes.forEach { forwardingMode -> + val parsedMode = forwardingMode.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() } + tasks.register("setupVelocity$parsedMode") { + group = "setup_proxy" + from(files( + "HeadlessMC/templates/velocity/common", + "HeadlessMC/templates/velocity/$forwardingMode" + )) + into(file("HeadlessMC/velocity/$forwardingMode")) + } } // Run Velocity -tasks.register("runVelocity") { - group = "run_proxy" - workingDir(file("HeadlessMC/velocity")) - classpath += velocityJar - mainClass.set(velocityMain) - jvmArgs(velocityJavaArgs) - standardInput = System.`in` +forwardingModes.forEach { forwardingMode -> + val parsedMode = forwardingMode.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() } + tasks.register("runVelocity$parsedMode") { + group = "run_proxy" + workingDir(file("HeadlessMC/velocity/$forwardingMode")) + classpath += velocityJar + mainClass.set(velocityMain) + jvmArgs(velocityJavaArgs) + standardInput = System.`in` + } } From 6c62ca436c1372d18da16d9658eeb9c1b0a2ef59 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Sun, 26 Apr 2026 23:29:28 -0600 Subject: [PATCH 59/71] Added an error logger to the decoder to account for versions that don't include one natively --- .../org/adde0109/pcf/forwarding/PacketDecoder.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index f6a0e53c..cacee626 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -129,4 +129,17 @@ protected void decode( out.add(msg.retain()); } } + + @Override + public void exceptionCaught( + final @NonNull ChannelHandlerContext ctx, final @NonNull Throwable cause) + throws Exception { + PCF.logger.error( + "Exception in PacketDecoder for " + + ctx.channel().remoteAddress() + + ": " + + cause.getMessage(), + cause); + super.exceptionCaught(ctx, cause); + } } From c5aa8f67fab20712c9a5c7f3414ed159c2998f44 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Sun, 26 Apr 2026 23:29:47 -0600 Subject: [PATCH 60/71] Fixed version-specific method issue --- .../adde0109/pcf/forwarding/legacy/LegacyForwarding.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java index 46b13d2d..03760a0e 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java @@ -128,7 +128,7 @@ public static void handleClientIntention( // spotless:off final String host = fmlMarker.map(property -> originalHost + LEGACY_SEPARATOR - + property.value().split("\u0001")[1] + + getValue(property).split("\u0001")[1] + LEGACY_SEPARATOR).orElse(originalHost); PCF.logger.debug("Parsed forwarded data - Host: " + host + ", UUID: " + uuid); // spotless:on @@ -139,6 +139,7 @@ public static void handleClientIntention( data.clear(); data.writeVarInt(0x00); ClientIntentionPacket.STREAM_CODEC.encode(data, newPacket); + PCF.logger.debug("Rewrote ClientIntentionPacket for " + channel.remoteAddress()); } /** @@ -215,8 +216,8 @@ public static void handleHello( * @return True if the property is the FML marker, false otherwise */ private static boolean isFmlMarker(final @NonNull Property property) { - return Objects.equals(property.name(), "extraData") - && property.value().startsWith("\u0001FORGE"); + return Objects.equals(getName(property), "extraData") + && getValue(property).startsWith("\u0001FORGE"); } /** From 63f1494aa43ef59a2baf2d2d51fd32984262618a Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Mon, 27 Apr 2026 01:15:11 -0600 Subject: [PATCH 61/71] Fixed 1.19.2 GSON issue --- .../adde0109/pcf/forwarding/legacy/LegacyForwarding.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java index 03760a0e..15a227cb 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java @@ -12,9 +12,9 @@ import com.google.common.collect.ImmutableMultimap; import com.google.common.net.InetAddresses; +import com.google.common.reflect.TypeToken; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.google.gson.reflect.TypeToken; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; @@ -38,6 +38,7 @@ import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.lang.reflect.Type; import java.net.InetAddress; import java.util.Collection; import java.util.HashSet; @@ -69,7 +70,8 @@ public final class LegacyForwarding { literal("This server requires the proxy to be configured for BungeeGuard forwarding."); private static final Gson GSON = new GsonBuilder().create(); - private static final TypeToken> profileTypeToken = new TypeToken<>() {}; + // Use Type b/c GSON shipped with MC 1.19.2 doesn't have Gson#fromJson(String, TypeToken) + private static final Type profileTypeToken = new TypeToken>() {}.getType(); private static final Pattern HOST_PATTERN = Pattern.compile("[0-9a-f.:]{0,45}"); private static final Pattern PROP_PATTERN = Pattern.compile("\\w{0,16}"); From 89b31120a09eea096293ddd307821f7a8e09b8f5 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Mon, 27 Apr 2026 01:36:10 -0600 Subject: [PATCH 62/71] Added legacy config to template files --- .../server/config/proxy-compatible-forge.cfg | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 test/HeadlessMC/templates/server/config/proxy-compatible-forge.cfg diff --git a/test/HeadlessMC/templates/server/config/proxy-compatible-forge.cfg b/test/HeadlessMC/templates/server/config/proxy-compatible-forge.cfg new file mode 100644 index 00000000..d1fac88f --- /dev/null +++ b/test/HeadlessMC/templates/server/config/proxy-compatible-forge.cfg @@ -0,0 +1,29 @@ +# Configuration file + +advanced { + S:modernForwardingVersion=NO_OVERRIDE +} + + +debug { + S:disabledMixins < + > + B:enabled=true +} + + +forwarding { + S:approvedProxyHosts < + 127.0.0.1 + > + B:enabled=true + S:mode=MODERN + S:secret=testtesttest +} + + +general { + D:version=2.0 +} + + From 72029ad73be372c4b3e130860191ed3aea5ffb5d Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Mon, 27 Apr 2026 21:55:11 -0600 Subject: [PATCH 63/71] Add vanilla client run tasks for when sanity checks are needed --- test/build.gradle.kts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/test/build.gradle.kts b/test/build.gradle.kts index c657f9e8..3f37a3d6 100644 --- a/test/build.gradle.kts +++ b/test/build.gradle.kts @@ -28,6 +28,13 @@ val versions: Map> = mapOf( "neoforge" to listOf( "1.20.2", "1.20.4", "1.21.1", "1.21.5", "26.1.2" + ), + "vanilla" to listOf( + "1.12.2", "1.13.2", + "1.14.4", "1.15.2", "1.16.5", + "1.17.1", "1.18.2", "1.19", "1.19.2", "1.19.4", "1.20.1", "1.20.2", "1.20.4", + "1.21.1", "1.21.5", + "26.1.2" ) ) @@ -90,6 +97,7 @@ tasks.register("headlessmc") { // Generate server setup tasks for each platform and version versions.forEach { (platform, mcVersions) -> + if (platform == "vanilla") return@forEach mcVersions.forEach { mcVersion -> val taskName = "setup${taskSuffix(platform, mcVersion)}" tasks.register(taskName) { @@ -127,6 +135,7 @@ versions.forEach { (platform, mcVersions) -> // Generate server run tasks for each platform and version versions.forEach { (platform, mcVersions) -> + if (platform == "vanilla") return@forEach forwardingModes.forEach { forwardingMode -> val parsedMode = forwardingMode.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() } mcVersions.forEach { mcVersion -> @@ -180,7 +189,11 @@ versions.forEach { (platform, mcVersions) -> "bungeeguard" -> jvmArgs("-Dhmc.gameargs=--server 127.0.0.1 --port 25579 --quickPlayMultiplayer 127.0.0.1:25579") "modern" -> jvmArgs("-Dhmc.gameargs=--server 127.0.0.1 --port 25577 --quickPlayMultiplayer 127.0.0.1:25577") } - args("--command launch $platform:$mcVersion".split(" ")) + if (platform == "vanilla") { + args("--command launch $mcVersion".split(" ")) + } else { + args("--command launch $platform:$mcVersion".split(" ")) + } standardInput = System.`in` } } From 9e4d5f8110c135cb0a9c9e89a8baa103718dcedc Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Tue, 28 Apr 2026 00:57:37 -0600 Subject: [PATCH 64/71] Added more packet logging --- .../pcf/forwarding/PacketDecoder.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index cacee626..723b18f9 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -7,11 +7,14 @@ import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.handleClientIntention; import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleCustomQueryAnswer; +import dev.neuralnexus.taterapi.meta.Constraint; +import dev.neuralnexus.taterapi.meta.MinecraftVersions; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; import dev.neuralnexus.taterapi.network.Protocol; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageDecoder; @@ -44,6 +47,38 @@ protected void decode( final int readerIndex = msg.readerIndex(); final FriendlyByteBuf data = new FriendlyByteBuf(msg); + + // Hexdump the packet for debugging + if (PCF.instance().debug().enabled()) { + final int id = data.readVarInt(); + // Don't want to leak the secret nor the encrypted payload in the debug log + if (!(connection.bridge$protocol() == Protocol.HANDSHAKING + && PCF.instance().forwarding().mode() == Mode.BUNGEEGUARD) + && !(connection.bridge$protocol() == Protocol.LOGIN + && PCF.instance().forwarding().mode() == Mode.MODERN + && id == 0x02)) { + msg.readerIndex(readerIndex); + if (connection.bridge$getPacketListener() != null) { + //noinspection DataFlowIssue + PCF.logger.debug( + "\nPacket listener: " + + connection.bridge$getPacketListener().getClass().getName() + + "\nPacket length: " + + data.readableBytes() + + "\nPacket data:\n" + + ByteBufUtil.prettyHexDump(data)); + } else { + PCF.logger.debug( + "\nPacket listener: NONE\nPacket length " + + data.readableBytes() + + "\nPacket data:\n" + + ByteBufUtil.prettyHexDump(data)); + } + } else { + msg.readerIndex(readerIndex); + } + } + final int id = data.readVarInt(); PCF.logger.debug( "Received " From d50250f0af93bf8e01f4b2abdb0be02e9448432e Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Tue, 28 Apr 2026 05:49:55 -0600 Subject: [PATCH 65/71] Mode debug logging, and improved Forge token parsing --- .../pcf/forwarding/PacketDecoder.java | 58 +++++++++++-------- .../forwarding/legacy/LegacyForwarding.java | 45 +++++++++++--- 2 files changed, 72 insertions(+), 31 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 723b18f9..0d76e13e 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -21,6 +21,7 @@ import org.adde0109.pcf.PCF; import org.jspecify.annotations.NonNull; +import java.nio.channels.ClosedChannelException; import java.util.List; public final class PacketDecoder extends MessageToMessageDecoder { @@ -51,32 +52,26 @@ protected void decode( // Hexdump the packet for debugging if (PCF.instance().debug().enabled()) { final int id = data.readVarInt(); - // Don't want to leak the secret nor the encrypted payload in the debug log - if (!(connection.bridge$protocol() == Protocol.HANDSHAKING - && PCF.instance().forwarding().mode() == Mode.BUNGEEGUARD) - && !(connection.bridge$protocol() == Protocol.LOGIN - && PCF.instance().forwarding().mode() == Mode.MODERN - && id == 0x02)) { - msg.readerIndex(readerIndex); - if (connection.bridge$getPacketListener() != null) { - //noinspection DataFlowIssue - PCF.logger.debug( - "\nPacket listener: " - + connection.bridge$getPacketListener().getClass().getName() - + "\nPacket length: " - + data.readableBytes() - + "\nPacket data:\n" - + ByteBufUtil.prettyHexDump(data)); - } else { - PCF.logger.debug( - "\nPacket listener: NONE\nPacket length " - + data.readableBytes() - + "\nPacket data:\n" - + ByteBufUtil.prettyHexDump(data)); - } + msg.readerIndex(readerIndex); + final String hexDump = ByteBufUtil.prettyHexDump(data); + + final StringBuilder sb = new StringBuilder(); + if (connection.bridge$getPacketListener() != null) { + //noinspection DataFlowIssue + sb.append("\nPacket listener: ") + .append(connection.bridge$getPacketListener().getClass().getName()); } else { - msg.readerIndex(readerIndex); + sb.append("\nPacket listener: NONE"); + } + sb.append("\nPacket length: ").append(data.readableBytes()); + + // Don't want to leak the secret nor the encrypted payload in the debug log + if (!(connection.bridge$protocol() == Protocol.LOGIN && id == 0x02) + && !(connection.bridge$protocol() == Protocol.HANDSHAKING + && PCF.instance().forwarding().mode().isLegacy())) { + sb.append("\nPacket data:\n").append(hexDump); } + PCF.logger.debug(sb.toString()); } final int id = data.readVarInt(); @@ -122,6 +117,17 @@ protected void decode( msg.readerIndex(readerIndex); break; } + + // Used to avoid a second 0x0 packet with 2 bytes consisting of [0x00, 0x03] + // Not entirely sure of the cause + if (data.readableBytes() == 1 + && Constraint.range( + MinecraftVersions.V20_2, MinecraftVersions.V20_4) + .result()) { + msg.readerIndex(readerIndex); + break; + } + PCF.logger.debug( "Handling ServerBoundHelloPacket from " + ctx.channel().remoteAddress()); @@ -169,6 +175,10 @@ protected void decode( public void exceptionCaught( final @NonNull ChannelHandlerContext ctx, final @NonNull Throwable cause) throws Exception { + if (cause instanceof ClosedChannelException) { + super.exceptionCaught(ctx, cause); + return; + } PCF.logger.error( "Exception in PacketDecoder for " + ctx.channel().remoteAddress() diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java index 15a227cb..2049cd06 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java @@ -97,6 +97,14 @@ public static void handleClientIntention( // Parse the host name for forwarded data final String[] split = hostName.split("\00"); + if (PCF.instance().debug().enabled()) { + // spotless:off + PCF.logger.debug( + "Received ClientIntentionPacket with the following:" + + "\nHostName: " + split[0] + + "\nSplit Length: " + split.length); + // spotless:on + } if (split.length < 3 || !(HOST_PATTERN.matcher(split[1]).matches())) { channel.attr(DEFERRED_DISCONNECT).set(LEGACY_DIRECT_CONNECT_ERR); return; @@ -128,10 +136,28 @@ public static void handleClientIntention( } // spotless:off - final String host = fmlMarker.map(property -> originalHost - + LEGACY_SEPARATOR - + getValue(property).split("\u0001")[1] - + LEGACY_SEPARATOR).orElse(originalHost); + final String host = fmlMarker.map(property -> { + // TODO: Convert magic strings to constants and build some version-specific logic + if (getName(property).equals("extraData") + && (getValue(property).startsWith("\u0001FML") + || getValue(property).startsWith("\u0001FORGE"))) { // Waterfall support + return getValue(property).split("\u0001")[1]; + } else if (getName(property).equals("forgeClient")) { // Velocity support + if (getValue(property).equals("true")) { // 1.12.2 and below + return "FML"; + } + + // Forge 1.20.2+ + final String[] natVersionStr = getValue(property).split(LEGACY_SEPARATOR + "FORGE"); + int natVersion = 0; + if (natVersionStr.length == 1) { + natVersion = Integer.parseInt(natVersionStr[0]); + } + return "FORGE" + (natVersion > 0 ? natVersion : ""); + } else { + return property; + } + }).map(token -> originalHost + LEGACY_SEPARATOR + token).orElse(originalHost); PCF.logger.debug("Parsed forwarded data - Host: " + host + ", UUID: " + uuid); // spotless:on @@ -212,14 +238,19 @@ public static void handleHello( } /** - * Check if a property is the FML marker used by Forge to indicate a modded client. + * Check if a property is the FML marker used by Forge to indicate a modded client.
+ * "extraData" is provided by Waterfall
+ * "forgeClient" is provided by Velocity * * @param property The property to check * @return True if the property is the FML marker, false otherwise */ private static boolean isFmlMarker(final @NonNull Property property) { - return Objects.equals(getName(property), "extraData") - && getValue(property).startsWith("\u0001FORGE"); + // TODO: Convert magic strings to constants and build some version-specific logic + return (Objects.equals(getName(property), "extraData") + && (getValue(property).startsWith("\u0001FML") + || getValue(property).startsWith("\u0001FORGE"))) + || Objects.equals(getName(property), "forgeClient"); } /** From 6f11193530ad5136de4822341e4d90f1b2c3a49f Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 29 Apr 2026 21:36:11 -0600 Subject: [PATCH 66/71] More debug logging, temporary debug logging, and a couple temporary fixes --- .../pcf/forwarding/PacketDecoder.java | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 0d76e13e..52d398a2 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -16,6 +16,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.DecoderException; import io.netty.handler.codec.MessageToMessageDecoder; import org.adde0109.pcf.PCF; @@ -67,9 +68,29 @@ protected void decode( // Don't want to leak the secret nor the encrypted payload in the debug log if (!(connection.bridge$protocol() == Protocol.LOGIN && id == 0x02) - && !(connection.bridge$protocol() == Protocol.HANDSHAKING - && PCF.instance().forwarding().mode().isLegacy())) { + && connection.bridge$protocol() != Protocol.HANDSHAKING) { sb.append("\nPacket data:\n").append(hexDump); + } else if (connection.bridge$protocol() == Protocol.HANDSHAKING) { + // Debug log the handshake without leaking the secret + data.readVarInt(); // Skip the packet id + final int protocol = data.readVarInt(); + // TODO: Resolve out of band login hello packet + // read when Legacy proto -> Modern PCF handling + // Effects: 1.20.4 + String[] host = {"failed to read, decoder likely in wrong protocol phase"}; + try { + host = data.readUtf().split("\0"); + } catch (final DecoderException ignored) { + } + msg.readerIndex(readerIndex); + + sb.append("\nReceived ClientIntentionPacket with the following:"); + sb.append("\n- Protocol version: ").append(protocol); + sb.append("\n- HostName: ").append(host[0]); + sb.append("\n- Split length: ").append(host.length); + if (host.length > 1) { + sb.append("\n- Forwarded IP or Forge token: ").append(host[1]); + } } PCF.logger.debug(sb.toString()); } @@ -118,8 +139,8 @@ protected void decode( break; } - // Used to avoid a second 0x0 packet with 2 bytes consisting of [0x00, 0x03] - // Not entirely sure of the cause + // TODO: Resolve out of band PLAY accept teleportation packet + // Effects: 1.20.2 - 1.20.4 if (data.readableBytes() == 1 && Constraint.range( MinecraftVersions.V20_2, MinecraftVersions.V20_4) From 2fe0c35f329e398367a4796f0af4305d5642a8df Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Wed, 29 Apr 2026 21:40:04 -0600 Subject: [PATCH 67/71] Improved modern and legacy Forge token parsing --- .../forwarding/legacy/LegacyForwarding.java | 94 ++++++++----------- 1 file changed, 39 insertions(+), 55 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java index 2049cd06..d7d1ede6 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java @@ -43,7 +43,6 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; -import java.util.Objects; import java.util.Optional; import java.util.UUID; import java.util.regex.Pattern; @@ -52,7 +51,9 @@ * Adapted from Spigot * and BungeeForge + * href="https://github.com/caunt/BungeeForge/blob/1.20.2/src/main/java/ua/caunt/bungeeforge/mixin/network/protocol/handshake/ClientIntentionPacket.java">BungeeForge. + * Additional information sourced from Velocity and Waterfall */ public final class LegacyForwarding { public static final AttributeKey DEFERRED_DISCONNECT = @@ -75,7 +76,11 @@ public final class LegacyForwarding { private static final Pattern HOST_PATTERN = Pattern.compile("[0-9a-f.:]{0,45}"); private static final Pattern PROP_PATTERN = Pattern.compile("\\w{0,16}"); - private static final char LEGACY_SEPARATOR = '\0'; + + private static final String LEGACY_FORGE_MARKER = "\0FML\0"; + private static final String EXTRA_DATA_PROPERTY = "extraData"; + private static final String FORGE_CLIENT_PROPERTY = "forgeClient"; + private static final String FORGE_CLIENT_TRUE = "true"; /** * Handle the client intention packet and extract player info @@ -96,15 +101,7 @@ public static void handleClientIntention( final Channel channel = connection.bridge$channel(); // Parse the host name for forwarded data - final String[] split = hostName.split("\00"); - if (PCF.instance().debug().enabled()) { - // spotless:off - PCF.logger.debug( - "Received ClientIntentionPacket with the following:" - + "\nHostName: " + split[0] - + "\nSplit Length: " + split.length); - // spotless:on - } + final String[] split = hostName.split("\0"); if (split.length < 3 || !(HOST_PATTERN.matcher(split[1]).matches())) { channel.attr(DEFERRED_DISCONNECT).set(LEGACY_DIRECT_CONNECT_ERR); return; @@ -122,42 +119,45 @@ public static void handleClientIntention( channel.attr(FORWARDED_ADDRESS).set(InetAddresses.forString(forwardedAddress)); channel.attr(SPOOFED_UUID).set(uuid); - final Optional fmlMarker; + // spotless:off + final boolean forgeClient; + final Optional extraData; if (split.length >= 4) { final String profileJSON = split[3]; final List properties = GSON.fromJson(profileJSON, profileTypeToken); - // Pop out the FML marker - fmlMarker = properties.stream().filter(LegacyForwarding::isFmlMarker).findFirst(); - properties.removeIf(LegacyForwarding::isFmlMarker); + // Pop out the Forge properties + forgeClient = properties.stream().anyMatch(p -> + getName(p).equals(FORGE_CLIENT_PROPERTY) && getValue(p).equals(FORGE_CLIENT_TRUE)); + extraData = properties.stream() + .filter(p -> getName(p).equals(EXTRA_DATA_PROPERTY)).findFirst(); + properties.removeIf(p -> + getName(p).equals(FORGE_CLIENT_PROPERTY) || getName(p).equals(EXTRA_DATA_PROPERTY)); channel.attr(SPOOFED_PROFILE).set(properties); } else { - fmlMarker = Optional.empty(); + forgeClient = false; + extraData = Optional.empty(); } - // spotless:off - final String host = fmlMarker.map(property -> { - // TODO: Convert magic strings to constants and build some version-specific logic - if (getName(property).equals("extraData") - && (getValue(property).startsWith("\u0001FML") - || getValue(property).startsWith("\u0001FORGE"))) { // Waterfall support - return getValue(property).split("\u0001")[1]; - } else if (getName(property).equals("forgeClient")) { // Velocity support - if (getValue(property).equals("true")) { // 1.12.2 and below - return "FML"; - } - - // Forge 1.20.2+ - final String[] natVersionStr = getValue(property).split(LEGACY_SEPARATOR + "FORGE"); - int natVersion = 0; - if (natVersionStr.length == 1) { - natVersion = Integer.parseInt(natVersionStr[0]); - } - return "FORGE" + (natVersion > 0 ? natVersion : ""); - } else { - return property; + final String host; + if (extraData.isPresent()) { + final String value = getValue(extraData.get()); + if (!forgeClient) { // Unlikely, but notable + PCF.logger.debug("Received extraData without forgeClient=true from " + + channel.remoteAddress() + " - value: " + value); + } + if (value.startsWith("\1")) { // Restore extra hostname data + host = originalHost + value.replace("\1", "\0"); + } else { // Avoid propagating bad data + PCF.logger.warn("Received misformatted extraData from " + + channel.remoteAddress() + " - value: " + value); + host = originalHost; } - }).map(token -> originalHost + LEGACY_SEPARATOR + token).orElse(originalHost); + } else if (forgeClient) { // Assume Forge 1.8 - 1.12.2 + host = originalHost + LEGACY_FORGE_MARKER; + } else { + host = originalHost; + } PCF.logger.debug("Parsed forwarded data - Host: " + host + ", UUID: " + uuid); // spotless:on @@ -237,22 +237,6 @@ public static void handleHello( string.replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5")); } - /** - * Check if a property is the FML marker used by Forge to indicate a modded client.
- * "extraData" is provided by Waterfall
- * "forgeClient" is provided by Velocity - * - * @param property The property to check - * @return True if the property is the FML marker, false otherwise - */ - private static boolean isFmlMarker(final @NonNull Property property) { - // TODO: Convert magic strings to constants and build some version-specific logic - return (Objects.equals(getName(property), "extraData") - && (getValue(property).startsWith("\u0001FML") - || getValue(property).startsWith("\u0001FORGE"))) - || Objects.equals(getName(property), "forgeClient"); - } - /** * Creates a new GameProfile * From 145bdaee6f11119c1decaf70aa474978e6015b81 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Thu, 30 Apr 2026 03:58:15 -0600 Subject: [PATCH 68/71] Modified modern forwarding so the handshake packet is rewritten if it's sent from a proxy configured for legacy forwarding and cleaned up some debug logging --- .../pcf/forwarding/ConnectionBridge.java | 6 +- .../adde0109/pcf/forwarding/Forwarding.java | 41 +++++++++ .../pcf/forwarding/PacketDecoder.java | 91 +++++-------------- .../forwarding/legacy/LegacyForwarding.java | 25 ++--- .../forwarding/modern/ModernForwarding.java | 42 +++++++++ 5 files changed, 121 insertions(+), 84 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java b/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java index 7df41abf..a1b5db2d 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/ConnectionBridge.java @@ -41,8 +41,10 @@ static void injectIntoPipeline(final @NonNull ChannelHandlerContext ctx) { || ctx.pipeline().get(PacketEncoder.NAME) != null) { return; } - PCF.logger.debug( - "Injecting packet handlers into pipeline of " + ctx.channel().remoteAddress()); + if (PCF.instance().debug().enabled()) { + PCF.logger.debug( + "Injecting packet handlers into pipeline of " + ctx.channel().remoteAddress()); + } ctx.channel() .pipeline() .addAfter(HANDLER_SPLITTER, PacketDecoder.NAME, new PacketDecoder()) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java index 33707b74..289dd1a0 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java @@ -3,12 +3,18 @@ import static dev.neuralnexus.taterapi.network.chat.Component.literal; import static dev.neuralnexus.taterapi.network.chat.Component.translatable; +import static org.adde0109.pcf.forwarding.ReflectionUtils.attributeKeyValueOf; + import com.mojang.authlib.GameProfile; import dev.neuralnexus.taterapi.event.Cancellable; import dev.neuralnexus.taterapi.mc.server.players.NameAndId; +import dev.neuralnexus.taterapi.network.FriendlyByteBuf; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; +import io.netty.channel.Channel; +import io.netty.util.AttributeKey; + import org.adde0109.pcf.PCF; import org.adde0109.pcf.forwarding.legacy.LegacyForwarding; import org.adde0109.pcf.forwarding.modern.ModernForwarding; @@ -20,12 +26,38 @@ import java.util.Collection; public final class Forwarding { + public static final AttributeKey DEFERRED_DISCONNECT = + attributeKeyValueOf("pcf-deferred-disconnect"); + public static final Object PLAYER_INFO_ERR = literal("Unable to verify player details."); private static final Object FAILED_TO_VERIFY = translatable("multiplayer.disconnect.unverified_username"); private static final Object REJECTED_PROXY_ERR = literal("Unapproved proxy host."); + /** + * Handle the client intention packet and extract player info + * + * @param connection The connection + * @param data The packet buffer + */ + public static void handleClientIntention( + final @NonNull ConnectionBridge connection, final @NonNull FriendlyByteBuf data) { + final Channel channel = connection.bridge$channel(); + try { + switch (PCF.instance().forwarding().mode()) { + case LEGACY, BUNGEEGUARD -> + LegacyForwarding.handleClientIntention(connection, data); + case MODERN -> ModernForwarding.handleClientIntention(connection, data); + } + } catch (final ThrowingComponent e) { + channel.attr(DEFERRED_DISCONNECT).set(e.getComponent()); + } catch (final Exception e) { + e.printStackTrace(); + channel.attr(DEFERRED_DISCONNECT).set(PLAYER_INFO_ERR); + } + } + /** * Abstract implementation of the hello packet handler * @@ -35,6 +67,15 @@ public final class Forwarding { public static void handleHello( final @NonNull ServerLoginPacketListenerBridge slpl, final @NonNull CallbackInfo ci) { try { + final ConnectionBridge connection = slpl.bridge$connection(); + final Channel channel = connection.bridge$channel(); + + // Handle any deferred disconnects from the handshake phase + final Object deferredDisconnect = channel.attr(DEFERRED_DISCONNECT).getAndSet(null); + if (deferredDisconnect != null) { + throw new ThrowingComponent(deferredDisconnect); + } + switch (PCF.instance().forwarding().mode()) { case LEGACY, BUNGEEGUARD -> LegacyForwarding.handleHello(slpl, ci); case MODERN -> ModernForwarding.handleHello(slpl, ci); diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 52d398a2..2f9b6f9a 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -3,8 +3,8 @@ import static dev.neuralnexus.taterapi.network.protocol.login.ServerboundHelloPacket.MAX_NAME_LENGTH; import static org.adde0109.pcf.forwarding.ConnectionBridge.HANDLER_PACKET; +import static org.adde0109.pcf.forwarding.Forwarding.handleClientIntention; import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.PLAYER_NAME; -import static org.adde0109.pcf.forwarding.legacy.LegacyForwarding.handleClientIntention; import static org.adde0109.pcf.forwarding.modern.ModernForwarding.handleCustomQueryAnswer; import dev.neuralnexus.taterapi.meta.Constraint; @@ -16,7 +16,6 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.DecoderException; import io.netty.handler.codec.MessageToMessageDecoder; import org.adde0109.pcf.PCF; @@ -49,74 +48,21 @@ protected void decode( final int readerIndex = msg.readerIndex(); final FriendlyByteBuf data = new FriendlyByteBuf(msg); - - // Hexdump the packet for debugging - if (PCF.instance().debug().enabled()) { - final int id = data.readVarInt(); - msg.readerIndex(readerIndex); - final String hexDump = ByteBufUtil.prettyHexDump(data); - - final StringBuilder sb = new StringBuilder(); - if (connection.bridge$getPacketListener() != null) { - //noinspection DataFlowIssue - sb.append("\nPacket listener: ") - .append(connection.bridge$getPacketListener().getClass().getName()); - } else { - sb.append("\nPacket listener: NONE"); - } - sb.append("\nPacket length: ").append(data.readableBytes()); - - // Don't want to leak the secret nor the encrypted payload in the debug log - if (!(connection.bridge$protocol() == Protocol.LOGIN && id == 0x02) - && connection.bridge$protocol() != Protocol.HANDSHAKING) { - sb.append("\nPacket data:\n").append(hexDump); - } else if (connection.bridge$protocol() == Protocol.HANDSHAKING) { - // Debug log the handshake without leaking the secret - data.readVarInt(); // Skip the packet id - final int protocol = data.readVarInt(); - // TODO: Resolve out of band login hello packet - // read when Legacy proto -> Modern PCF handling - // Effects: 1.20.4 - String[] host = {"failed to read, decoder likely in wrong protocol phase"}; - try { - host = data.readUtf().split("\0"); - } catch (final DecoderException ignored) { - } - msg.readerIndex(readerIndex); - - sb.append("\nReceived ClientIntentionPacket with the following:"); - sb.append("\n- Protocol version: ").append(protocol); - sb.append("\n- HostName: ").append(host[0]); - sb.append("\n- Split length: ").append(host.length); - if (host.length > 1) { - sb.append("\n- Forwarded IP or Forge token: ").append(host[1]); - } - } - PCF.logger.debug(sb.toString()); - } - final int id = data.readVarInt(); - PCF.logger.debug( - "Received " - + connection.bridge$protocol() - + " packet with ID 0x" - + Integer.toHexString(id) - + " from " - + ctx.channel().remoteAddress()); + final StringBuilder debugInfo = + new StringBuilder("Received ") + .append(connection.bridge$protocol()) + .append(" packet with ID 0x") + .append(Integer.toHexString(id)) + .append(" from ") + .append(ctx.channel().remoteAddress()); switch (connection.bridge$protocol()) { case HANDSHAKING -> { - if (!PCF.instance().forwarding().mode().isLegacy()) { - msg.readerIndex(readerIndex); - break; - } - //noinspection SwitchStatementWithTooFewBranches switch (id) { case 0x00 -> { - PCF.logger.debug( - "Handling ClientIntentionPacket from " - + ctx.channel().remoteAddress()); + debugInfo.append(", Handling ClientIntentionPacket"); // Rewrite the packet handleClientIntention(connection, data); @@ -146,12 +92,16 @@ protected void decode( MinecraftVersions.V20_2, MinecraftVersions.V20_4) .result()) { msg.readerIndex(readerIndex); + debugInfo + .append( + ", Handling out-of-band PLAY accept teleportation packet:") + .append("\n - Packet Length: ") + .append(data.readableBytes()) + .append("\n - Packet data: 0x") + .append(ByteBufUtil.prettyHexDump(data)); break; } - - PCF.logger.debug( - "Handling ServerBoundHelloPacket from " - + ctx.channel().remoteAddress()); + debugInfo.append(", Handling ServerBoundHelloPacket"); // Save player name final String name = data.readUtf(MAX_NAME_LENGTH); @@ -163,9 +113,7 @@ protected void decode( msg.readerIndex(readerIndex); break; } - PCF.logger.debug( - "Handling ServerboundCustomQueryAnswerPacket from " - + ctx.channel().remoteAddress()); + debugInfo.append(", Handling ServerboundCustomQueryAnswerPacket"); boolean handled = false; try { @@ -186,6 +134,9 @@ protected void decode( } case null, default -> msg.readerIndex(readerIndex); } + if (PCF.instance().debug().enabled()) { + PCF.logger.debug(debugInfo.toString()); + } if (msg.isReadable()) { out.add(msg.retain()); diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java index d7d1ede6..2895ca44 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java @@ -27,6 +27,7 @@ import dev.neuralnexus.taterapi.network.protocol.handshake.ClientIntentionPacket; import io.netty.channel.Channel; +import io.netty.handler.codec.DecoderException; import io.netty.util.AttributeKey; import org.adde0109.pcf.PCF; @@ -56,8 +57,6 @@ * href="https://github.com/PaperMC/Waterfall/blob/master/BungeeCord-Patches/0011-Add-support-for-FML-with-IP-Forwarding-enabled.patch">Waterfall */ public final class LegacyForwarding { - public static final AttributeKey DEFERRED_DISCONNECT = - attributeKeyValueOf("pcf-deferred-disconnect"); public static final AttributeKey FORWARDED_ADDRESS = attributeKeyValueOf("pcf-forwarded-address"); public static final AttributeKey PLAYER_NAME = attributeKeyValueOf("pcf-player-name"); @@ -92,7 +91,16 @@ public static void handleClientIntention( final @NonNull ConnectionBridge connection, final @NonNull FriendlyByteBuf data) { // Read the original packet final int protocolVersion = data.readVarInt(); - final String hostName = data.readUtf(Short.MAX_VALUE); + final String hostName; + try { + hostName = data.readUtf(Short.MAX_VALUE); + } catch (final DecoderException e) { + if (e.getMessage().startsWith("Not enough bytes in buffer")) { + PCF.logger.debug("Received out-of-band LOGIN ServerBoundHelloPacket"); + throw new ThrowingComponent(LEGACY_DIRECT_CONNECT_ERR); + } + throw e; + } final int hostPort = data.readUnsignedShort(); final ClientIntent intention = ClientIntent.byId(data.readVarInt()); if (intention != ClientIntent.LOGIN) { @@ -103,12 +111,11 @@ public static void handleClientIntention( // Parse the host name for forwarded data final String[] split = hostName.split("\0"); if (split.length < 3 || !(HOST_PATTERN.matcher(split[1]).matches())) { - channel.attr(DEFERRED_DISCONNECT).set(LEGACY_DIRECT_CONNECT_ERR); - return; + throw new ThrowingComponent(LEGACY_DIRECT_CONNECT_ERR); } if (PCF.instance().forwarding().mode() == Mode.BUNGEEGUARD && (split.length < 4 || !split[3].contains(BUNGEE_GUARD_TOKEN_PROPERTY_NAME))) { - channel.attr(DEFERRED_DISCONNECT).set(BG_CONFIG_ERR); + throw new ThrowingComponent(BG_CONFIG_ERR); } final String originalHost = split[0]; @@ -181,12 +188,6 @@ public static void handleHello( final ConnectionBridge connection = slpl.bridge$connection(); final Channel channel = connection.bridge$channel(); - // Handle any deferred disconnects from the handshake phase - final Object deferredDisconnect = channel.attr(DEFERRED_DISCONNECT).getAndSet(null); - if (deferredDisconnect != null) { - throw new ThrowingComponent(deferredDisconnect); - } - // Check if the connection is from an approved proxy Forwarding.checkProxy(connection); diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index 59d1caca..3457bf3f 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -14,10 +14,13 @@ import dev.neuralnexus.taterapi.meta.MinecraftVersions; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; +import dev.neuralnexus.taterapi.network.protocol.handshake.ClientIntent; +import dev.neuralnexus.taterapi.network.protocol.handshake.ClientIntentionPacket; import dev.neuralnexus.taterapi.network.protocol.login.ClientboundCustomQueryPacket; import dev.neuralnexus.taterapi.network.protocol.login.ServerboundCustomQueryAnswerPacket; import dev.neuralnexus.taterapi.network.protocol.login.custom.CustomQueryAnswerPayload; +import io.netty.channel.Channel; import io.netty.handler.codec.DecoderException; import io.netty.util.AttributeKey; @@ -60,6 +63,45 @@ public final class ModernForwarding { private static final Object INVALID_SIGNATURE = translatable("multiplayer.disconnect.invalid_public_key_signature"); + /** + * Handle the client intention packet and reject the connection if legacy forwarding is + * detected. + * + * @param connection The connection + * @param data The packet buffer + */ + public static void handleClientIntention( + final @NonNull ConnectionBridge connection, final @NonNull FriendlyByteBuf data) { + // Read the original packet + final int protocolVersion = data.readVarInt(); + final String hostName = data.readUtf(Short.MAX_VALUE); + final int hostPort = data.readUnsignedShort(); + final ClientIntent intention = ClientIntent.byId(data.readVarInt()); + if (intention != ClientIntent.LOGIN) { + return; + } + final Channel channel = connection.bridge$channel(); + + // Parse the host name for forwarded data + final String[] split = hostName.split("\0"); + if (split.length >= 2 && (split[1].startsWith("FML") || split[1].startsWith("FORGE"))) { + return; // Modded client + } else if (split.length < 2) { + return; // Likely a normal connection + } + + // Rewrite the packet so the player can enter the login phase + final ClientIntentionPacket newPacket = + new ClientIntentionPacket(protocolVersion, split[0], hostPort, intention); + data.clear(); + data.writeVarInt(0x00); + ClientIntentionPacket.STREAM_CODEC.encode(data, newPacket); + PCF.logger.debug("Rewrote ClientIntentionPacket for " + channel.remoteAddress()); + + // Disconnect the user + throw new ThrowingComponent(MODERN_DIRECT_CONNECT_ERR); + } + /** * Hello packet handler for modern forwarding * From f051af4b2132bcb653f65ab3c8443bcc984c382b Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Thu, 30 Apr 2026 04:19:52 -0600 Subject: [PATCH 69/71] Properly fixed the ClientIntention rewriting --- .../adde0109/pcf/forwarding/Forwarding.java | 30 +++++++++++++++++++ .../forwarding/legacy/LegacyForwarding.java | 25 ++++------------ .../forwarding/modern/ModernForwarding.java | 18 ++++------- 3 files changed, 42 insertions(+), 31 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java index 289dd1a0..d5ce12bf 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/Forwarding.java @@ -11,6 +11,8 @@ import dev.neuralnexus.taterapi.mc.server.players.NameAndId; import dev.neuralnexus.taterapi.network.FriendlyByteBuf; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; +import dev.neuralnexus.taterapi.network.protocol.handshake.ClientIntent; +import dev.neuralnexus.taterapi.network.protocol.handshake.ClientIntentionPacket; import io.netty.channel.Channel; import io.netty.util.AttributeKey; @@ -24,6 +26,7 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.Collection; +import java.util.regex.Pattern; public final class Forwarding { public static final AttributeKey DEFERRED_DISCONNECT = @@ -35,6 +38,8 @@ public final class Forwarding { translatable("multiplayer.disconnect.unverified_username"); private static final Object REJECTED_PROXY_ERR = literal("Unapproved proxy host."); + public static final Pattern HOST_PATTERN = Pattern.compile("[0-9a-f.:]{0,45}"); + /** * Handle the client intention packet and extract player info * @@ -90,6 +95,31 @@ public static void handleHello( } } + /** + * Rewrite ClientIntention packet so the player can enter the login phase. + * + * @param channel The connection's Netty channel + * @param protocolVersion The protocol version from the original packet + * @param hostName The hostname from the original packet + * @param hostPort The port from the original packet + * @param intention The client intention from the original packet + * @param data The packet buffer to write the new packet into + */ + public static void rewriteClientIntention( + final @NonNull Channel channel, + final int protocolVersion, + final String hostName, + final int hostPort, + final ClientIntent intention, + final @NonNull FriendlyByteBuf data) { + final ClientIntentionPacket newPacket = + new ClientIntentionPacket(protocolVersion, hostName, hostPort, intention); + data.clear(); + data.writeVarInt(0x00); + ClientIntentionPacket.STREAM_CODEC.encode(data, newPacket); + PCF.logger.debug("Rewrote ClientIntentionPacket for " + channel.remoteAddress()); + } + /** * Checks if the connection is coming from an approved proxy host * diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java index 2895ca44..40898c8b 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java @@ -2,7 +2,9 @@ import static dev.neuralnexus.taterapi.network.chat.Component.literal; +import static org.adde0109.pcf.forwarding.Forwarding.HOST_PATTERN; import static org.adde0109.pcf.forwarding.Forwarding.PLAYER_INFO_ERR; +import static org.adde0109.pcf.forwarding.Forwarding.rewriteClientIntention; import static org.adde0109.pcf.forwarding.ReflectionUtils.attributeKeyValueOf; import static org.adde0109.pcf.forwarding.ReflectionUtils.getName; import static org.adde0109.pcf.forwarding.ReflectionUtils.getProperties; @@ -24,10 +26,8 @@ import dev.neuralnexus.taterapi.network.FriendlyByteBuf; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; import dev.neuralnexus.taterapi.network.protocol.handshake.ClientIntent; -import dev.neuralnexus.taterapi.network.protocol.handshake.ClientIntentionPacket; import io.netty.channel.Channel; -import io.netty.handler.codec.DecoderException; import io.netty.util.AttributeKey; import org.adde0109.pcf.PCF; @@ -73,7 +73,6 @@ public final class LegacyForwarding { // Use Type b/c GSON shipped with MC 1.19.2 doesn't have Gson#fromJson(String, TypeToken) private static final Type profileTypeToken = new TypeToken>() {}.getType(); - private static final Pattern HOST_PATTERN = Pattern.compile("[0-9a-f.:]{0,45}"); private static final Pattern PROP_PATTERN = Pattern.compile("\\w{0,16}"); private static final String LEGACY_FORGE_MARKER = "\0FML\0"; @@ -91,16 +90,7 @@ public static void handleClientIntention( final @NonNull ConnectionBridge connection, final @NonNull FriendlyByteBuf data) { // Read the original packet final int protocolVersion = data.readVarInt(); - final String hostName; - try { - hostName = data.readUtf(Short.MAX_VALUE); - } catch (final DecoderException e) { - if (e.getMessage().startsWith("Not enough bytes in buffer")) { - PCF.logger.debug("Received out-of-band LOGIN ServerBoundHelloPacket"); - throw new ThrowingComponent(LEGACY_DIRECT_CONNECT_ERR); - } - throw e; - } + final String hostName = data.readUtf(Short.MAX_VALUE); final int hostPort = data.readUnsignedShort(); final ClientIntent intention = ClientIntent.byId(data.readVarInt()); if (intention != ClientIntent.LOGIN) { @@ -115,6 +105,8 @@ public static void handleClientIntention( } if (PCF.instance().forwarding().mode() == Mode.BUNGEEGUARD && (split.length < 4 || !split[3].contains(BUNGEE_GUARD_TOKEN_PROPERTY_NAME))) { + // Rewrite the packet before throwing + rewriteClientIntention(channel, protocolVersion, split[0], hostPort, intention, data); throw new ThrowingComponent(BG_CONFIG_ERR); } @@ -169,12 +161,7 @@ public static void handleClientIntention( // spotless:on // Write the original address (and Forge marker) back into packet - final ClientIntentionPacket newPacket = - new ClientIntentionPacket(protocolVersion, host, hostPort, intention); - data.clear(); - data.writeVarInt(0x00); - ClientIntentionPacket.STREAM_CODEC.encode(data, newPacket); - PCF.logger.debug("Rewrote ClientIntentionPacket for " + channel.remoteAddress()); + rewriteClientIntention(channel, protocolVersion, host, hostPort, intention, data); } /** diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java index 3457bf3f..695160e8 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/modern/ModernForwarding.java @@ -3,7 +3,9 @@ import static dev.neuralnexus.taterapi.network.chat.Component.literal; import static dev.neuralnexus.taterapi.network.chat.Component.translatable; +import static org.adde0109.pcf.forwarding.Forwarding.HOST_PATTERN; import static org.adde0109.pcf.forwarding.Forwarding.PLAYER_INFO_ERR; +import static org.adde0109.pcf.forwarding.Forwarding.rewriteClientIntention; import static org.adde0109.pcf.forwarding.ReflectionUtils.attributeKeyValueOf; import static org.adde0109.pcf.forwarding.ReflectionUtils.enforceSecureProfile; import static org.adde0109.pcf.forwarding.modern.VelocityProxy.MODERN_MAX_VERSION; @@ -15,7 +17,6 @@ import dev.neuralnexus.taterapi.network.FriendlyByteBuf; import dev.neuralnexus.taterapi.network.chat.ThrowingComponent; import dev.neuralnexus.taterapi.network.protocol.handshake.ClientIntent; -import dev.neuralnexus.taterapi.network.protocol.handshake.ClientIntentionPacket; import dev.neuralnexus.taterapi.network.protocol.login.ClientboundCustomQueryPacket; import dev.neuralnexus.taterapi.network.protocol.login.ServerboundCustomQueryAnswerPacket; import dev.neuralnexus.taterapi.network.protocol.login.custom.CustomQueryAnswerPayload; @@ -84,19 +85,12 @@ public static void handleClientIntention( // Parse the host name for forwarded data final String[] split = hostName.split("\0"); - if (split.length >= 2 && (split[1].startsWith("FML") || split[1].startsWith("FORGE"))) { - return; // Modded client - } else if (split.length < 2) { - return; // Likely a normal connection + if (split.length < 3 || !(HOST_PATTERN.matcher(split[1]).matches())) { + return; // Either vanilla or direct modded connection } - // Rewrite the packet so the player can enter the login phase - final ClientIntentionPacket newPacket = - new ClientIntentionPacket(protocolVersion, split[0], hostPort, intention); - data.clear(); - data.writeVarInt(0x00); - ClientIntentionPacket.STREAM_CODEC.encode(data, newPacket); - PCF.logger.debug("Rewrote ClientIntentionPacket for " + channel.remoteAddress()); + // Rewrite packet + rewriteClientIntention(channel, protocolVersion, split[0], hostPort, intention, data); // Disconnect the user throw new ThrowingComponent(MODERN_DIRECT_CONNECT_ERR); From 2488f7c5cad70664ec6e2f5e7b19bc68524c77d5 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Sat, 2 May 2026 00:05:07 -0600 Subject: [PATCH 70/71] Adjusted implementation to make use of "modernForgeClient" property --- .../forwarding/legacy/LegacyForwarding.java | 44 ++++++++++++++----- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java index 40898c8b..8d0d2111 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/legacy/LegacyForwarding.java @@ -53,7 +53,9 @@ * href="https://hub.spigotmc.org/stash/projects/SPIGOT/repos/spigot/browse/CraftBukkit-Patches/0024-BungeeCord-Support.patch">Spigot * and BungeeForge. - * Additional information sourced from Velocity and Velocity + * and Waterfall */ public final class LegacyForwarding { @@ -77,7 +79,8 @@ public final class LegacyForwarding { private static final String LEGACY_FORGE_MARKER = "\0FML\0"; private static final String EXTRA_DATA_PROPERTY = "extraData"; - private static final String FORGE_CLIENT_PROPERTY = "forgeClient"; + private static final String LEGACY_FORGE_CLIENT_PROPERTY = "forgeClient"; + private static final String MODERN_FORGE_CLIENT_PROPERTY = "modernForgeClient"; private static final String FORGE_CLIENT_TRUE = "true"; /** @@ -119,31 +122,44 @@ public static void handleClientIntention( channel.attr(SPOOFED_UUID).set(uuid); // spotless:off - final boolean forgeClient; + final boolean legacyForgeClient; + final boolean modernForgeClient; final Optional extraData; if (split.length >= 4) { final String profileJSON = split[3]; final List properties = GSON.fromJson(profileJSON, profileTypeToken); // Pop out the Forge properties - forgeClient = properties.stream().anyMatch(p -> - getName(p).equals(FORGE_CLIENT_PROPERTY) && getValue(p).equals(FORGE_CLIENT_TRUE)); + legacyForgeClient = properties.stream().anyMatch(p -> + getName(p).equals(LEGACY_FORGE_CLIENT_PROPERTY) && getValue(p).equals(FORGE_CLIENT_TRUE)); + modernForgeClient = properties.stream().anyMatch(p -> + getName(p).equals(MODERN_FORGE_CLIENT_PROPERTY) && getValue(p).equals(FORGE_CLIENT_TRUE)); extraData = properties.stream() .filter(p -> getName(p).equals(EXTRA_DATA_PROPERTY)).findFirst(); - properties.removeIf(p -> - getName(p).equals(FORGE_CLIENT_PROPERTY) || getName(p).equals(EXTRA_DATA_PROPERTY)); + properties.removeIf(p -> getName(p).equals(LEGACY_FORGE_CLIENT_PROPERTY) + || getName(p).equals(MODERN_FORGE_CLIENT_PROPERTY) + || getName(p).equals(EXTRA_DATA_PROPERTY)); channel.attr(SPOOFED_PROFILE).set(properties); } else { - forgeClient = false; + legacyForgeClient = false; + modernForgeClient = false; extraData = Optional.empty(); } final String host; if (extraData.isPresent()) { final String value = getValue(extraData.get()); - if (!forgeClient) { // Unlikely, but notable - PCF.logger.debug("Received extraData without forgeClient=true from " - + channel.remoteAddress() + " - value: " + value); + if (PCF.instance().debug().enabled()) { + if (legacyForgeClient) { + PCF.logger.debug("Received extraData with forgeClient=true from " + + channel.remoteAddress() + " - value: " + value); + } else if (modernForgeClient) { + PCF.logger.debug("Received extraData with modernForgeClient=true from " + + channel.remoteAddress() + " - value: " + value); + } else { // Some implementations do this + PCF.logger.debug("Received extraData without (modernF|f)orgeClient=true from " + + channel.remoteAddress() + " - value: " + value); + } } if (value.startsWith("\1")) { // Restore extra hostname data host = originalHost + value.replace("\1", "\0"); @@ -152,7 +168,11 @@ public static void handleClientIntention( + channel.remoteAddress() + " - value: " + value); host = originalHost; } - } else if (forgeClient) { // Assume Forge 1.8 - 1.12.2 + } else if (legacyForgeClient) { // Assume Forge 1.8 - 1.12.2 + if (PCF.instance().debug().enabled()) { + PCF.logger.debug("Identified legacy Forge client from " + channel.remoteAddress() + + " - appending legacy Forge marker to hostname"); + } host = originalHost + LEGACY_FORGE_MARKER; } else { host = originalHost; From e50784fd16b6a0a5474be8264030c7728ed7f159 Mon Sep 17 00:00:00 2001 From: p0t4t0sandwich Date: Sat, 2 May 2026 00:05:17 -0600 Subject: [PATCH 71/71] Slight logging change --- .../main/java/org/adde0109/pcf/forwarding/PacketDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java index 2f9b6f9a..828bc605 100644 --- a/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java +++ b/common/src/main/java/org/adde0109/pcf/forwarding/PacketDecoder.java @@ -94,7 +94,7 @@ protected void decode( msg.readerIndex(readerIndex); debugInfo .append( - ", Handling out-of-band PLAY accept teleportation packet:") + ", Deferring out-of-band PLAY accept teleportation packet:") .append("\n - Packet Length: ") .append(data.readableBytes()) .append("\n - Packet data: 0x")