diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/ConnectionListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/ConnectionListener.java index 2bacbc5d..33b5c425 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/ConnectionListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/ConnectionListener.java @@ -90,6 +90,7 @@ public class ConnectionListener implements Listener { if (floodgatePlayer != null) { Runnable floodgateAuthTask = new FloodgateAuthTask(plugin.getCore(), player, floodgatePlayer); Bukkit.getScheduler().runTaskAsynchronously(plugin, floodgateAuthTask); + plugin.getBungeeManager().markJoinEventFired(player); return; } } diff --git a/velocity/src/main/java/com/github/games647/fastlogin/velocity/FastLoginVelocity.java b/velocity/src/main/java/com/github/games647/fastlogin/velocity/FastLoginVelocity.java index 2dd1f2a4..26217b83 100644 --- a/velocity/src/main/java/com/github/games647/fastlogin/velocity/FastLoginVelocity.java +++ b/velocity/src/main/java/com/github/games647/fastlogin/velocity/FastLoginVelocity.java @@ -230,4 +230,8 @@ public class FastLoginVelocity implements PlatformPlugin { public UUID getProxyId() { return proxyId; } + + public ProxyServer getServer() { + return server; + } } diff --git a/velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/ConnectListener.java b/velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/ConnectListener.java index 98e2191a..90513b23 100644 --- a/velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/ConnectListener.java +++ b/velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/ConnectListener.java @@ -36,6 +36,9 @@ import com.github.games647.fastlogin.velocity.VelocityLoginSession; import com.github.games647.fastlogin.velocity.task.AsyncPremiumCheck; import com.github.games647.fastlogin.velocity.task.FloodgateAuthTask; import com.github.games647.fastlogin.velocity.task.ForceLoginTask; +import com.google.common.cache.Cache; +import com.google.common.collect.ListMultimap; +import com.velocitypowered.api.event.EventManager; import com.velocitypowered.api.event.EventTask; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.connection.DisconnectEvent; @@ -43,6 +46,7 @@ import com.velocitypowered.api.event.connection.PreLoginEvent; import com.velocitypowered.api.event.connection.PreLoginEvent.PreLoginComponentResult; import com.velocitypowered.api.event.player.GameProfileRequestEvent; import com.velocitypowered.api.event.player.ServerConnectedEvent; +import com.velocitypowered.api.plugin.PluginContainer; import com.velocitypowered.api.proxy.InboundConnection; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.server.RegisteredServer; @@ -52,6 +56,7 @@ import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.geysermc.floodgate.api.player.FloodgatePlayer; +import java.lang.reflect.Field; import java.net.InetSocketAddress; import java.time.Duration; import java.util.ArrayList; @@ -61,6 +66,8 @@ import java.util.UUID; public class ConnectListener { + private static final String FLOODGATE_PLUGIN_NAME = "org.geysermc.floodgate.VelocityPlugin"; + private final FastLoginVelocity plugin; private final AntiBotService antiBotService; @@ -80,6 +87,15 @@ public class ConnectListener { InetSocketAddress address = connection.getRemoteAddress(); plugin.getLog().info("Incoming login request for {} from {}", username, address); + // FloodgateVelocity only sets the correct username in GetProfileRequestEvent, but we need it here too. + if (plugin.getFloodgateService() != null) { + String floodgateUsername = getFloodgateUsername(connection); + if (floodgateUsername != null) { + plugin.getLog().info("Found player's Floodgate: {}", floodgateUsername); + username = floodgateUsername; + } + } + Action action = antiBotService.onIncomingConnection(address, username); switch (action) { case Ignore: @@ -177,4 +193,74 @@ public class ConnectListener { Player player = disconnectEvent.getPlayer(); plugin.getCore().getPendingConfirms().remove(player.getUniqueId()); } + + /** + * Get the Floodgate username from the Floodgate plugin's playerCache using lots of reflections + * + * @param connection + * @return the Floodgate username or null if not found + */ + private String getFloodgateUsername(InboundConnection connection) { + try { + // get floodgate's event handler + Object floodgateEventHandler = getFloodgateHandler(); + if (floodgateEventHandler == null) { + return null; + } + + // Get the Floodgate playerCache field + Field playerCacheField = floodgateEventHandler.getClass().getDeclaredField("playerCache"); + playerCacheField.setAccessible(true); + @SuppressWarnings("unchecked") + Cache playerCache = + (Cache) playerCacheField.get(floodgateEventHandler); + + // Find the FloodgatePlayer instance in playerCache + FloodgatePlayer floodgatePlayer = playerCache.getIfPresent(connection); + if (floodgatePlayer == null) { + return null; + } + + return floodgatePlayer.getCorrectUsername(); + } catch (Exception ex) { + plugin.getLog().error("Failed to fetch current floodgate username", ex); + } + + return null; + } + + private Object getFloodgateHandler() + throws NoSuchFieldException, IllegalAccessException { + // Get Velocity's event manager + EventManager eventManager = plugin.getServer().getEventManager(); + Field handlerField = eventManager.getClass().getDeclaredField("handlersByType"); + handlerField.setAccessible(true); + @SuppressWarnings("unchecked") + ListMultimap, ?> handlersByType = (ListMultimap, ?>) handlerField.get(eventManager); + + // Get all registered PreLoginEvent handlers + List loginEventRegistrations = handlersByType.get(PreLoginEvent.class); + Field pluginField = loginEventRegistrations.get(0).getClass().getDeclaredField("plugin"); + pluginField.setAccessible(true); + + // Find the Floodgate plugin's PreLoginEvent handler registration (Velocity implementation) + Object floodgateRegistration = null; + for (Object handler : loginEventRegistrations) { + PluginContainer eventHandlerPlugin = (PluginContainer) pluginField.get(handler); + String eventHandlerPluginName = eventHandlerPlugin.getInstance().get().getClass().getName(); + if (eventHandlerPluginName.equals(FLOODGATE_PLUGIN_NAME)) { + floodgateRegistration = handler; + break; + } + } + + if (floodgateRegistration == null) { + return null; + } + + // Extract the EventHandler instance (floodgate impl) from Velocity's internal registration handler storage + Field eventHandlerField = floodgateRegistration.getClass().getDeclaredField("instance"); + eventHandlerField.setAccessible(true); + return eventHandlerField.get(floodgateRegistration); + } }