Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
4e73f26
ConnectionBridge now has a helper method for querying the protocol ph…
p0t4t0sandwich Apr 22, 2026
37946ba
Version bump
p0t4t0sandwich Apr 22, 2026
ff7aed1
Beginnings of legacy forwarding support
p0t4t0sandwich Apr 22, 2026
23be520
Relocated ConnectionBridge and PacketEncoder/Decoder
p0t4t0sandwich Apr 22, 2026
6565622
Disable mixins in the forwarding.legacy package if the mode is not LE…
p0t4t0sandwich Apr 22, 2026
4dbdfc8
Missed a package change
p0t4t0sandwich Apr 22, 2026
7e51f45
Moved intention packet handling into the decoder
p0t4t0sandwich Apr 22, 2026
cf2bf1b
Switch to using a Netty attribute for modern forwarding login message…
p0t4t0sandwich Apr 22, 2026
07a6a79
Move SLPL impl mixins into the common forwarding package
p0t4t0sandwich Apr 22, 2026
202021a
Pulled profile parsing and util methods into LegacyForwarding
p0t4t0sandwich Apr 22, 2026
578fe3c
Move error future listener to ConnectionBridge
p0t4t0sandwich Apr 23, 2026
2ab842b
Removed forwarding mode NONE, as it's somewhat redundant on the backend
p0t4t0sandwich Apr 23, 2026
48f9e44
Renamed PostProcessor to PreLoginHandler to better describe its purpo…
p0t4t0sandwich Apr 23, 2026
bf87a73
Added helper methods to Mode to aid with differentiating between Lega…
p0t4t0sandwich Apr 23, 2026
e0f793a
Legacy and BungeeGuard forwarding implemented
p0t4t0sandwich Apr 23, 2026
fff78b8
Reorganize init
p0t4t0sandwich Apr 23, 2026
e5de986
Remove frivolous forwarding type checks
p0t4t0sandwich Apr 23, 2026
3405b96
Clean up PreLoginHandler init
p0t4t0sandwich Apr 23, 2026
f181766
Pull handleHello mixins up a level and create a common delegate that …
p0t4t0sandwich Apr 23, 2026
638bcc8
Added bridge$disconnect to ConnectionBridge to allow for disconnects …
p0t4t0sandwich Apr 23, 2026
67bc7b8
Didn't work as expected due to handing the handshake too early, now d…
p0t4t0sandwich Apr 23, 2026
6397f19
Removed ConnectionBridge disconnect helper method
p0t4t0sandwich Apr 23, 2026
375b7e7
Cleaned up forwarding impls and pulled out common code
p0t4t0sandwich Apr 23, 2026
74dae2d
Tidied things up some more
p0t4t0sandwich Apr 24, 2026
749e720
1.7.10 doesn't have access to AttributeKey.valueOf
p0t4t0sandwich Apr 24, 2026
1207d47
Fixed 1.7.10 chat component handling
p0t4t0sandwich Apr 24, 2026
0976935
Remove copy task from main buildscript
p0t4t0sandwich Apr 24, 2026
88dbf10
ConnectionBridge now has a helper method for querying the protocol ph…
p0t4t0sandwich Apr 22, 2026
6f68684
Merge updates from main
p0t4t0sandwich Apr 22, 2026
9d7d7a2
Beginnings of legacy forwarding support
p0t4t0sandwich Apr 22, 2026
9f548b4
Relocated ConnectionBridge and PacketEncoder/Decoder
p0t4t0sandwich Apr 22, 2026
51853c8
Disable mixins in the forwarding.legacy package if the mode is not LE…
p0t4t0sandwich Apr 22, 2026
21361ac
Missed a package change
p0t4t0sandwich Apr 22, 2026
09d8cf7
Moved intention packet handling into the decoder
p0t4t0sandwich Apr 22, 2026
8a23781
Switch to using a Netty attribute for modern forwarding login message…
p0t4t0sandwich Apr 22, 2026
ec80fba
Move SLPL impl mixins into the common forwarding package
p0t4t0sandwich Apr 22, 2026
a47be7b
Pulled profile parsing and util methods into LegacyForwarding
p0t4t0sandwich Apr 22, 2026
40f4829
Move error future listener to ConnectionBridge
p0t4t0sandwich Apr 23, 2026
0f09b95
Removed forwarding mode NONE, as it's somewhat redundant on the backend
p0t4t0sandwich Apr 23, 2026
719e444
Renamed PostProcessor to PreLoginHandler to better describe its purpo…
p0t4t0sandwich Apr 23, 2026
a49d2a1
Added helper methods to Mode to aid with differentiating between Lega…
p0t4t0sandwich Apr 23, 2026
8f07bb4
Legacy and BungeeGuard forwarding implemented
p0t4t0sandwich Apr 23, 2026
0a675c7
Reorganize init
p0t4t0sandwich Apr 23, 2026
01dab56
Remove frivolous forwarding type checks
p0t4t0sandwich Apr 23, 2026
bc756e9
Clean up PreLoginHandler init
p0t4t0sandwich Apr 23, 2026
f69b222
Pull handleHello mixins up a level and create a common delegate that …
p0t4t0sandwich Apr 23, 2026
4bf230c
Added bridge$disconnect to ConnectionBridge to allow for disconnects …
p0t4t0sandwich Apr 23, 2026
e742b78
Didn't work as expected due to handing the handshake too early, now d…
p0t4t0sandwich Apr 23, 2026
65c894b
Removed ConnectionBridge disconnect helper method
p0t4t0sandwich Apr 23, 2026
b13f4ff
Cleaned up forwarding impls and pulled out common code
p0t4t0sandwich Apr 23, 2026
cb0dc92
Tidied things up some more
p0t4t0sandwich Apr 24, 2026
9df36c8
1.7.10 doesn't have access to AttributeKey.valueOf
p0t4t0sandwich Apr 24, 2026
2b71205
Fixed 1.7.10 chat component handling
p0t4t0sandwich Apr 24, 2026
a95d432
Setup online tests (to be reverted pre-merge)
p0t4t0sandwich Apr 26, 2026
9c27118
Bump TaterLibLite version to fix ffapi dual-platform detection when c…
p0t4t0sandwich Apr 27, 2026
fed611e
Forgot to reset reader index when login query payload is unhandled
p0t4t0sandwich Apr 27, 2026
3555c1c
Merge remote-tracking branch 'origin/snapshot/v1.3.0' into snapshot/v…
p0t4t0sandwich Apr 27, 2026
257d6b3
Added the ability to use either a JVM arg or env var to set the forwa…
p0t4t0sandwich Apr 27, 2026
d114d4a
Overhauled the test system to support generating runs for modern, leg…
p0t4t0sandwich Apr 27, 2026
6c62ca4
Added an error logger to the decoder to account for versions that don…
p0t4t0sandwich Apr 27, 2026
c5aa8f6
Fixed version-specific method issue
p0t4t0sandwich Apr 27, 2026
63f1494
Fixed 1.19.2 GSON issue
p0t4t0sandwich Apr 27, 2026
89b3112
Added legacy config to template files
p0t4t0sandwich Apr 27, 2026
72029ad
Add vanilla client run tasks for when sanity checks are needed
p0t4t0sandwich Apr 28, 2026
9e4d5f8
Added more packet logging
p0t4t0sandwich Apr 28, 2026
d50250f
Mode debug logging, and improved Forge token parsing
p0t4t0sandwich Apr 28, 2026
6f11193
More debug logging, temporary debug logging, and a couple temporary f…
p0t4t0sandwich Apr 30, 2026
2fe0c35
Improved modern and legacy Forge token parsing
p0t4t0sandwich Apr 30, 2026
145bdae
Modified modern forwarding so the handshake packet is rewritten if it…
p0t4t0sandwich Apr 30, 2026
f051af4
Properly fixed the ClientIntention rewriting
p0t4t0sandwich Apr 30, 2026
2488f7c
Adjusted implementation to make use of "modernForgeClient" property
p0t4t0sandwich May 2, 2026
e50784f
Slight logging change
p0t4t0sandwich May 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
112 changes: 72 additions & 40 deletions common/src/main/java/org/adde0109/pcf/PCF.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -15,11 +17,12 @@
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;
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;
Expand Down Expand Up @@ -78,49 +81,40 @@ void onInit() {
}
loader.onInit();

// Modern forwarding init
if (this.forwarding().enabled() && this.forwarding().mode().equals(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");
logger.debug("Arclight detected, applying pre-login handler");
if (Constraint.range(MinecraftVersions.V14, MinecraftVersions.V20_1).result()) {
ModernForwarding.postProcessors.removeFirst();
ModernForwarding.postProcessors.add(
(slpl, profile, c) -> {
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.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.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) -> {
logger.debug("Mohist detected, applying pre-login handler");
HANDLERS.add(
(slpl, profile, _) -> {
slpl.bridge$setGameProfile(profile);
MohistPreLogin.V20_1.fireEvents(slpl);
});
} else if (Constraint.builder()
.platform(Platforms.YOUER)
.version(MinecraftVersions.V21_1)
.result()) {
logger.debug("Youer detected, applying pre-login post processor");
ModernForwarding.postProcessors.removeFirst();
ModernForwarding.postProcessors.add(
(slpl, profile, c) -> {
logger.debug("Youer detected, applying pre-login handler");
HANDLERS.add(
(slpl, profile, _) -> {
MohistPreLogin.Youer.fireEvents(slpl, profile);
slpl.bridge$startClientVerification(profile);
});
Expand All @@ -135,10 +129,9 @@ void onInit() {
.platform(Platforms.MAGMA, Platforms.KETTING)
.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) -> {
logger.debug("Forge+Bukkit hybrid detected, applying pre-login handler");
HANDLERS.add(
(slpl, profile, _) -> {
slpl.bridge$setGameProfile(profile);
SpigotPreLogin.Legacy.fireEvents(slpl);
});
Expand All @@ -150,11 +143,8 @@ void onInit() {
.platform(Platforms.MOHIST)
.version(MinecraftVersions.V20_2))
.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));
logger.debug("[Neo]Forge+Bukkit hybrid detected, applying pre-login handler");
HANDLERS.add((slpl, profile, _) -> SpigotPreLogin.V20_2.fireEvents(slpl, profile));
} else if (Constraints.builder()
.or(
Constraint.builder()
Expand All @@ -169,25 +159,43 @@ 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");
ModernForwarding.postProcessors.addFirst(
(slpl, profile, c) ->
logger.debug("[Neo]Forge+Bukkit hybrid detected, applying pre-login handler");
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)
.platform(Platforms.SPONGE)
.result()) {
logger.debug("SpongeAPI 8 or 9 detected, applying pre-login post processor");
ModernForwarding.postProcessors.addFirst(
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));
});
}
}

// 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("Forwarding mode set to BungeeGuard, applying pre-login handler");
HANDLERS.addFirst(BungeeGuard::validateToken);
}

Constraint.Evaluator.DEBUG = debug;
}

Expand Down Expand Up @@ -225,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;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package org.adde0109.pcf.forwarding;

import dev.neuralnexus.taterapi.network.Protocol;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.concurrent.Future;

import org.adde0109.pcf.PCF;
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(ConnectionBridge::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;
}
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())
.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<? super Void> future) {
if (!future.isSuccess()) {
PCF.logger.error("An error occurred during packet handling", future.cause());
}
}
}
Loading