diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeConnectionType.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeConnectionType.java index 45d19844e5..5337606071 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeConnectionType.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeConnectionType.java @@ -38,11 +38,11 @@ public LegacyForgeConnectionType() { @Override public GameProfile addGameProfileTokensIfRequired(GameProfile original, PlayerInfoForwarding forwardingType) { - // We can't forward the FML token to the server when we are running in legacy forwarding mode, + // We can't forward the FML token to the server when we are running in legacy (or bungeeguard) forwarding mode, // since both use the "hostname" field in the handshake. We add a special property to the // profile instead, which will be ignored by non-Forge servers and can be intercepted by a // Forge coremod, such as SpongeForge. - if (forwardingType == PlayerInfoForwarding.LEGACY) { + if (forwardingType == PlayerInfoForwarding.LEGACY || forwardingType == PlayerInfoForwarding.BUNGEEGUARD) { return original.addProperty(IS_FORGE_CLIENT_PROPERTY); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/modern/ModernForgeConnectionType.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/modern/ModernForgeConnectionType.java index d58e4eae05..01f992643f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/modern/ModernForgeConnectionType.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/modern/ModernForgeConnectionType.java @@ -17,14 +17,18 @@ package com.velocitypowered.proxy.connection.forge.modern; +import static com.velocitypowered.proxy.connection.forge.modern.ModernForgeConstants.EXTRA_DATA_PROPERTY; +import static com.velocitypowered.proxy.connection.forge.modern.ModernForgeConstants.IS_MODERN_FORGE_CLIENT_PROPERTY; import static com.velocitypowered.proxy.connection.forge.modern.ModernForgeConstants.MODERN_FORGE_TOKEN; +import com.velocitypowered.api.util.GameProfile; +import com.velocitypowered.proxy.config.PlayerInfoForwarding; import com.velocitypowered.proxy.connection.backend.BackendConnectionPhases; import com.velocitypowered.proxy.connection.client.ClientConnectionPhases; import com.velocitypowered.proxy.connection.util.ConnectionTypeImpl; /** - * Contains extra logic. + * Contains extra logic to handle Forge 1.20.2+ clients. */ public class ModernForgeConnectionType extends ConnectionTypeImpl { @@ -44,22 +48,38 @@ public ModernForgeConnectionType(String hostName) { /** * Align the acquisition logic with the internal code of Forge. * - * @return returns the final correct hostname + * @return returns the modern Forge token with the Net Version. */ public String getModernToken() { - int natVersion = 0; + int netVersion = 0; int idx = hostName.indexOf('\0'); if (idx != -1) { for (var pt : hostName.split("\0")) { if (pt.startsWith(MODERN_FORGE_TOKEN)) { if (pt.length() > MODERN_FORGE_TOKEN.length()) { - natVersion = Integer.parseInt( + netVersion = Integer.parseInt( pt.substring(MODERN_FORGE_TOKEN.length())); + break; } } } } - return natVersion == 0 ? "\0" + MODERN_FORGE_TOKEN : "\0" - + MODERN_FORGE_TOKEN + natVersion; + return MODERN_FORGE_TOKEN + (netVersion == 0 ? "" : netVersion); + } + + @Override + public GameProfile addGameProfileTokensIfRequired(GameProfile original, + PlayerInfoForwarding forwardingType) { + // We can't forward the FORGE token to the server when we are running in legacy (or bungeeguard) forwarding mode, + // since both use the "hostname" field in the handshake. We add a special property to the + // profile instead, which will be ignored by non-Forge servers and can be intercepted by a + // Forge coremod, such as SpongeForge, BungeeForge, or ProxyCompatibleForge. + if (forwardingType == PlayerInfoForwarding.LEGACY || forwardingType == PlayerInfoForwarding.BUNGEEGUARD) { + return original.addProperty(IS_MODERN_FORGE_CLIENT_PROPERTY) + .addProperty(EXTRA_DATA_PROPERTY.apply( + this.getModernToken().replaceAll("\0", "\1"))); + } + + return original; } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/modern/ModernForgeConstants.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/modern/ModernForgeConstants.java index 15add83bcc..8067660bf7 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/modern/ModernForgeConstants.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/modern/ModernForgeConstants.java @@ -17,9 +17,30 @@ package com.velocitypowered.proxy.connection.forge.modern; +import com.velocitypowered.api.util.GameProfile; +import java.util.function.Function; + /** * Constants for use with Modern Forge systems. */ public class ModernForgeConstants { - public static final String MODERN_FORGE_TOKEN = "FORGE"; + /** + * Clients attempting to connect to 1.20.2+ Forge servers will have this token appended to the + * hostname in the initial handshake packet. + */ + public static final String MODERN_FORGE_TOKEN = "\0FORGE"; + + /** + * Property used to identify a modern Forge client, used in tandem with "extraData". + */ + public static final String MODERN_FORGE_CLIENT = "modernForgeClient"; + public static final GameProfile.Property IS_MODERN_FORGE_CLIENT_PROPERTY = + new GameProfile.Property(MODERN_FORGE_CLIENT, "true", ""); + + /** + * Property used to forward the Forge marker with the Net Version to the backend server. + */ + public static final String EXTRA_DATA = "extraData"; + public static final Function EXTRA_DATA_PROPERTY = + (extraData) -> new GameProfile.Property(EXTRA_DATA, extraData, ""); }