Skip to content

Commit 119b9cb

Browse files
author
games647
authored
Merge pull request #494 from Smart123s/main
Floodgate support for Bukkit
2 parents 6b20b71 + d44ab4e commit 119b9cb

File tree

9 files changed

+258
-7
lines changed

9 files changed

+258
-7
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ nb-configuration.xml
1313
*.iws
1414
.idea/
1515

16+
# VSCode
17+
.vscode/
18+
1619
# Maven
1720
target/
1821
pom.xml.versionsBackup

bukkit/pom.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,12 @@
125125
<enabled>false</enabled>
126126
</snapshots>
127127
</repository>
128+
129+
<!-- Floodgate -->
130+
<repository>
131+
<id>nukkitx-snapshot</id>
132+
<url>https://repo.nukkitx.com/maven-snapshots/</url>
133+
</repository>
128134
</repositories>
129135

130136
<dependencies>
@@ -183,6 +189,14 @@
183189
</exclusions>
184190
</dependency>
185191

192+
<!--Floodgate for Xbox Live Authentication-->
193+
<dependency>
194+
<groupId>org.geysermc.floodgate</groupId>
195+
<artifactId>api</artifactId>
196+
<version>2.0-SNAPSHOT</version>
197+
<scope>provided</scope>
198+
</dependency>
199+
186200
<!--Login Plugins-->
187201
<dependency>
188202
<groupId>fr.xephi</groupId>

bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,13 @@
4747
import java.util.concurrent.ConcurrentHashMap;
4848
import java.util.concurrent.ConcurrentMap;
4949

50+
import org.bukkit.Bukkit;
51+
import org.bukkit.Server.Spigot;
5052
import org.bukkit.command.CommandSender;
5153
import org.bukkit.entity.Player;
5254
import org.bukkit.plugin.PluginManager;
5355
import org.bukkit.plugin.java.JavaPlugin;
56+
import org.geysermc.floodgate.api.FloodgateApi;
5457
import org.slf4j.Logger;
5558

5659
/**
@@ -86,6 +89,13 @@ public void onEnable() {
8689
setEnabled(false);
8790
return;
8891
}
92+
93+
// Check Floodgate config values
94+
if (!isValidFloodgateConfigString("autoLoginFloodgate")
95+
|| !isValidFloodgateConfigString("allowFloodgateNameConflict")) {
96+
setEnabled(false);
97+
return;
98+
}
8999

90100
bungeeManager = new BungeeManager(this);
91101
bungeeManager.initialize();
@@ -131,6 +141,8 @@ public void onEnable() {
131141
premiumPlaceholder = new PremiumPlaceholder(this);
132142
premiumPlaceholder.register();
133143
}
144+
145+
dependencyWarnings();
134146
}
135147

136148
@Override
@@ -237,4 +249,59 @@ public BukkitScheduler getScheduler() {
237249
public void sendMessage(CommandSender receiver, String message) {
238250
receiver.sendMessage(message);
239251
}
252+
253+
/**
254+
* Checks if a config entry (related to Floodgate) is valid. <br>
255+
* Writes to Log if the value is invalid.
256+
* <p>
257+
* This should be used for:
258+
* <ul>
259+
* <li>allowFloodgateNameConflict
260+
* <li>autoLoginFloodgate
261+
* </ul>
262+
* </p>
263+
*
264+
* @param key the key of the entry in config.yml
265+
* @return <b>true</b> if the entry's value is "true", "false", or "linked"
266+
*/
267+
private boolean isValidFloodgateConfigString(String key) {
268+
String value = core.getConfig().get(key).toString().toLowerCase();
269+
if (!value.equals("true") && !value.equals("linked") && !value.equals("false")) {
270+
logger.error("Invalid value detected for {} in FastLogin/config.yml.", key);
271+
return false;
272+
}
273+
return true;
274+
}
275+
276+
/**
277+
* Checks if a plugin is installed on the server
278+
* @param name the name of the plugin
279+
* @return true if the plugin is installed
280+
*/
281+
private boolean isPluginInstalled(String name) {
282+
//the plugin may be enabled after FastLogin, so isPluginEnabled()
283+
//won't work here
284+
return Bukkit.getServer().getPluginManager().getPlugin(name) != null;
285+
}
286+
287+
/**
288+
* Send warning messages to log if incompatible plugins are used
289+
*/
290+
private void dependencyWarnings() {
291+
if (isPluginInstalled("floodgate-bukkit")) {
292+
logger.warn("We have detected that you are runnging Floodgate 1.0 which is not supported by the Bukkit "
293+
+ "version of FastLogin.");
294+
logger.warn("If you would like to use FastLogin with Floodgate, you can download developement builds of "
295+
+ "Floodgate 2.0 from https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/dev%252F2.0/");
296+
logger.warn("Don't forget to update Geyser to a supported version as well from "
297+
+ "https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/floodgate-2.0/");
298+
} else if (isPluginInstalled("floodgate") && isPluginInstalled("ProtocolLib")) {
299+
logger.warn("We have detected that you are runnging FastLogin alongside Floodgate and ProtocolLib.");
300+
logger.warn("Currently there is an issue with FastLogin that prevents Floodgate name prefixes from showing up "
301+
+ "when it is together used with ProtocolLib.");
302+
logger.warn("If you would like to use Floodgate name prefixes, you can replace ProtocolLib with ProtocolSupport "
303+
+ "which does not have this issue.");
304+
logger.warn("For more information visit https://github.com/games647/FastLogin/issues/493");
305+
}
306+
}
240307
}

bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/ConnectionListener.java

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
2929
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
30+
import com.github.games647.fastlogin.bukkit.task.FloodgateAuthTask;
3031
import com.github.games647.fastlogin.bukkit.task.ForceLoginTask;
3132

3233
import org.bukkit.Bukkit;
@@ -37,6 +38,8 @@
3738
import org.bukkit.event.player.PlayerJoinEvent;
3839
import org.bukkit.event.player.PlayerLoginEvent;
3940
import org.bukkit.event.player.PlayerLoginEvent.Result;
41+
import org.geysermc.floodgate.api.FloodgateApi;
42+
import org.geysermc.floodgate.api.player.FloodgatePlayer;
4043
import org.bukkit.event.player.PlayerQuitEvent;
4144

4245
/**
@@ -70,13 +73,26 @@ public void onPlayerJoin(PlayerJoinEvent joinEvent) {
7073
// cases: Paper (firing BungeeCord message before PlayerJoinEvent) or not running BungeeCord and already
7174
// having the login session from the login process
7275
BukkitLoginSession session = plugin.getSession(player.getAddress());
73-
if (session == null) {
74-
String sessionId = plugin.getSessionId(player.getAddress());
75-
plugin.getLog().info("No on-going login session for player: {} with ID {}", player, sessionId);
76-
} else {
77-
Runnable forceLoginTask = new ForceLoginTask(plugin.getCore(), player, session);
78-
Bukkit.getScheduler().runTaskAsynchronously(plugin, forceLoginTask);
79-
}
76+
77+
boolean isFloodgateLogin = false;
78+
if (Bukkit.getServer().getPluginManager().isPluginEnabled("floodgate")) {
79+
FloodgatePlayer floodgatePlayer = FloodgateApi.getInstance().getPlayer(player.getUniqueId());
80+
if (floodgatePlayer != null) {
81+
isFloodgateLogin = true;
82+
Runnable floodgateAuthTask = new FloodgateAuthTask(plugin, player, floodgatePlayer);
83+
Bukkit.getScheduler().runTaskAsynchronously(plugin, floodgateAuthTask);
84+
}
85+
}
86+
87+
if (!isFloodgateLogin) {
88+
if (session == null) {
89+
String sessionId = plugin.getSessionId(player.getAddress());
90+
plugin.getLog().info("No on-going login session for player: {} with ID {}", player, sessionId);
91+
} else {
92+
Runnable forceLoginTask = new ForceLoginTask(plugin.getCore(), player, session);
93+
Bukkit.getScheduler().runTaskAsynchronously(plugin, forceLoginTask);
94+
}
95+
}
8096

8197
plugin.getBungeeManager().markJoinEventFired(player);
8298
// delay the login process to let auth plugins initialize the player

bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/NameCheckTask.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,11 @@
3737
import java.security.PublicKey;
3838
import java.util.Random;
3939

40+
import org.bukkit.Bukkit;
4041
import org.bukkit.command.CommandSender;
4142
import org.bukkit.entity.Player;
43+
import org.geysermc.floodgate.api.FloodgateApi;
44+
import org.geysermc.floodgate.api.player.FloodgatePlayer;
4245

4346
public class NameCheckTask extends JoinManagement<Player, CommandSender, ProtocolLibLoginSource>
4447
implements Runnable {
@@ -67,6 +70,12 @@ public NameCheckTask(FastLoginBukkit plugin, PacketEvent packetEvent, Random ran
6770
@Override
6871
public void run() {
6972
try {
73+
// check if the player is connecting through Geyser
74+
if (!plugin.getCore().getConfig().get("allowFloodgateNameConflict").toString().equalsIgnoreCase("false")
75+
&& getFloodgatePlayer(username) != null) {
76+
plugin.getLog().info("Skipping name conflict checking for player {}", username);
77+
return;
78+
}
7079
super.onLogin(username, new ProtocolLibLoginSource(packetEvent, player, random, publicKey));
7180
} finally {
7281
ProtocolLibrary.getProtocolManager().getAsynchronousManager().signalPacketTransmission(packetEvent);
@@ -111,4 +120,16 @@ public void startCrackedSession(ProtocolLibLoginSource source, StoredProfile pro
111120
BukkitLoginSession loginSession = new BukkitLoginSession(username, profile);
112121
plugin.putSession(player.getAddress(), loginSession);
113122
}
123+
124+
private static FloodgatePlayer getFloodgatePlayer(String username) {
125+
if (Bukkit.getServer().getPluginManager().isPluginEnabled("floodgate")) {
126+
// the Floodgate API requires UUID, which is inaccessible at NameCheckTask.java
127+
for (FloodgatePlayer floodgatePlayer : FloodgateApi.getInstance().getPlayers()) {
128+
if (floodgatePlayer.getUsername().equals(username)) {
129+
return floodgatePlayer;
130+
}
131+
}
132+
}
133+
return null;
134+
}
114135
}

bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocolsupport/ProtocolSupportListener.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import java.net.InetSocketAddress;
3838
import java.util.Optional;
3939

40+
import org.bukkit.Bukkit;
4041
import org.bukkit.command.CommandSender;
4142
import org.bukkit.entity.Player;
4243
import org.bukkit.event.EventHandler;
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package com.github.games647.fastlogin.bukkit.task;
2+
3+
import org.bukkit.Bukkit;
4+
import org.bukkit.entity.Player;
5+
import org.geysermc.floodgate.api.player.FloodgatePlayer;
6+
7+
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
8+
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
9+
import com.github.games647.fastlogin.core.StoredProfile;
10+
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
11+
12+
public class FloodgateAuthTask implements Runnable {
13+
14+
private final FastLoginBukkit plugin;
15+
private final Player player;
16+
private final FloodgatePlayer floodgatePlayer;
17+
18+
public FloodgateAuthTask(FastLoginBukkit plugin, Player player, FloodgatePlayer floodgatePlayer) {
19+
this.plugin = plugin;
20+
this.player = player;
21+
this.floodgatePlayer = floodgatePlayer;
22+
}
23+
24+
@Override
25+
public void run() {
26+
plugin.getLog().info(
27+
"Player {} is connecting through Geyser Floodgate.",
28+
player.getName());
29+
String allowNameConflict = plugin.getCore().getConfig().get("allowFloodgateNameConflict").toString().toLowerCase();
30+
// check if the Bedrock player is linked to a Java account
31+
boolean isLinked = floodgatePlayer.getLinkedPlayer() != null;
32+
if (allowNameConflict.equals("linked") && !isLinked) {
33+
plugin.getLog().info(
34+
"Bedrock Player {}'s name conflits an existing Java Premium Player's name",
35+
player.getName());
36+
37+
// kicking must be synchronous
38+
// https://www.spigotmc.org/threads/asynchronous-player-kick-problem.168580/
39+
Bukkit.getScheduler().runTask(plugin, new Runnable() {
40+
public void run() {
41+
player.kickPlayer("This name is allready in use by a Premium Java Player");
42+
}
43+
});
44+
return;
45+
46+
}
47+
48+
AuthPlugin<Player> authPlugin = plugin.getCore().getAuthPluginHook();
49+
50+
String autoLoginFloodgate = plugin.getCore().getConfig().get("autoLoginFloodgate").toString().toLowerCase();
51+
boolean autoRegisterFloodgate = plugin.getCore().getConfig().getBoolean("autoRegisterFloodgate");
52+
53+
boolean isRegistered;
54+
try {
55+
isRegistered = authPlugin.isRegistered(player.getName());
56+
} catch (Exception e) {
57+
plugin.getLog().error(
58+
"An error has occured while checking if player {} is registered",
59+
player.getName());
60+
return;
61+
}
62+
63+
if (!isRegistered && !autoRegisterFloodgate) {
64+
plugin.getLog().info(
65+
"Auto registration is disabled for Floodgate players in config.yml");
66+
return;
67+
}
68+
69+
// logging in from bedrock for a second time threw an error with UUID
70+
StoredProfile profile = plugin.getCore().getStorage().loadProfile(player.getName());
71+
if (profile == null) {
72+
profile = new StoredProfile(player.getUniqueId(), player.getName(), true, player.getAddress().toString());
73+
}
74+
75+
BukkitLoginSession session = new BukkitLoginSession(player.getName(), isRegistered, profile);
76+
77+
// enable auto login based on the value of 'autoLoginFloodgate' in config.yml
78+
session.setVerified(autoLoginFloodgate.equals("true")
79+
|| (autoLoginFloodgate.equals("linked") && isLinked));
80+
81+
// run login task
82+
Runnable forceLoginTask = new ForceLoginTask(plugin.getCore(), player, session);
83+
Bukkit.getScheduler().runTaskAsynchronously(plugin, forceLoginTask);
84+
}
85+
86+
}

bukkit/src/main/resources/plugin.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ softdepend:
2020
- ProtocolLib
2121
# Premium variable
2222
- PlaceholderAPI
23+
- floodgate
2324
# Auth plugins
2425
- AuthMe
2526
- LoginSecurity

core/src/main/resources/config.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,48 @@ auto-register-unknown: false
187187
# The password of your Minecraft and the password to login in with your auth plugin
188188
autoLogin: true
189189

190+
# Floodgate configuration
191+
# Connecing through Floodgate requires player's to sign in via their Xbox Live account
192+
# Requires Floodgate 2.0 https://github.com/GeyserMC/Floodgate/tree/dev/2.0
193+
# These settings only work in Bukkit/Spigot/Paper mode
194+
# !!!!!!!! WARNING: FLOODGATE SUPPORT IS AN EXPERIMENTAL FEATURE !!!!!!!!
195+
# Enabling any of these settings might lead to people gaining unauthorized access to other's accounts!
196+
197+
# This enables auto login for every player connecting through Floodgate.
198+
# Possible values: false, true, linked
199+
# Linked means that only Bedrock accounts linked to a Java account will be logged in automatically
200+
# !!!!!!!! WARNING: FLOODGATE SUPPORT IS AN EXPERIMENTAL FEATURE !!!!!!!!
201+
# Enabling this might lead to people gaining unauthorized access to other's accounts!
202+
autoLoginFloodgate: false
203+
204+
# This enables Floodgate players to join the server, even if autoRegister is true and there's an existing
205+
# Java **PREMIUM** account with the same name
206+
#
207+
# Java and Bedrock players will get different UUIDs, so their inventories, location, etc. will be different.
208+
# However, some plugins (such as AuthMe) rely on names instead of UUIDs to identify a player which might cause issues.
209+
# In the case of AuthMe (and other auth plugins), both the Java and the Bedrock player will have the same password.
210+
#
211+
# To prevent conflits from two different players having the same name, it is highly recommended to use a 'username-prefix'
212+
# in floodgate/config.yml
213+
# Note: 'username-prefix' is currently broken when used with FastLogin and ProtocolLib. For more information visit:
214+
# https://github.com/games647/FastLogin/issues/493
215+
# A solution to this is to replace ProtocolLib with ProtocolSupport
216+
#
217+
# Possible values:
218+
# false: Check for Premium Java name conflicts as described in 'autoRegister'
219+
# 'autoRegister' must be 'true' for this to work
220+
# true: Bypass 'autoRegister's name conflict checking
221+
# linked: Bedrock accounts linked to a Java account will be allowed to join with conflicting names
222+
# !!!!!!!! WARNING: FLOODGATE SUPPORT IS AN EXPERIMENTAL FEATURE !!!!!!!!
223+
# Enabling this might lead to people gaining unauthorized access to other's accounts!
224+
allowFloodgateNameConflict: false
225+
226+
# This enables auto registering every player connecting through Floodgate.
227+
# autoLoginFloodgate must be 'true' for this to work
228+
# !!!!!!!! WARNING: FLOODGATE SUPPORT IS AN EXPERIMENTAL FEATURE !!!!!!!!
229+
# Enabling this might lead to people gaining unauthorized access to other's accounts!
230+
autoRegisterFloodgate: false
231+
190232
# Database configuration
191233
# Recommended is the use of MariaDB (a better version of MySQL)
192234

0 commit comments

Comments
 (0)