diff --git a/.gitignore b/.gitignore
index a67d3fae..29365516 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,9 @@ nb-configuration.xml
*.iws
.idea/
+# VSCode
+.vscode/
+
# Maven
target/
pom.xml.versionsBackup
diff --git a/bukkit/pom.xml b/bukkit/pom.xml
index 97492b7c..81a0351c 100644
--- a/bukkit/pom.xml
+++ b/bukkit/pom.xml
@@ -125,6 +125,12 @@
false
+
+
+
+ nukkitx-snapshot
+ https://repo.nukkitx.com/maven-snapshots/
+
@@ -183,6 +189,14 @@
+
+
+ org.geysermc.floodgate
+ api
+ 2.0-SNAPSHOT
+ provided
+
+
fr.xephi
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java
index 3d30c275..067bd9b6 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java
@@ -47,10 +47,13 @@ import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import org.bukkit.Bukkit;
+import org.bukkit.Server.Spigot;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
+import org.geysermc.floodgate.api.FloodgateApi;
import org.slf4j.Logger;
/**
@@ -86,6 +89,13 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin
+ * Writes to Log if the value is invalid.
+ *
+ * This should be used for:
+ *
+ * - allowFloodgateNameConflict
+ *
- autoLoginFloodgate
+ *
+ *
+ *
+ * @param key the key of the entry in config.yml
+ * @return true if the entry's value is "true", "false", or "linked"
+ */
+ private boolean isValidFloodgateConfigString(String key) {
+ String value = core.getConfig().get(key).toString().toLowerCase();
+ if (!value.equals("true") && !value.equals("linked") && !value.equals("false")) {
+ logger.error("Invalid value detected for {} in FastLogin/config.yml.", key);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Checks if a plugin is installed on the server
+ * @param name the name of the plugin
+ * @return true if the plugin is installed
+ */
+ private boolean isPluginInstalled(String name) {
+ //the plugin may be enabled after FastLogin, so isPluginEnabled()
+ //won't work here
+ return Bukkit.getServer().getPluginManager().getPlugin(name) != null;
+ }
+
+ /**
+ * Send warning messages to log if incompatible plugins are used
+ */
+ private void dependencyWarnings() {
+ if (isPluginInstalled("floodgate-bukkit")) {
+ logger.warn("We have detected that you are runnging Floodgate 1.0 which is not supported by the Bukkit "
+ + "version of FastLogin.");
+ logger.warn("If you would like to use FastLogin with Floodgate, you can download developement builds of "
+ + "Floodgate 2.0 from https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/dev%252F2.0/");
+ logger.warn("Don't forget to update Geyser to a supported version as well from "
+ + "https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/floodgate-2.0/");
+ } else if (isPluginInstalled("floodgate") && isPluginInstalled("ProtocolLib")) {
+ logger.warn("We have detected that you are runnging FastLogin alongside Floodgate and ProtocolLib.");
+ logger.warn("Currently there is an issue with FastLogin that prevents Floodgate name prefixes from showing up "
+ + "when it is together used with ProtocolLib.");
+ logger.warn("If you would like to use Floodgate name prefixes, you can replace ProtocolLib with ProtocolSupport "
+ + "which does not have this issue.");
+ logger.warn("For more information visit https://github.com/games647/FastLogin/issues/493");
+ }
+ }
}
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 bbdcdf6a..fc2acad7 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
@@ -27,6 +27,7 @@ package com.github.games647.fastlogin.bukkit.listener;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
+import com.github.games647.fastlogin.bukkit.task.FloodgateAuthTask;
import com.github.games647.fastlogin.bukkit.task.ForceLoginTask;
import org.bukkit.Bukkit;
@@ -37,6 +38,8 @@ import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerLoginEvent.Result;
+import org.geysermc.floodgate.api.FloodgateApi;
+import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.bukkit.event.player.PlayerQuitEvent;
/**
@@ -70,13 +73,26 @@ public class ConnectionListener implements Listener {
// cases: Paper (firing BungeeCord message before PlayerJoinEvent) or not running BungeeCord and already
// having the login session from the login process
BukkitLoginSession session = plugin.getSession(player.getAddress());
- if (session == null) {
- String sessionId = plugin.getSessionId(player.getAddress());
- plugin.getLog().info("No on-going login session for player: {} with ID {}", player, sessionId);
- } else {
- Runnable forceLoginTask = new ForceLoginTask(plugin.getCore(), player, session);
- Bukkit.getScheduler().runTaskAsynchronously(plugin, forceLoginTask);
- }
+
+ boolean isFloodgateLogin = false;
+ if (Bukkit.getServer().getPluginManager().isPluginEnabled("floodgate")) {
+ FloodgatePlayer floodgatePlayer = FloodgateApi.getInstance().getPlayer(player.getUniqueId());
+ if (floodgatePlayer != null) {
+ isFloodgateLogin = true;
+ Runnable floodgateAuthTask = new FloodgateAuthTask(plugin, player, floodgatePlayer);
+ Bukkit.getScheduler().runTaskAsynchronously(plugin, floodgateAuthTask);
+ }
+ }
+
+ if (!isFloodgateLogin) {
+ if (session == null) {
+ String sessionId = plugin.getSessionId(player.getAddress());
+ plugin.getLog().info("No on-going login session for player: {} with ID {}", player, sessionId);
+ } else {
+ Runnable forceLoginTask = new ForceLoginTask(plugin.getCore(), player, session);
+ Bukkit.getScheduler().runTaskAsynchronously(plugin, forceLoginTask);
+ }
+ }
plugin.getBungeeManager().markJoinEventFired(player);
// delay the login process to let auth plugins initialize the player
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/NameCheckTask.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/NameCheckTask.java
index 79068973..ee6ba69b 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/NameCheckTask.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/NameCheckTask.java
@@ -37,8 +37,11 @@ import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent;
import java.security.PublicKey;
import java.util.Random;
+import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
+import org.geysermc.floodgate.api.FloodgateApi;
+import org.geysermc.floodgate.api.player.FloodgatePlayer;
public class NameCheckTask extends JoinManagement
implements Runnable {
@@ -67,6 +70,12 @@ public class NameCheckTask extends JoinManagement authPlugin = plugin.getCore().getAuthPluginHook();
+
+ String autoLoginFloodgate = plugin.getCore().getConfig().get("autoLoginFloodgate").toString().toLowerCase();
+ boolean autoRegisterFloodgate = plugin.getCore().getConfig().getBoolean("autoRegisterFloodgate");
+
+ boolean isRegistered;
+ try {
+ isRegistered = authPlugin.isRegistered(player.getName());
+ } catch (Exception e) {
+ plugin.getLog().error(
+ "An error has occured while checking if player {} is registered",
+ player.getName());
+ return;
+ }
+
+ if (!isRegistered && !autoRegisterFloodgate) {
+ plugin.getLog().info(
+ "Auto registration is disabled for Floodgate players in config.yml");
+ return;
+ }
+
+ // logging in from bedrock for a second time threw an error with UUID
+ StoredProfile profile = plugin.getCore().getStorage().loadProfile(player.getName());
+ if (profile == null) {
+ profile = new StoredProfile(player.getUniqueId(), player.getName(), true, player.getAddress().toString());
+ }
+
+ BukkitLoginSession session = new BukkitLoginSession(player.getName(), isRegistered, profile);
+
+ // enable auto login based on the value of 'autoLoginFloodgate' in config.yml
+ session.setVerified(autoLoginFloodgate.equals("true")
+ || (autoLoginFloodgate.equals("linked") && isLinked));
+
+ // run login task
+ Runnable forceLoginTask = new ForceLoginTask(plugin.getCore(), player, session);
+ Bukkit.getScheduler().runTaskAsynchronously(plugin, forceLoginTask);
+ }
+
+}
diff --git a/bukkit/src/main/resources/plugin.yml b/bukkit/src/main/resources/plugin.yml
index df3b48cb..146565bd 100644
--- a/bukkit/src/main/resources/plugin.yml
+++ b/bukkit/src/main/resources/plugin.yml
@@ -20,6 +20,7 @@ softdepend:
- ProtocolLib
# Premium variable
- PlaceholderAPI
+ - floodgate
# Auth plugins
- AuthMe
- LoginSecurity
diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml
index 2a0fb48d..ca949d2f 100644
--- a/core/src/main/resources/config.yml
+++ b/core/src/main/resources/config.yml
@@ -187,6 +187,48 @@ auto-register-unknown: false
# The password of your Minecraft and the password to login in with your auth plugin
autoLogin: true
+# Floodgate configuration
+# Connecing through Floodgate requires player's to sign in via their Xbox Live account
+# Requires Floodgate 2.0 https://github.com/GeyserMC/Floodgate/tree/dev/2.0
+# These settings only work in Bukkit/Spigot/Paper mode
+# !!!!!!!! WARNING: FLOODGATE SUPPORT IS AN EXPERIMENTAL FEATURE !!!!!!!!
+# Enabling any of these settings might lead to people gaining unauthorized access to other's accounts!
+
+# This enables auto login for every player connecting through Floodgate.
+# Possible values: false, true, linked
+# Linked means that only Bedrock accounts linked to a Java account will be logged in automatically
+# !!!!!!!! WARNING: FLOODGATE SUPPORT IS AN EXPERIMENTAL FEATURE !!!!!!!!
+# Enabling this might lead to people gaining unauthorized access to other's accounts!
+autoLoginFloodgate: false
+
+# This enables Floodgate players to join the server, even if autoRegister is true and there's an existing
+# Java **PREMIUM** account with the same name
+#
+# Java and Bedrock players will get different UUIDs, so their inventories, location, etc. will be different.
+# However, some plugins (such as AuthMe) rely on names instead of UUIDs to identify a player which might cause issues.
+# In the case of AuthMe (and other auth plugins), both the Java and the Bedrock player will have the same password.
+#
+# To prevent conflits from two different players having the same name, it is highly recommended to use a 'username-prefix'
+# in floodgate/config.yml
+# Note: 'username-prefix' is currently broken when used with FastLogin and ProtocolLib. For more information visit:
+# https://github.com/games647/FastLogin/issues/493
+# A solution to this is to replace ProtocolLib with ProtocolSupport
+#
+# Possible values:
+# false: Check for Premium Java name conflicts as described in 'autoRegister'
+# 'autoRegister' must be 'true' for this to work
+# true: Bypass 'autoRegister's name conflict checking
+# linked: Bedrock accounts linked to a Java account will be allowed to join with conflicting names
+# !!!!!!!! WARNING: FLOODGATE SUPPORT IS AN EXPERIMENTAL FEATURE !!!!!!!!
+# Enabling this might lead to people gaining unauthorized access to other's accounts!
+allowFloodgateNameConflict: false
+
+# This enables auto registering every player connecting through Floodgate.
+# autoLoginFloodgate must be 'true' for this to work
+# !!!!!!!! WARNING: FLOODGATE SUPPORT IS AN EXPERIMENTAL FEATURE !!!!!!!!
+# Enabling this might lead to people gaining unauthorized access to other's accounts!
+autoRegisterFloodgate: false
+
# Database configuration
# Recommended is the use of MariaDB (a better version of MySQL)