Skip to content

Commit

Permalink
Merge pull request #1223 from Smart123s/fix/floodgate/velocity-1
Browse files Browse the repository at this point in the history
Floodgate Velocity fixes
  • Loading branch information
games647 authored Jul 8, 2024
2 parents bdd7af8 + 7f48849 commit 1a56741
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ private void delayForceLogin(Player player) {
if (floodgatePlayer != null) {
Runnable floodgateAuthTask = new FloodgateAuthTask(plugin.getCore(), player, floodgatePlayer);
Bukkit.getScheduler().runTaskAsynchronously(plugin, floodgateAuthTask);
plugin.getBungeeManager().markJoinEventFired(player);
return;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,4 +230,8 @@ private void loadOrGenerateProxyId() {
public UUID getProxyId() {
return proxyId;
}

public ProxyServer getServer() {
return server;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,17 @@
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;
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;
Expand All @@ -52,6 +56,7 @@
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;
Expand All @@ -61,6 +66,8 @@

public class ConnectListener {

private static final String FLOODGATE_PLUGIN_NAME = "org.geysermc.floodgate.VelocityPlugin";

private final FastLoginVelocity plugin;
private final AntiBotService antiBotService;

Expand All @@ -80,6 +87,15 @@ public EventTask onPreLogin(PreLoginEvent preLoginEvent) {
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:
Expand Down Expand Up @@ -177,4 +193,74 @@ public void onDisconnect(DisconnectEvent disconnectEvent) {
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<InboundConnection, FloodgatePlayer> playerCache =
(Cache<InboundConnection, FloodgatePlayer>) 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<Class<?>, ?> handlersByType = (ListMultimap<Class<?>, ?>) 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);
}
}

0 comments on commit 1a56741

Please sign in to comment.