Skip to content

Commit 2d177e3

Browse files
committed
Retrieve and use Floodgate username in Velocity PreLoginEvent
1 parent bdd7af8 commit 2d177e3

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

velocity/src/main/java/com/github/games647/fastlogin/velocity/FastLoginVelocity.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,4 +230,8 @@ private void loadOrGenerateProxyId() {
230230
public UUID getProxyId() {
231231
return proxyId;
232232
}
233+
234+
public ProxyServer getServer() {
235+
return server;
236+
}
233237
}

velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/ConnectListener.java

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,22 +36,27 @@
3636
import com.github.games647.fastlogin.velocity.task.AsyncPremiumCheck;
3737
import com.github.games647.fastlogin.velocity.task.FloodgateAuthTask;
3838
import com.github.games647.fastlogin.velocity.task.ForceLoginTask;
39+
import com.google.common.cache.Cache;
40+
import com.google.common.collect.ListMultimap;
3941
import com.velocitypowered.api.event.EventTask;
4042
import com.velocitypowered.api.event.Subscribe;
4143
import com.velocitypowered.api.event.connection.DisconnectEvent;
4244
import com.velocitypowered.api.event.connection.PreLoginEvent;
4345
import com.velocitypowered.api.event.connection.PreLoginEvent.PreLoginComponentResult;
4446
import com.velocitypowered.api.event.player.GameProfileRequestEvent;
4547
import com.velocitypowered.api.event.player.ServerConnectedEvent;
48+
import com.velocitypowered.api.plugin.PluginContainer;
4649
import com.velocitypowered.api.proxy.InboundConnection;
4750
import com.velocitypowered.api.proxy.Player;
4851
import com.velocitypowered.api.proxy.server.RegisteredServer;
4952
import com.velocitypowered.api.util.GameProfile;
5053
import com.velocitypowered.api.util.GameProfile.Property;
54+
5155
import net.kyori.adventure.text.TextComponent;
5256
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
5357
import org.geysermc.floodgate.api.player.FloodgatePlayer;
5458

59+
import java.lang.reflect.Field;
5560
import java.net.InetSocketAddress;
5661
import java.time.Duration;
5762
import java.util.ArrayList;
@@ -61,6 +66,8 @@
6166

6267
public class ConnectListener {
6368

69+
private static final String FLOODGATE_PLUGIN_NAME = "org.geysermc.floodgate.VelocityPlugin";
70+
6471
private final FastLoginVelocity plugin;
6572
private final AntiBotService antiBotService;
6673

@@ -80,6 +87,16 @@ public EventTask onPreLogin(PreLoginEvent preLoginEvent) {
8087
InetSocketAddress address = connection.getRemoteAddress();
8188
plugin.getLog().info("Incoming login request for {} from {}", username, address);
8289

90+
91+
// FloodgateVelocity only sets the correct username in GetProfileRequestEvent, but we need it here too.
92+
if (plugin.getFloodgateService() != null) {
93+
String floodgateUsername = getFloodgateUsername(preLoginEvent, connection);
94+
if (floodgateUsername != null) {
95+
plugin.getLog().info("Found player's Floodgate: {}", floodgateUsername);
96+
username = floodgateUsername;
97+
}
98+
}
99+
83100
Action action = antiBotService.onIncomingConnection(address, username);
84101
switch (action) {
85102
case Ignore:
@@ -177,4 +194,68 @@ public void onDisconnect(DisconnectEvent disconnectEvent) {
177194
Player player = disconnectEvent.getPlayer();
178195
plugin.getCore().getPendingConfirms().remove(player.getUniqueId());
179196
}
197+
198+
/**
199+
* Get the Floodgate username from the Floodgate plugin's playerCache using lots of reflections
200+
* @param preLoginEvent
201+
* @param connection
202+
* @return the Floodgate username or null if not found
203+
*/
204+
private String getFloodgateUsername(PreLoginEvent preLoginEvent, InboundConnection connection) {
205+
try {
206+
// Get Velocity's event manager
207+
Object eventManager = plugin.getServer().getEventManager();
208+
Field handlerField = eventManager.getClass().getDeclaredField("handlersByType");
209+
handlerField.setAccessible(true);
210+
@SuppressWarnings("rawtypes")
211+
ListMultimap handlersByType = (ListMultimap) handlerField.get(eventManager);
212+
handlerField.setAccessible(false);
213+
214+
// Get all registered PreLoginEvent handlers
215+
@SuppressWarnings({ "rawtypes", "unchecked" })
216+
List preLoginEventHandlres = handlersByType.get(preLoginEvent.getClass());
217+
Field pluginField = preLoginEventHandlres.get(0).getClass().getDeclaredField("plugin");
218+
pluginField.setAccessible(true);
219+
Object floodgateEventHandlerRegistration = null;
220+
221+
// Find the Floodgate plugin's PreLoginEvent handler
222+
for (Object handler : preLoginEventHandlres) {
223+
PluginContainer eventHandlerPlugin = (PluginContainer) pluginField.get(handler);
224+
String eventHandlerPluginName = eventHandlerPlugin.getInstance().get().getClass().getName();
225+
if (eventHandlerPluginName.equals(FLOODGATE_PLUGIN_NAME)) {
226+
floodgateEventHandlerRegistration = handler;
227+
break;
228+
}
229+
}
230+
pluginField.setAccessible(false);
231+
if (floodgateEventHandlerRegistration == null) {
232+
return null;
233+
}
234+
235+
// Extract the EventHandler instance from Velocity's internal registration handler storage
236+
Field eventHandlerField = floodgateEventHandlerRegistration.getClass().getDeclaredField("instance");
237+
eventHandlerField.setAccessible(true);
238+
Object floodgateEventHandler = eventHandlerField.get(floodgateEventHandlerRegistration);
239+
eventHandlerField.setAccessible(false);
240+
241+
// Get the Floodgate playerCache field
242+
Field playerCacheField = floodgateEventHandler.getClass().getDeclaredField("playerCache");
243+
playerCacheField.setAccessible(true);
244+
@SuppressWarnings("unchecked")
245+
Cache<InboundConnection, FloodgatePlayer> playerCache =
246+
(Cache<InboundConnection, FloodgatePlayer>) playerCacheField.get(floodgateEventHandler);
247+
playerCacheField.setAccessible(false);
248+
249+
// Find the FloodgatePlayer instance in playerCache
250+
FloodgatePlayer floodgatePlayer = playerCache.getIfPresent(connection);
251+
if (floodgatePlayer == null) {
252+
return null;
253+
}
254+
return floodgatePlayer.getCorrectUsername();
255+
256+
} catch (Exception e) {
257+
e.printStackTrace();
258+
}
259+
return null;
260+
}
180261
}

0 commit comments

Comments
 (0)