diff --git a/api/src/main/java/us/ajg0702/queue/api/AjQueueAPI.java b/api/src/main/java/us/ajg0702/queue/api/AjQueueAPI.java index 5a2fa72..fc868e3 100644 --- a/api/src/main/java/us/ajg0702/queue/api/AjQueueAPI.java +++ b/api/src/main/java/us/ajg0702/queue/api/AjQueueAPI.java @@ -3,6 +3,8 @@ package us.ajg0702.queue.api; import us.ajg0702.queue.api.events.utils.EventReceiver; import us.ajg0702.queue.api.premium.Logic; import us.ajg0702.queue.api.premium.LogicGetter; +import us.ajg0702.queue.api.premium.PermissionHookRegistry; +import us.ajg0702.queue.api.queueholders.QueueHolderRegistry; import us.ajg0702.queue.api.spigot.AjQueueSpigotAPI; import us.ajg0702.queue.api.util.QueueLogger; import us.ajg0702.utils.common.Config; @@ -12,6 +14,10 @@ import java.util.concurrent.ExecutorService; public abstract class AjQueueAPI { + public static QueueHolderRegistry queueHolderRegistry = new QueueHolderRegistry(); + + public static PermissionHookRegistry permissionHookRegistry = new PermissionHookRegistry(); + public static AjQueueAPI INSTANCE; public static AjQueueSpigotAPI SPIGOT_INSTANCE; @@ -40,6 +46,12 @@ public abstract class AjQueueAPI { */ public abstract void setTimeBetweenPlayers(); + /** + * Gets the server time manager instance, which tracks when players last changed servers + * @return The server time manager instance + */ + public abstract ServerTimeManager getServerTimeManager(); + /** * Gets the ajQueue config * @return the ajQueue config @@ -115,6 +127,14 @@ public abstract class AjQueueAPI { */ public abstract void shutdown(); + public static QueueHolderRegistry getQueueHolderRegistry() { + return queueHolderRegistry; + } + + public static PermissionHookRegistry getPermissionHookRegistry() { + return permissionHookRegistry; + } + public abstract void listen(Class event, EventReceiver handler); public abstract ExecutorService getServersUpdateExecutor(); diff --git a/api/src/main/java/us/ajg0702/queue/api/QueueHolder.java b/api/src/main/java/us/ajg0702/queue/api/QueueHolder.java deleted file mode 100644 index a3ceb66..0000000 --- a/api/src/main/java/us/ajg0702/queue/api/QueueHolder.java +++ /dev/null @@ -1,6 +0,0 @@ -package us.ajg0702.queue.api; - -public interface QueueHolder { - boolean isAvailable(); - -} \ No newline at end of file diff --git a/api/src/main/java/us/ajg0702/queue/api/ServerTimeManager.java b/api/src/main/java/us/ajg0702/queue/api/ServerTimeManager.java new file mode 100644 index 0000000..ff2a62c --- /dev/null +++ b/api/src/main/java/us/ajg0702/queue/api/ServerTimeManager.java @@ -0,0 +1,12 @@ +package us.ajg0702.queue.api; + +import us.ajg0702.queue.api.players.AdaptedPlayer; + +public interface ServerTimeManager { + /** + * Gets the time that the player specified was last seen switching servers + * @param player The player to check + * @return The time that they last switched servers, in milliseconds since midnight, January 1, 1970, UTC + */ + long getLastServerChange(AdaptedPlayer player); +} diff --git a/api/src/main/java/us/ajg0702/queue/api/players/QueuePlayer.java b/api/src/main/java/us/ajg0702/queue/api/players/QueuePlayer.java index 7008553..9e5a3ff 100644 --- a/api/src/main/java/us/ajg0702/queue/api/players/QueuePlayer.java +++ b/api/src/main/java/us/ajg0702/queue/api/players/QueuePlayer.java @@ -1,6 +1,7 @@ package us.ajg0702.queue.api.players; import us.ajg0702.queue.api.queues.QueueServer; +import us.ajg0702.queue.api.server.AdaptedServer; import javax.annotation.Nullable; import java.util.UUID; @@ -68,4 +69,10 @@ public interface QueuePlayer { * @return the max number of seconds this player can be offline before being removed from the queue */ int getMaxOfflineTime(); + + /** + * Gets the server that the player was in when they joined the queue + * @return the server that the player was in when they joined the queue + */ + AdaptedServer getInitialServer(); } diff --git a/api/src/main/java/us/ajg0702/queue/api/premium/Logic.java b/api/src/main/java/us/ajg0702/queue/api/premium/Logic.java index 8e1667d..9dc7bf7 100644 --- a/api/src/main/java/us/ajg0702/queue/api/premium/Logic.java +++ b/api/src/main/java/us/ajg0702/queue/api/premium/Logic.java @@ -38,6 +38,8 @@ public interface Logic { */ PermissionGetter getPermissionGetter(); + int getHighestPriority(QueueServer queueServer, AdaptedServer server, AdaptedPlayer player); + static int getUnJoinablePriorities(QueueServer queueServer, AdaptedServer server, AdaptedPlayer player) { Config config = AjQueueAPI.getInstance().getConfig(); int highest = 0; @@ -59,7 +61,10 @@ public interface Logic { } if(fulljoinPriority > 0) { - if(server.isFull() && server.canJoinFull(player)) { + boolean hasMakeRoom = player.hasPermission("ajqueue.make-room") && AjQueueAPI.getInstance().getConfig().getBoolean("enable-make-room-permission"); + if( + (server.isFull() && (server.canJoinFull(player) || hasMakeRoom)) || + (queueServer.isManuallyFull() && (AdaptedServer.canJoinFull(player, queueServer.getName()) || hasMakeRoom))) { highest = Math.max(highest, fulljoinPriority); } } diff --git a/api/src/main/java/us/ajg0702/queue/api/premium/PermissionHookRegistry.java b/api/src/main/java/us/ajg0702/queue/api/premium/PermissionHookRegistry.java new file mode 100644 index 0000000..8762cf9 --- /dev/null +++ b/api/src/main/java/us/ajg0702/queue/api/premium/PermissionHookRegistry.java @@ -0,0 +1,24 @@ +package us.ajg0702.queue.api.premium; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +public class PermissionHookRegistry { + private final Map hooks = new HashMap<>(); + + public void register(PermissionHook... permissionHooks) { + for (PermissionHook hook : permissionHooks) { + if(hooks.containsKey(hook.getName())) { + throw new IllegalArgumentException("Hook " + hook.getName() + " is already registered!"); + } + } + for (PermissionHook hook : permissionHooks) { + hooks.put(hook.getName(), hook); + } + } + + public Collection getRegisteredHooks() { + return hooks.values(); + } +} diff --git a/api/src/main/java/us/ajg0702/queue/api/queueholders/QueueHolder.java b/api/src/main/java/us/ajg0702/queue/api/queueholders/QueueHolder.java new file mode 100644 index 0000000..d9cf7c6 --- /dev/null +++ b/api/src/main/java/us/ajg0702/queue/api/queueholders/QueueHolder.java @@ -0,0 +1,84 @@ +package us.ajg0702.queue.api.queueholders; + +import us.ajg0702.queue.api.players.AdaptedPlayer; +import us.ajg0702.queue.api.players.QueuePlayer; +import us.ajg0702.queue.api.queues.QueueServer; + +import java.util.List; +import java.util.UUID; + +public abstract class QueueHolder { + + private final QueueServer queueServer; + + public QueueHolder(QueueServer queueServer) { + this.queueServer = queueServer; + } + + /** + * Returns the identifier of this QueueHolder + * Used by the server owner in order to tell ajQueue to use this QueueHolder + * @return a string that is very unlikely to be re-used by another QueueHolder + */ + public abstract String getIdentifier(); + + + /** + * Adds a player to the end of the queue + * NOTE: Do not manually call this! Use the QueueManager to add players to queues + * @param player The QueuePlayer to add + */ + public abstract void addPlayer(QueuePlayer player); + + /** + * Adds a player to the specified position in the queue + * NOTE: Do not manually call this! Use the QueueManager to add players to queues + * @param player The QueuePlayer to add + * @param position The position to add them to + */ + public abstract void addPlayer(QueuePlayer player, int position); + + public void removePlayer(AdaptedPlayer player) { + removePlayer(player.getUniqueId()); + } + + public void removePlayer(UUID uuid) { + QueuePlayer player = findPlayer(uuid); + if(player == null) return; + removePlayer(player); + } + + /** + * Removes a player from the queue + * @param player The player to remove + */ + public abstract void removePlayer(QueuePlayer player); + + /** + * Finds the player with this uuid in this queue and returns the representative QueuePlayer + * @return The QueuePlayer representing the player, null if not found + */ + public abstract QueuePlayer findPlayer(UUID uuid); + + /** + * Finds the player with this username in this queue and returns the representative QueuePlayer + * @return The QueuePlayer representing the player, null if not found + */ + public abstract QueuePlayer findPlayer(String name); + + public QueuePlayer findPlayer(AdaptedPlayer player) { + return findPlayer(player.getUniqueId()); + } + + /** + * Returns the size of the queue + * @return The number of players in the queue + */ + public abstract int getQueueSize(); + + /** + * Get all players that are in the queue + * @return a list of players in the queue + */ + public abstract List getAllPlayers(); +} diff --git a/api/src/main/java/us/ajg0702/queue/api/queueholders/QueueHolderRegistry.java b/api/src/main/java/us/ajg0702/queue/api/queueholders/QueueHolderRegistry.java new file mode 100644 index 0000000..5ac96d7 --- /dev/null +++ b/api/src/main/java/us/ajg0702/queue/api/queueholders/QueueHolderRegistry.java @@ -0,0 +1,44 @@ +package us.ajg0702.queue.api.queueholders; + +import us.ajg0702.queue.api.AjQueueAPI; +import us.ajg0702.queue.api.queues.QueueServer; + +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class QueueHolderRegistry { + + private Map> holders = new ConcurrentHashMap<>(); + + /** + * Register a QueueHolder that can be used + * @param holder The QueueHolder to register + */ + public void register(String identifier, Class holder) { + holders.put(identifier, holder); + } + + public QueueHolder getQueueHolder(QueueServer queueServer) { + String queueHolderName = AjQueueAPI.getInstance().getConfig().getString("queue-holder"); + QueueHolder queueHolder = getQueueHolder(queueHolderName, queueServer); + if(queueHolder == null) { + AjQueueAPI.getInstance().getLogger().warn("Invalid queue-holder '" + queueHolderName + "'! Using the default one"); + return getQueueHolder("default", queueServer); + } + return queueHolder; + } + + public QueueHolder getQueueHolder(String identifier, QueueServer queueServer) { + Class holder = holders.get(identifier); + if(holder == null) return null; + try { + return holder.getConstructor(QueueServer.class).newInstance(queueServer); + } catch(NoSuchMethodException e) { + throw new IllegalArgumentException("QueueHolder " + identifier + " is missing the required constructor!"); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } +} diff --git a/api/src/main/java/us/ajg0702/queue/api/queues/Balancer.java b/api/src/main/java/us/ajg0702/queue/api/queues/Balancer.java index 331aec4..806aabc 100644 --- a/api/src/main/java/us/ajg0702/queue/api/queues/Balancer.java +++ b/api/src/main/java/us/ajg0702/queue/api/queues/Balancer.java @@ -1,8 +1,9 @@ package us.ajg0702.queue.api.queues; +import org.jetbrains.annotations.Nullable; import us.ajg0702.queue.api.players.AdaptedPlayer; import us.ajg0702.queue.api.server.AdaptedServer; public interface Balancer { - AdaptedServer getIdealServer(AdaptedPlayer player); + AdaptedServer getIdealServer(@Nullable AdaptedPlayer player); } diff --git a/api/src/main/java/us/ajg0702/queue/api/queues/QueueServer.java b/api/src/main/java/us/ajg0702/queue/api/queues/QueueServer.java index 652ca67..68c404d 100644 --- a/api/src/main/java/us/ajg0702/queue/api/queues/QueueServer.java +++ b/api/src/main/java/us/ajg0702/queue/api/queues/QueueServer.java @@ -3,10 +3,9 @@ package us.ajg0702.queue.api.queues; import com.google.common.collect.ImmutableList; import us.ajg0702.queue.api.players.AdaptedPlayer; import us.ajg0702.queue.api.players.QueuePlayer; +import us.ajg0702.queue.api.queueholders.QueueHolder; import us.ajg0702.queue.api.server.AdaptedServer; -import us.ajg0702.queue.api.server.AdaptedServerPing; -import java.util.HashMap; import java.util.List; import java.util.UUID; @@ -19,7 +18,9 @@ public interface QueueServer { /** * Get the players who are queued. * @return The players who are queued + * @deprecated It is recommended to not use this method unless you absolutely have to. If you have to, use getQueueHolder().getAllPlayers() */ + @Deprecated ImmutableList getQueue(); /** @@ -69,6 +70,18 @@ public interface QueueServer { */ boolean isJoinable(AdaptedPlayer p); + /** + * Gets the manually-set max player count for this server/group + * @return The manually-set max player count + */ + int getManualMaxPlayers(); + + /** + * Checks if the total number of players in this server/group is above the manually-set max player count + * @return If the server is at or above the manually-set player limit + */ + boolean isManuallyFull(); + /** * Pauses or unpauses a server * @param paused true = paused, false = unpaused @@ -209,6 +222,12 @@ public interface QueueServer { */ Balancer getBalancer(); + /** + * Gets the QueueHolder for this queue + * @return the QueueHolder that holds the queue + */ + QueueHolder getQueueHolder(); + /** * elliot is bad diff --git a/api/src/main/java/us/ajg0702/queue/api/server/AdaptedServer.java b/api/src/main/java/us/ajg0702/queue/api/server/AdaptedServer.java index 94c5f4f..50e5c26 100644 --- a/api/src/main/java/us/ajg0702/queue/api/server/AdaptedServer.java +++ b/api/src/main/java/us/ajg0702/queue/api/server/AdaptedServer.java @@ -1,5 +1,6 @@ package us.ajg0702.queue.api.server; +import us.ajg0702.queue.api.AjQueueAPI; import us.ajg0702.queue.api.players.AdaptedPlayer; import us.ajg0702.queue.api.util.Handle; import us.ajg0702.queue.api.util.QueueLogger; @@ -52,7 +53,20 @@ public interface AdaptedServer extends Handle { */ int getOfflineTime(); - boolean canJoinFull(AdaptedPlayer player); + default boolean canJoinFull(AdaptedPlayer player) { + return canJoinFull(player, getName()); + } + + static boolean canJoinFull(AdaptedPlayer player, String serverName) { + if(player == null) return true; + return + player.hasPermission("ajqueue.joinfull") || + player.hasPermission("ajqueue.joinfullserver." + serverName) || + player.hasPermission("ajqueue.joinfullandbypassserver." + serverName) || + player.hasPermission("ajqueue.joinfullandbypass") || + (AjQueueAPI.getInstance().isPremium() && AjQueueAPI.getInstance().getLogic().getPermissionGetter().hasUniqueFullBypass(player, serverName)) + ; + } boolean justWentOnline(); @@ -75,14 +89,16 @@ public interface AdaptedServer extends Handle { } /** - * Gets if the last ping was successfull + * Gets if the last ping was successful * (which almost always means the server is online) * @return If the server is determined to be online or not */ default boolean isOnline() { - return getLastPing().isPresent(); + return getLastPing().isPresent() && !shouldWaitAfterOnline(); } + boolean shouldWaitAfterOnline(); + /** * Gets the number of players currently online * @return The number of players online diff --git a/build.gradle.kts b/build.gradle.kts index d4d7364..1321d05 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,7 +12,7 @@ repositories { } allprojects { - version = "2.5.0" + version = "2.6.0" group = "us.ajg0702" plugins.apply("java") diff --git a/common/src/main/java/us/ajg0702/queue/commands/commands/SlashServer/SlashServerCommand.java b/common/src/main/java/us/ajg0702/queue/commands/commands/SlashServer/SlashServerCommand.java index 803b2f1..551ce4e 100644 --- a/common/src/main/java/us/ajg0702/queue/commands/commands/SlashServer/SlashServerCommand.java +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/SlashServer/SlashServerCommand.java @@ -1,12 +1,13 @@ package us.ajg0702.queue.commands.commands.SlashServer; import com.google.common.collect.ImmutableList; +import us.ajg0702.queue.api.commands.IBaseCommand; import us.ajg0702.queue.api.commands.ICommandSender; import us.ajg0702.queue.commands.BaseCommand; import us.ajg0702.queue.common.QueueMain; import us.ajg0702.utils.common.Messages; -import java.util.ArrayList; +import java.util.Collections; import java.util.List; public class SlashServerCommand extends BaseCommand { @@ -14,6 +15,10 @@ public class SlashServerCommand extends BaseCommand { final QueueMain main; final String server; final String command; + + private IBaseCommand moveCommand; + + public SlashServerCommand(QueueMain main, String server) { this.main = main; this.server = server; @@ -51,15 +56,14 @@ public class SlashServerCommand extends BaseCommand { sender.sendMessage(getMessages().getComponent("errors.player-only")); return; } - if(main.getConfig().getBoolean("require-permission") && !sender.hasPermission("ajqueue.queue."+server)) { - sender.sendMessage(getMessages().getComponent("noperm")); - return; + if(moveCommand == null) { + moveCommand = main.getPlatformMethods().getCommands().get(0); } - main.getQueueManager().addToQueue(main.getPlatformMethods().senderToPlayer(sender), server); + moveCommand.execute(sender, new String[]{server}); } @Override public List autoComplete(ICommandSender sender, String[] args) { - return new ArrayList<>(); + return Collections.emptyList(); } } diff --git a/common/src/main/java/us/ajg0702/queue/commands/commands/leavequeue/LeaveCommand.java b/common/src/main/java/us/ajg0702/queue/commands/commands/leavequeue/LeaveCommand.java index 336a621..00909e6 100644 --- a/common/src/main/java/us/ajg0702/queue/commands/commands/leavequeue/LeaveCommand.java +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/leavequeue/LeaveCommand.java @@ -11,6 +11,7 @@ import us.ajg0702.queue.common.QueueMain; import us.ajg0702.utils.common.Messages; import java.util.ArrayList; +import java.util.Collections; import java.util.List; public class LeaveCommand extends BaseCommand { @@ -105,11 +106,12 @@ public class LeaveCommand extends BaseCommand { @Override public List autoComplete(ICommandSender sender, String[] args) { + if(args.length > 1) return Collections.emptyList(); List servers = main.getQueueManager().findPlayerInQueues(main.getPlatformMethods().senderToPlayer(sender)); List serverNames = new ArrayList<>(); for(QueuePlayer queuePlayer : servers) { serverNames.add(queuePlayer.getQueueServer().getName()); } - return serverNames; + return filterCompletion(serverNames, args[0]); } } diff --git a/common/src/main/java/us/ajg0702/queue/commands/commands/listqueues/ListCommand.java b/common/src/main/java/us/ajg0702/queue/commands/commands/listqueues/ListCommand.java index 2e9ff6c..814006c 100644 --- a/common/src/main/java/us/ajg0702/queue/commands/commands/listqueues/ListCommand.java +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/listqueues/ListCommand.java @@ -10,7 +10,7 @@ import us.ajg0702.queue.commands.BaseCommand; import us.ajg0702.queue.common.QueueMain; import us.ajg0702.utils.common.Messages; -import java.util.ArrayList; +import java.util.Collections; import java.util.List; public class ListCommand extends BaseCommand { @@ -79,6 +79,6 @@ public class ListCommand extends BaseCommand { @Override public List autoComplete(ICommandSender sender, String[] args) { - return new ArrayList<>(); + return Collections.emptyList(); } } diff --git a/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Kick.java b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Kick.java index e0d5197..450a9fe 100644 --- a/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Kick.java +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Kick.java @@ -81,10 +81,10 @@ public class Kick extends SubCommand { @Override public List autoComplete(ICommandSender sender, String[] args) { if(args.length == 1) { - return main.getPlatformMethods().getPlayerNames(false); + return filterCompletion(main.getPlatformMethods().getPlayerNames(false), args[0]); } if(args.length == 2) { - return main.getQueueManager().getServerNames(); + return filterCompletion(main.getQueueManager().getServerNames(), args[1]); } return new ArrayList<>(); } diff --git a/common/src/main/java/us/ajg0702/queue/commands/commands/manage/KickAll.java b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/KickAll.java index 57ff453..2dbeaa9 100644 --- a/common/src/main/java/us/ajg0702/queue/commands/commands/manage/KickAll.java +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/KickAll.java @@ -9,6 +9,7 @@ import us.ajg0702.queue.common.QueueMain; import us.ajg0702.utils.common.Messages; import java.util.ArrayList; +import java.util.Collections; import java.util.List; public class KickAll extends SubCommand { @@ -65,9 +66,9 @@ public class KickAll extends SubCommand { @Override public List autoComplete(ICommandSender sender, String[] args) { if(args.length == 1) { - return main.getQueueManager().getServerNames(); + return filterCompletion(main.getQueueManager().getServerNames(), args[0]); } - return new ArrayList<>(); + return Collections.emptyList(); } } diff --git a/common/src/main/java/us/ajg0702/queue/commands/commands/manage/ManageCommand.java b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/ManageCommand.java index b32e67a..d26fee2 100644 --- a/common/src/main/java/us/ajg0702/queue/commands/commands/manage/ManageCommand.java +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/ManageCommand.java @@ -104,6 +104,6 @@ public class ManageCommand extends BaseCommand { commands.add(subCommand.getName()); commands.addAll(subCommand.getAliases()); } - return commands; + return filterCompletion(commands, args[0]); } } diff --git a/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Pause.java b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Pause.java index 92205b7..bbe4121 100644 --- a/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Pause.java +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Pause.java @@ -77,11 +77,11 @@ public class Pause extends SubCommand { if(args.length == 1) { List servers = new ArrayList<>(main.getQueueManager().getServerNames()); servers.add("all"); - return servers; + return filterCompletion(servers, args[0]); } if(args.length == 2) { - return Arrays.asList("on", "off", "true", "false"); + return filterCompletion(Arrays.asList("on", "off", "true", "false"), args[1]); } - return new ArrayList<>(); + return Collections.emptyList(); } } diff --git a/common/src/main/java/us/ajg0702/queue/commands/commands/manage/QueueList.java b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/QueueList.java index 1aa49e3..fdc4961 100644 --- a/common/src/main/java/us/ajg0702/queue/commands/commands/manage/QueueList.java +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/QueueList.java @@ -11,7 +11,7 @@ import us.ajg0702.queue.commands.SubCommand; import us.ajg0702.queue.common.QueueMain; import us.ajg0702.utils.common.Messages; -import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.regex.Pattern; @@ -88,6 +88,6 @@ public class QueueList extends SubCommand { @Override public java.util.List autoComplete(ICommandSender sender, String[] args) { - return new ArrayList<>(); + return Collections.emptyList(); } } diff --git a/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Reload.java b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Reload.java index c45b0aa..9e8ac6c 100644 --- a/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Reload.java +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Reload.java @@ -9,7 +9,7 @@ import us.ajg0702.queue.commands.SubCommand; import us.ajg0702.queue.common.QueueMain; import us.ajg0702.utils.common.Messages; -import java.util.ArrayList; +import java.util.Collections; import java.util.List; public class Reload extends SubCommand { @@ -63,6 +63,6 @@ public class Reload extends SubCommand { @Override public List autoComplete(ICommandSender sender, String[] args) { - return new ArrayList<>(); + return Collections.emptyList(); } } diff --git a/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Send.java b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Send.java index 576d3c2..ff14169 100644 --- a/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Send.java +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Send.java @@ -10,6 +10,7 @@ import us.ajg0702.queue.common.QueueMain; import us.ajg0702.utils.common.Messages; import java.util.ArrayList; +import java.util.Collections; import java.util.List; public class Send extends SubCommand { @@ -93,12 +94,12 @@ public class Send extends SubCommand { if(args.length == 1) { List options = new ArrayList<>(main.getPlatformMethods().getServerNames()); options.addAll(main.getPlatformMethods().getPlayerNames(false)); - return options; + return filterCompletion(options, args[0]); } if(args.length == 2) { - return main.getQueueManager().getServerNames(); + return filterCompletion(main.getQueueManager().getServerNames(), args[1]); } - return new ArrayList<>(); + return Collections.emptyList(); } diff --git a/common/src/main/java/us/ajg0702/queue/commands/commands/manage/debug/PermissionList.java b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/debug/PermissionList.java index 06b73eb..473f15f 100644 --- a/common/src/main/java/us/ajg0702/queue/commands/commands/manage/debug/PermissionList.java +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/debug/PermissionList.java @@ -26,7 +26,7 @@ public class PermissionList extends SubCommand { @Override public ImmutableList getAliases() { - return ImmutableList.of(); + return ImmutableList.of("permissionslist", "listpermissions", "listpermission"); } @Override diff --git a/common/src/main/java/us/ajg0702/queue/commands/commands/queue/QueueCommand.java b/common/src/main/java/us/ajg0702/queue/commands/commands/queue/QueueCommand.java index 0409689..8952bf3 100644 --- a/common/src/main/java/us/ajg0702/queue/commands/commands/queue/QueueCommand.java +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/queue/QueueCommand.java @@ -8,10 +8,7 @@ import us.ajg0702.queue.commands.BaseCommand; import us.ajg0702.queue.common.QueueMain; import us.ajg0702.utils.common.Messages; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; public class QueueCommand extends BaseCommand { @@ -92,7 +89,7 @@ public class QueueCommand extends BaseCommand { @Override public List autoComplete(ICommandSender sender, String[] args) { if(!main.getConfig().getBoolean("tab-complete-queues")) { - return new ArrayList<>(); + return Collections.emptyList(); } if(args.length == 1) { List servers = filterCompletion(main.getQueueManager().getServerNames(), args[0]); @@ -101,6 +98,6 @@ public class QueueCommand extends BaseCommand { } return servers; } - return new ArrayList<>(); + return Collections.emptyList(); } } diff --git a/common/src/main/java/us/ajg0702/queue/common/DefaultQueueHolder.java b/common/src/main/java/us/ajg0702/queue/common/DefaultQueueHolder.java new file mode 100644 index 0000000..4fef9f5 --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/common/DefaultQueueHolder.java @@ -0,0 +1,69 @@ +package us.ajg0702.queue.common; + +import com.google.common.collect.ImmutableList; +import us.ajg0702.queue.api.players.QueuePlayer; +import us.ajg0702.queue.api.queueholders.QueueHolder; +import us.ajg0702.queue.api.queues.QueueServer; + +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CopyOnWriteArrayList; + +public class DefaultQueueHolder extends QueueHolder { + + List queue = new CopyOnWriteArrayList<>(); + + public DefaultQueueHolder(QueueServer queueServer) { + super(queueServer); + } + + @Override + public String getIdentifier() { + return "default"; + } + + @Override + public void addPlayer(QueuePlayer player) { + queue.add(player); + } + + @Override + public void addPlayer(QueuePlayer player, int position) { + queue.add(position, player); + } + + @Override + public void removePlayer(QueuePlayer player) { + queue.remove(player); + } + + @Override + public QueuePlayer findPlayer(UUID uuid) { + for(QueuePlayer queuePlayer : queue) { + if(queuePlayer.getUniqueId().toString().equals(uuid.toString())) { + return queuePlayer; + } + } + return null; + } + + @Override + public QueuePlayer findPlayer(String name) { + for(QueuePlayer queuePlayer : queue) { + if(queuePlayer.getName().equalsIgnoreCase(name)) { + return queuePlayer; + } + } + return null; + } + + @Override + public int getQueueSize() { + return queue.size(); + } + + @Override + public List getAllPlayers() { + return ImmutableList.copyOf(queue); + } +} diff --git a/common/src/main/java/us/ajg0702/queue/common/EventHandlerImpl.java b/common/src/main/java/us/ajg0702/queue/common/EventHandlerImpl.java index b477971..5efe06f 100644 --- a/common/src/main/java/us/ajg0702/queue/common/EventHandlerImpl.java +++ b/common/src/main/java/us/ajg0702/queue/common/EventHandlerImpl.java @@ -58,6 +58,8 @@ public class EventHandlerImpl implements EventHandler { if(queues.size() > 0) { main.getQueueManager().sendMessage(main.getQueueManager().getSingleServer(player).findPlayer(player)); } + + main.serverTimeManager.playerChanged(player); } @Override @@ -77,6 +79,7 @@ public class EventHandlerImpl implements EventHandler { } main.getQueueManager().clear(player); QueueCommand.cooldowns.remove(player); + main.serverTimeManager.removePlayer(player); } @Override @@ -108,12 +111,32 @@ public class EventHandlerImpl implements EventHandler { String[] parts = s.split(":"); String from = parts[0]; QueueServer to = main.getQueueManager().findServer(parts[1]); - if(from.equalsIgnoreCase(serverName) && to != null) { - main.getQueueManager().addToQueue(player, to); + if( + from.equalsIgnoreCase(serverName) && to != null && + ( + !main.getConfig().getBoolean("require-queueserver-permission") || + player.hasPermission("ajqueue.queueserver." + to.getName()) + ) + ) { + int delay = Math.min(main.getConfig().getInt("queue-server-delay"), 3000); + Runnable task = () -> { + if(to.getServers().contains(player.getCurrentServer())) return; + main.getQueueManager().addToQueue(player, to); + }; + + Debug.info("Delaying queue-server by " + delay); + + if(delay > 0) { + main.getTaskManager().executor.schedule(task, delay, TimeUnit.MILLISECONDS); + } else { + task.run(); + } } } } + main.serverTimeManager.playerChanged(player); + } @Override diff --git a/common/src/main/java/us/ajg0702/queue/common/QueueMain.java b/common/src/main/java/us/ajg0702/queue/common/QueueMain.java index 3b69bab..3f281c6 100644 --- a/common/src/main/java/us/ajg0702/queue/common/QueueMain.java +++ b/common/src/main/java/us/ajg0702/queue/common/QueueMain.java @@ -27,6 +27,14 @@ public class QueueMain extends AjQueueAPI { } private double timeBetweenPlayers; + + protected ServerTimeManagerImpl serverTimeManager = new ServerTimeManagerImpl(); + + @Override + public ServerTimeManager getServerTimeManager() { + return serverTimeManager; + } + @Override public double getTimeBetweenPlayers() { return timeBetweenPlayers; @@ -182,8 +190,6 @@ public class QueueMain extends AjQueueAPI { this.platformMethods = platformMethods; this.dataFolder = dataFolder; - constructMessages(); - try { config = new Config(dataFolder, new LogConverter(logger)); } catch (ConfigurateException e) { @@ -192,6 +198,10 @@ public class QueueMain extends AjQueueAPI { return; } + constructMessages(); + + getQueueHolderRegistry().register("default", DefaultQueueHolder.class); + logic = logicGetter.constructLogic(); aliasManager = logicGetter.constructAliasManager(config); @@ -230,6 +240,8 @@ public class QueueMain extends AjQueueAPI { d.put("status.now-in-queue", "&aYou are now queued for {SERVER}! &7You are in position &f{POS}&7 of &f{LEN}&7.\n&7Type &f/leavequeue&7 or &fclick here&7 to leave the queue!"); d.put("status.now-in-empty-queue", ""); d.put("status.sending-now", "&aSending you to &f{SERVER} &anow.."); + d.put("status.making-room", "Making room for you.."); + d.put("status.priority-increased", "You now have higher priority! Moving you up in the queue.."); d.put("errors.server-not-exist", "&cThe server {SERVER} does not exist!"); d.put("errors.already-queued", "&cYou are already queued for that server!"); @@ -241,6 +253,10 @@ public class QueueMain extends AjQueueAPI { d.put("errors.wrong-version.or", " or "); d.put("errors.wrong-version.comma", ", "); d.put("errors.too-fast-queue", "You're queueing too fast!"); + d.put("errors.kicked-to-make-room", "You were moved to the lobby to make room for another player."); + d.put("errors.make-room-failed.player", "Failed to make room for you in that server."); + d.put("errors.make-room-failed.admin", "Failed to make room for you in that server. Check the console for more information."); + d.put("commands.leave-queue", "&aYou left the queue for {SERVER}!"); d.put("commands.reload", "&aConfig and messages reloaded successfully!"); @@ -322,6 +338,58 @@ public class QueueMain extends AjQueueAPI { d.put("updater.fail", "An error occurred while downloading the update. Check the console for more info."); d.put("updater.already-downloaded", "The update has already been downloaded."); + List oldProtocolNames = config.getStringList("protocol-names"); + for (String oldProtocolName : oldProtocolNames) { + String[] parts = oldProtocolName.split(":"); + if(parts.length != 2) { + logger.warn("Invalid old (in the config) protocol name '" + oldProtocolName + "'. Skipping."); + continue; + } + String protocol = parts[0]; + String name = parts[1]; + + d.put("protocol-names." + protocol, name); + } + + + d.putIfAbsent("protocol-names.763", "1.20.1"); + d.putIfAbsent("protocol-names.762", "1.19.4"); + d.putIfAbsent("protocol-names.761", "1.19.3"); + d.putIfAbsent("protocol-names.760", "1.19.2"); + d.putIfAbsent("protocol-names.759", "1.19"); + d.putIfAbsent("protocol-names.758", "1.18.2"); + d.putIfAbsent("protocol-names.757", "1.18.1"); + d.putIfAbsent("protocol-names.756", "1.17.1"); + d.putIfAbsent("protocol-names.755", "1.17"); + d.putIfAbsent("protocol-names.754", "1.16.5"); + d.putIfAbsent("protocol-names.753", "1.16.3"); + d.putIfAbsent("protocol-names.751", "1.16.2"); + d.putIfAbsent("protocol-names.736", "1.16.1"); + d.putIfAbsent("protocol-names.735", "1.16"); + d.putIfAbsent("protocol-names.578", "1.15.2"); + d.putIfAbsent("protocol-names.575", "1.15.1"); + d.putIfAbsent("protocol-names.573", "1.15"); + d.putIfAbsent("protocol-names.498", "1.14.4"); + d.putIfAbsent("protocol-names.490", "1.14.3"); + d.putIfAbsent("protocol-names.485", "1.14.2"); + d.putIfAbsent("protocol-names.480", "1.14.1"); + d.putIfAbsent("protocol-names.477", "1.14"); + d.putIfAbsent("protocol-names.404", "1.13.2"); + d.putIfAbsent("protocol-names.401", "1.13.1"); + d.putIfAbsent("protocol-names.393", "1.13"); + d.putIfAbsent("protocol-names.340", "1.12.2"); + d.putIfAbsent("protocol-names.338", "1.12.1"); + d.putIfAbsent("protocol-names.335", "1.12"); + d.putIfAbsent("protocol-names.316", "1.11.2"); + d.putIfAbsent("protocol-names.315", "1.11"); + d.putIfAbsent("protocol-names.210", "1.10.2"); + d.putIfAbsent("protocol-names.110", "1.9.4"); + d.putIfAbsent("protocol-names.109", "1.9.2"); + d.putIfAbsent("protocol-names.108", "1.9.1"); + d.putIfAbsent("protocol-names.107", "1.9"); + d.putIfAbsent("protocol-names.47", "1.8.9"); + d.putIfAbsent("protocol-names.5", "1.7.10"); + messages = new Messages(dataFolder, new LogConverter(logger), d); } } diff --git a/common/src/main/java/us/ajg0702/queue/common/QueueManagerImpl.java b/common/src/main/java/us/ajg0702/queue/common/QueueManagerImpl.java index f144e6c..70325d7 100644 --- a/common/src/main/java/us/ajg0702/queue/common/QueueManagerImpl.java +++ b/common/src/main/java/us/ajg0702/queue/common/QueueManagerImpl.java @@ -188,11 +188,13 @@ public class QueueManagerImpl implements QueueManager { } } - List notInServers = new ArrayList<>(server.getServers()); - notInServers.removeIf(adaptedServer -> !adaptedServer.getName().equals(player.getServerName())); - if(notInServers.size() > 0) { - player.sendMessage(msgs.getComponent("errors.already-connected", "SERVER:"+server.getAlias())); - return false; + if(!server.isGroup() || !main.getConfig().getBoolean("allow-group-requeue")) { + List notInServers = new ArrayList<>(server.getServers()); + notInServers.removeIf(adaptedServer -> !adaptedServer.getName().equals(player.getServerName())); + if(notInServers.size() > 0) { + player.sendMessage(msgs.getComponent("errors.already-connected", "SERVER:"+server.getAlias())); + return false; + } } ImmutableList beforeQueues = getPlayerQueues(player); @@ -438,13 +440,14 @@ public class QueueManagerImpl implements QueueManager { "TIME:"+ TimeUtils.timeString(time, msgs.getString("format.time.mins"), msgs.getString("format.time.secs")) ); - Title title = Title.title(titleMessage, subTitleMessage, Title.Times.of(Duration.ZERO, Duration.ofSeconds(2L), Duration.ZERO)); + Title title = Title.title(titleMessage, subTitleMessage, Title.Times.times(Duration.ZERO, Duration.ofSeconds(2L), Duration.ZERO)); player.showTitle(title); } } } protected final Map pausedAntiSpam = new ConcurrentHashMap<>(); + private boolean skipPriorityCheck = true; @Override public void sendQueueEvents() { @@ -467,7 +470,18 @@ public class QueueManagerImpl implements QueueManager { } return; } - if(!getPlayerQueues(player).contains(to)) { + long lastSwitch = main.getServerTimeManager().getLastServerChange(player); + int delay = Math.min(Math.max(main.getConfig().getInt("queue-server-delay"), 0), 3000); + if(System.currentTimeMillis() - lastSwitch < delay + 1000 || !player.getCurrentServer().equals(from)) { + return; + } + if( + !getPlayerQueues(player).contains(to) && + ( + !main.getConfig().getBoolean("require-queueserver-permission") || + player.hasPermission("ajqueue.queueserver." + to.getName()) + ) + ) { addToQueue(player, to); } }); @@ -475,12 +489,33 @@ public class QueueManagerImpl implements QueueManager { } for (QueueServer s : servers) { for (QueuePlayer queuePlayer : s.getQueue()) { - AdaptedPlayer player = queuePlayer.getPlayer(); + AdaptedPlayer player = queuePlayer.getPlayer(); if (player == null || !player.isConnected()) continue; if(player.getServerName() == null) continue; main.getPlatformMethods().sendPluginMessage(player, "inqueueevent", "true"); } } + if(main.getConfig().getBoolean("re-check-priority")) { + if(skipPriorityCheck) { + skipPriorityCheck = false; + } else { + for (QueueServer server : servers) { + for (QueuePlayer queuePlayer : server.getQueue()) { + if(queuePlayer.getPlayer() == null) continue; + AdaptedPlayer player = queuePlayer.getPlayer(); + AdaptedServer ideal = server.getIdealServer(player); + + int currentHighestPriority = main.getLogic().getHighestPriority(server, ideal, player); + if(queuePlayer.getPriority() >= currentHighestPriority) continue; + + player.sendMessage(main.getMessages().getComponent("status.priority-increased")); + + server.removePlayer(queuePlayer); + addToQueue(player, server); + } + } + } + } } @Override @@ -568,9 +603,10 @@ public class QueueManagerImpl implements QueueManager { final ConcurrentHashMap sendingNowAntiSpam = new ConcurrentHashMap<>(); final Map sendingAttempts = new WeakHashMap<>(); + final Map makeRoomAntispam = new WeakHashMap<>(); @Override - public void sendPlayers(QueueServer queueServer) { + public synchronized void sendPlayers(QueueServer queueServer) { List sendingServers; if(queueServer == null) { sendingServers = new ArrayList<>(servers); @@ -603,7 +639,10 @@ public class QueueManagerImpl implements QueueManager { continue; } - if(selected.isFull() && !selected.canJoinFull(p.getPlayer())) continue; + if( + (selected.isFull() && !selected.canJoinFull(player)) || + (server.isManuallyFull() && !AdaptedServer.canJoinFull(player, server.getName())) + ) continue; player.sendMessage(msgs.getComponent("status.sending-now", "SERVER:"+server.getAlias())); Debug.info("Calling player.connect for " + player.getName() + "(send when back online)"); @@ -618,7 +657,9 @@ public class QueueManagerImpl implements QueueManager { // If the first person int the queue is offline or already in the server, find the next online player in the queue int i = 0; - while((nextPlayer == null || server.getServerNames().contains(nextPlayer.getServerName())) && i < server.getQueue().size()) { + List excludableServers = new ArrayList<>(server.getServerNames()); + if(nextQueuePlayer.getInitialServer() != null) excludableServers.remove(nextQueuePlayer.getInitialServer().getName()); + while((nextPlayer == null || excludableServers.contains(nextPlayer.getServerName())) && i < server.getQueue().size()) { if(nextPlayer != null) { // Remove them if they are already in the server server.removePlayer(nextQueuePlayer); if(server.getQueue().size() > i) { @@ -650,7 +691,105 @@ public class QueueManagerImpl implements QueueManager { if(!server.canAccess(nextPlayer)) continue; - if(selected.isFull() && !selected.canJoinFull(nextPlayer)) continue; + if( + ( + (selected.isFull() && !selected.canJoinFull(nextPlayer)) || + (server.isManuallyFull() && !AdaptedServer.canJoinFull(nextPlayer, server.getName())) + ) && + !( + nextPlayer.hasPermission("ajqueue.make-room") && + main.getConfig().getBoolean("enable-make-room-permission") && + (!server.isGroup() || server.isManuallyFull()) // only use make-room on groups if the server is manually full + ) + ) continue; + + + // ajqueue.make-room logic + if( + ( + (selected.isFull() && !selected.canJoinFull(nextPlayer)) || + (server.isManuallyFull() && !AdaptedServer.canJoinFull(nextPlayer, server.getName())) + ) && + main.getConfig().getBoolean("enable-make-room-permission") && + nextPlayer.hasPermission("ajqueue.make-room") && + (!server.isGroup() || server.isManuallyFull()) && // only use make-room on groups if the server is manually full + ( // don't make room more than the minimum ping time + System.currentTimeMillis() - makeRoomAntispam.getOrDefault(nextQueuePlayer, 0L) + >= (main.getConfig().getDouble("minimum-ping-time") * 1e3) + ) + ) { + makeRoomAntispam.put(nextQueuePlayer, System.currentTimeMillis()); + List players = selected.getPlayers(); + + // first, we need to find what the lowest priority on the server is + int lowestPriority = Integer.MAX_VALUE; + for (AdaptedPlayer player : players) { + int priority = main.getLogic().getHighestPriority(server, selected, player); + if(priority < lowestPriority) lowestPriority = priority; + } + + boolean kickLongest = main.getConfig().getBoolean("make-room-kick-longest-playtime"); + + long selectedTime = kickLongest ? Long.MAX_VALUE : 0; + AdaptedPlayer selectedPlayer = null; + for (AdaptedPlayer player : players) { + int priority = main.getLogic().getHighestPriority(server, selected, player); + if(priority > lowestPriority) continue; // don't select players with higher priorities + long switchTime = main.getServerTimeManager().getLastServerChange(player); + if(selectedPlayer == null) { + selectedPlayer = player; + selectedTime = switchTime; + continue; + } + if(kickLongest) { + if(switchTime < selectedTime) { + selectedTime = switchTime; + selectedPlayer = player; + } + } else { + if(switchTime > selectedTime) { + selectedTime = switchTime; + selectedPlayer = player; + } + } + } + + + if(selectedPlayer == null) { + main.getLogger().warn( + "Unable to find player to kick from " + selected.getName() + " " + + "to let " + nextPlayer.getName() + "join!" + ); + } else { + Debug.info( + "Selected " + selectedPlayer.getName() + " " + + "to make room for " + nextPlayer.getName() + " in " + selected.getName() + ); + String kickToName = main.getConfig().getString("make-room-kick-to"); + AdaptedServer kickTo = main.getPlatformMethods().getServer(kickToName); + if(kickTo == null) { + main.getLogger().warn( + "Unable to make room due to '" + kickToName + "' not existing! " + + "Please configure make-room-kick-to in the config" + ); + boolean isAdmin = nextPlayer.hasPermission("ajqueue.manage"); + nextPlayer.sendMessage( + main.getMessages().getComponent( + isAdmin ? "errors.make-room-failed.admin" : "errors.make-room-failed.player" + ) + ); + } else { + selectedPlayer.connect(kickTo); + selectedPlayer.sendMessage(main.getMessages().getComponent("errors.kicked-to-make-room")); + + if(main.getTimeBetweenPlayers() >= 1d) { + nextPlayer.sendMessage(main.getMessages().getComponent("status.making-room")); + } + + continue; + } + } + } if(main.getConfig().getBoolean("enable-bypasspaused-permission")) { if(server.isPaused() && !nextPlayer.hasPermission("ajqueue.bypasspaused")) continue; @@ -682,7 +821,7 @@ public class QueueManagerImpl implements QueueManager { "title.sending-now.subtitle", "SERVER:"+server.getAlias() ), - Title.Times.of(Duration.ZERO, Duration.ofSeconds(2L), Duration.ZERO) + Title.Times.times(Duration.ZERO, Duration.ofSeconds(2L), Duration.ZERO) )); } sendingNowAntiSpam.put(nextPlayer, System.currentTimeMillis()); diff --git a/common/src/main/java/us/ajg0702/queue/common/ServerTimeManagerImpl.java b/common/src/main/java/us/ajg0702/queue/common/ServerTimeManagerImpl.java new file mode 100644 index 0000000..5f37296 --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/common/ServerTimeManagerImpl.java @@ -0,0 +1,27 @@ +package us.ajg0702.queue.common; + +import us.ajg0702.queue.api.ServerTimeManager; +import us.ajg0702.queue.api.players.AdaptedPlayer; + +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +public class ServerTimeManagerImpl implements ServerTimeManager { + + Map serverSwitches = new ConcurrentHashMap<>(); + + + @Override + public long getLastServerChange(AdaptedPlayer player) { + return serverSwitches.get(player.getUniqueId()); + } + + public void playerChanged(AdaptedPlayer player) { + serverSwitches.put(player.getUniqueId(), System.currentTimeMillis()); + } + + public void removePlayer(AdaptedPlayer player) { + serverSwitches.remove(player.getUniqueId()); + } +} diff --git a/common/src/main/java/us/ajg0702/queue/common/TaskManager.java b/common/src/main/java/us/ajg0702/queue/common/TaskManager.java index 6abe8be..87d665f 100644 --- a/common/src/main/java/us/ajg0702/queue/common/TaskManager.java +++ b/common/src/main/java/us/ajg0702/queue/common/TaskManager.java @@ -61,11 +61,14 @@ public class TaskManager { TimeUnit.MILLISECONDS ); - messageTask = scheduleAtFixedRate( - main.getQueueManager()::sendMessages, - main.getConfig().getInt("message-time"), - TimeUnit.SECONDS - ); + int messageTime = main.getConfig().getInt("message-time"); + if(messageTime > 0) { + messageTask = scheduleAtFixedRate( + main.getQueueManager()::sendMessages, + messageTime, + TimeUnit.SECONDS + ); + } actionBarTask = scheduleAtFixedRate( main.getQueueManager()::sendActionBars, diff --git a/common/src/main/java/us/ajg0702/queue/common/communication/handlers/PlayerStatusHandler.java b/common/src/main/java/us/ajg0702/queue/common/communication/handlers/PlayerStatusHandler.java index 62e3d6e..d4f7df0 100644 --- a/common/src/main/java/us/ajg0702/queue/common/communication/handlers/PlayerStatusHandler.java +++ b/common/src/main/java/us/ajg0702/queue/common/communication/handlers/PlayerStatusHandler.java @@ -17,7 +17,7 @@ public class PlayerStatusHandler extends MessageHandler { if(server == null) { return ComResponse .from("playerstatus") - .id(data) + .id(player.getUniqueId() + data) .with("invalid_server"); } if(!player.isConnected() || player.getServerName() == null) return null; diff --git a/common/src/main/java/us/ajg0702/queue/common/players/QueuePlayerImpl.java b/common/src/main/java/us/ajg0702/queue/common/players/QueuePlayerImpl.java index 379e7f6..47a7b7d 100644 --- a/common/src/main/java/us/ajg0702/queue/common/players/QueuePlayerImpl.java +++ b/common/src/main/java/us/ajg0702/queue/common/players/QueuePlayerImpl.java @@ -5,6 +5,7 @@ import org.jetbrains.annotations.Nullable; import us.ajg0702.queue.api.players.AdaptedPlayer; import us.ajg0702.queue.api.players.QueuePlayer; import us.ajg0702.queue.api.queues.QueueServer; +import us.ajg0702.queue.api.server.AdaptedServer; import java.util.UUID; @@ -21,6 +22,8 @@ public class QueuePlayerImpl implements QueuePlayer { private final int maxOfflineTime; + private final AdaptedServer initialServer; + public int lastPosition; public QueuePlayerImpl(UUID uuid, String name, QueueServer server, int highestPriority, int maxOfflineTime) { @@ -42,6 +45,8 @@ public class QueuePlayerImpl implements QueuePlayer { this.maxOfflineTime = maxOfflineTime; + initialServer = player != null ? player.getCurrentServer() : null; + lastPosition = getPosition(); } @@ -106,6 +111,11 @@ public class QueuePlayerImpl implements QueuePlayer { return maxOfflineTime; } + @Override + public AdaptedServer getInitialServer() { + return initialServer; + } + private long leaveTime = 0; public void setLeaveTime(long leaveTime) { diff --git a/common/src/main/java/us/ajg0702/queue/common/queues/QueueServerImpl.java b/common/src/main/java/us/ajg0702/queue/common/queues/QueueServerImpl.java index 988d8be..72561d1 100644 --- a/common/src/main/java/us/ajg0702/queue/common/queues/QueueServerImpl.java +++ b/common/src/main/java/us/ajg0702/queue/common/queues/QueueServerImpl.java @@ -1,9 +1,11 @@ package us.ajg0702.queue.common.queues; import com.google.common.collect.ImmutableList; +import us.ajg0702.queue.api.AjQueueAPI; import us.ajg0702.queue.api.events.PositionChangeEvent; import us.ajg0702.queue.api.players.AdaptedPlayer; import us.ajg0702.queue.api.players.QueuePlayer; +import us.ajg0702.queue.api.queueholders.QueueHolder; import us.ajg0702.queue.api.queues.Balancer; import us.ajg0702.queue.api.queues.QueueServer; import us.ajg0702.queue.api.server.AdaptedServer; @@ -11,13 +13,12 @@ import us.ajg0702.queue.api.server.AdaptedServerPing; import us.ajg0702.queue.common.QueueMain; import us.ajg0702.queue.common.players.QueuePlayerImpl; import us.ajg0702.queue.common.queues.balancers.DefaultBalancer; +import us.ajg0702.queue.common.queues.balancers.FirstBalancer; import us.ajg0702.queue.common.queues.balancers.MinigameBalancer; import us.ajg0702.queue.common.utils.Debug; import us.ajg0702.utils.common.Messages; import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; public class QueueServerImpl implements QueueServer { @@ -27,7 +28,7 @@ public class QueueServerImpl implements QueueServer { private final List servers; - private final List queue = new ArrayList<>(); + private final QueueHolder queueHolder = AjQueueAPI.getQueueHolderRegistry().getQueueHolder(this); private List supportedProtocols = new ArrayList<>(); @@ -37,6 +38,9 @@ public class QueueServerImpl implements QueueServer { private long lastSentTime = 0; + private int manualMaxPlayers = Integer.MAX_VALUE; + + public QueueServerImpl(String name, QueueMain main, AdaptedServer server, List previousPlayers) { this(name, main, Collections.singletonList(server), previousPlayers); } @@ -54,11 +58,13 @@ public class QueueServerImpl implements QueueServer { String balancerType = type.substring(colon+1); if(groupName.equals(name)) { - //noinspection SwitchStatementWithTooFewBranches switch(balancerType.toLowerCase(Locale.ROOT)) { case "minigame": balancer = new MinigameBalancer(this, main); break; + case "first": + balancer = new FirstBalancer(this, main); + break; default: balancerType = "default"; balancer = new DefaultBalancer(this, main); @@ -72,6 +78,26 @@ public class QueueServerImpl implements QueueServer { Debug.info("Using default balancer for "+name); } + List manualLimits = main.getConfig().getStringList("manual-max-players"); + for (String manualLimit : manualLimits) { + String[] parts = manualLimit.split(":"); + if(parts.length != 2) { + main.getLogger().warn("Invalid manual limit: " + manualLimit); + continue; + } + String limitFor = parts[0]; + + if(!limitFor.equals(name)) continue; + + String limitStr = parts[1]; + try { + manualMaxPlayers = Integer.parseInt(limitStr); + } catch(NumberFormatException e) { + main.getLogger().warn("Invalid limit number for " + limitFor); + } + break; + } + for(QueuePlayer queuePlayer : previousPlayers) { if(queuePlayer.getPlayer() == null) { addPlayer( @@ -98,7 +124,7 @@ public class QueueServerImpl implements QueueServer { @Override public ImmutableList getQueue() { - return ImmutableList.copyOf(queue); + return ImmutableList.copyOf(queueHolder.getAllPlayers()); } @Override @@ -118,11 +144,11 @@ public class QueueServerImpl implements QueueServer { return msgs.getString("status.offline.paused"); } - if(p != null && server.isWhitelisted() && !server.getWhitelistedPlayers().contains(p.getUniqueId())) { + if(server.isWhitelisted() && (p == null || !server.getWhitelistedPlayers().contains(p.getUniqueId()))) { return msgs.getString("status.offline.whitelisted"); } - if(server.isFull() && !server.canJoinFull(p)) { + if((server.isFull() && !server.canJoinFull(p)) || (isManuallyFull() && !AdaptedServer.canJoinFull(p, getName()))) { return msgs.getString("status.offline.full"); } @@ -154,11 +180,11 @@ public class QueueServerImpl implements QueueServer { return "paused"; } - if(p != null && server.isWhitelisted() && !server.getWhitelistedPlayers().contains(p.getUniqueId())) { + if(server.isWhitelisted() && (p == null || !server.getWhitelistedPlayers().contains(p.getUniqueId()))) { return "whitelisted"; } - if(server.isFull() && !server.canJoinFull(p)) { + if(((server.isFull() && !server.canJoinFull(p)) || (isManuallyFull() && !AdaptedServer.canJoinFull(p, getName())))) { return "full"; } @@ -185,11 +211,31 @@ public class QueueServerImpl implements QueueServer { @Override public boolean isJoinable(AdaptedPlayer p) { + if(isManuallyFull() && !AdaptedServer.canJoinFull(p, getName())) return false; AdaptedServer server = getIdealServer(p); if(server == null) return false; return server.isJoinable(p) && !isPaused(); } + @Override + public int getManualMaxPlayers() { + return manualMaxPlayers; + } + + @Override + public boolean isManuallyFull() { + int total = 0; + for (AdaptedServer server : servers) { + Optional lastPing = server.getLastPing(); + if(!lastPing.isPresent()) continue; + total += lastPing.get().getPlayerCount(); + } + +// Debug.info(total + " >= " + getManualMaxPlayers() + " = " + (total >= getManualMaxPlayers())); + + return total >= getManualMaxPlayers(); + } + @Override public synchronized void setPaused(boolean paused) { this.paused = paused; @@ -201,9 +247,9 @@ public class QueueServerImpl implements QueueServer { } @Override - public synchronized void removePlayer(QueuePlayer player) { + public void removePlayer(QueuePlayer player) { main.getQueueManager().getSendingAttempts().remove(player); - queue.remove(player); + queueHolder.removePlayer(player); positionChange(); } @@ -220,13 +266,13 @@ public class QueueServerImpl implements QueueServer { } @Override - public synchronized void addPlayer(QueuePlayer player, int position) { - if(!player.getQueueServer().equals(this) || queue.contains(player)) return; + public void addPlayer(QueuePlayer player, int position) { + if(!player.getQueueServer().equals(this) || queueHolder.findPlayer(player.getUniqueId()) != null) return; if(position >= 0) { - queue.add(position, player); + queueHolder.addPlayer(player, position); } else { - queue.add(player); + queueHolder.addPlayer(player); } positionChange(); } @@ -271,6 +317,11 @@ public class QueueServerImpl implements QueueServer { return ImmutableList.copyOf(names); } + @Override + public boolean isOnline() { + return QueueServer.super.isOnline(); + } + @Override public boolean isGroup() { return servers.size() > 1; @@ -278,25 +329,15 @@ public class QueueServerImpl implements QueueServer { @Override public QueuePlayer findPlayer(String player) { - for(QueuePlayer queuePlayer : queue) { - if(queuePlayer.getName().equalsIgnoreCase(player)) { - return queuePlayer; - } - } - return null; + return queueHolder.findPlayer(player); } @Override public QueuePlayer findPlayer(AdaptedPlayer player) { return findPlayer(player.getUniqueId()); } @Override - public synchronized QueuePlayer findPlayer(UUID uuid) { - for(QueuePlayer queuePlayer : queue) { - if(queuePlayer.getUniqueId().toString().equals(uuid.toString())) { - return queuePlayer; - } - } - return null; + public QueuePlayer findPlayer(UUID uuid) { + return queueHolder.findPlayer(uuid); } @Override @@ -319,9 +360,14 @@ public class QueueServerImpl implements QueueServer { return balancer; } + @Override + public QueueHolder getQueueHolder() { + return queueHolder; + } + private void positionChange() { main.getTaskManager().runNow( - () -> queue.forEach(queuePlayer -> { + () -> queueHolder.getAllPlayers().forEach(queuePlayer -> { if(((QueuePlayerImpl) queuePlayer).lastPosition != queuePlayer.getPosition()) { main.call(new PositionChangeEvent(queuePlayer)); } diff --git a/common/src/main/java/us/ajg0702/queue/common/queues/balancers/DefaultBalancer.java b/common/src/main/java/us/ajg0702/queue/common/queues/balancers/DefaultBalancer.java index 6370f5b..8c90fe8 100644 --- a/common/src/main/java/us/ajg0702/queue/common/queues/balancers/DefaultBalancer.java +++ b/common/src/main/java/us/ajg0702/queue/common/queues/balancers/DefaultBalancer.java @@ -1,15 +1,13 @@ package us.ajg0702.queue.common.queues.balancers; +import org.jetbrains.annotations.Nullable; import us.ajg0702.queue.api.players.AdaptedPlayer; import us.ajg0702.queue.api.queues.Balancer; import us.ajg0702.queue.api.queues.QueueServer; import us.ajg0702.queue.api.server.AdaptedServer; -import us.ajg0702.queue.api.server.AdaptedServerPing; import us.ajg0702.queue.common.QueueMain; -import us.ajg0702.queue.common.utils.Debug; import us.ajg0702.utils.common.GenUtils; -import java.util.HashMap; import java.util.List; public class DefaultBalancer implements Balancer { @@ -22,7 +20,13 @@ public class DefaultBalancer implements Balancer { } @Override - public AdaptedServer getIdealServer(AdaptedPlayer player) { + public AdaptedServer getIdealServer(@Nullable AdaptedPlayer player) { + AdaptedServer alreadyConnected; + if(player == null) { + alreadyConnected = null; + } else { + alreadyConnected = player.getCurrentServer(); + } List servers = server.getServers(); AdaptedServer selected = null; int selectednum = 0; @@ -31,6 +35,7 @@ public class DefaultBalancer implements Balancer { } else { for(AdaptedServer sv : servers) { if(!sv.isOnline()) continue; + if(sv.equals(alreadyConnected)) continue; int online = sv.getPlayerCount(); if(selected == null) { selected = sv; diff --git a/common/src/main/java/us/ajg0702/queue/common/queues/balancers/FirstBalancer.java b/common/src/main/java/us/ajg0702/queue/common/queues/balancers/FirstBalancer.java new file mode 100644 index 0000000..0604768 --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/common/queues/balancers/FirstBalancer.java @@ -0,0 +1,37 @@ +package us.ajg0702.queue.common.queues.balancers; + +import org.jetbrains.annotations.Nullable; +import us.ajg0702.queue.api.players.AdaptedPlayer; +import us.ajg0702.queue.api.queues.Balancer; +import us.ajg0702.queue.api.queues.QueueServer; +import us.ajg0702.queue.api.server.AdaptedServer; +import us.ajg0702.queue.common.QueueMain; + +public class FirstBalancer implements Balancer { + + private final QueueServer server; + private final QueueMain main; + public FirstBalancer(QueueServer server, QueueMain main) { + this.server = server; + this.main = main; + } + + @Override + public AdaptedServer getIdealServer(@Nullable AdaptedPlayer player) { + AdaptedServer alreadyConnected; + if(player == null) { + alreadyConnected = null; + } else { + alreadyConnected = player.getCurrentServer(); + } + for (AdaptedServer sv : server.getServers()) { + if(!sv.isOnline()) continue; + if(sv.equals(alreadyConnected)) continue; + if(!sv.isJoinable(player)) continue; + return sv; + } + + // If all servers are unavailable, just select the first one + return server.getServers().get(0); + } +} diff --git a/common/src/main/java/us/ajg0702/queue/common/queues/balancers/MinigameBalancer.java b/common/src/main/java/us/ajg0702/queue/common/queues/balancers/MinigameBalancer.java index 941b82e..3eb67c3 100644 --- a/common/src/main/java/us/ajg0702/queue/common/queues/balancers/MinigameBalancer.java +++ b/common/src/main/java/us/ajg0702/queue/common/queues/balancers/MinigameBalancer.java @@ -1,13 +1,15 @@ package us.ajg0702.queue.common.queues.balancers; +import org.jetbrains.annotations.Nullable; import us.ajg0702.queue.api.players.AdaptedPlayer; import us.ajg0702.queue.api.queues.Balancer; import us.ajg0702.queue.api.queues.QueueServer; import us.ajg0702.queue.api.server.AdaptedServer; -import us.ajg0702.queue.api.server.AdaptedServerPing; import us.ajg0702.queue.common.QueueMain; -import java.util.*; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; public class MinigameBalancer implements Balancer { @@ -19,7 +21,13 @@ public class MinigameBalancer implements Balancer { } @Override - public AdaptedServer getIdealServer(AdaptedPlayer player) { + public AdaptedServer getIdealServer(@Nullable AdaptedPlayer player) { + AdaptedServer alreadyConnected; + if(player == null) { + alreadyConnected = null; + } else { + alreadyConnected = player.getCurrentServer(); + } List servers = server.getServers(); if(servers.size() == 1) { return servers.get(0); @@ -30,6 +38,7 @@ public class MinigameBalancer implements Balancer { for(AdaptedServer si : svs) { if(!si.isOnline()) continue; + if(si.equals(alreadyConnected)) continue; int online = si.getPlayerCount(); int max = si.getMaxPlayers(); if(online < max && si.isJoinable(player)) { diff --git a/common/src/main/java/us/ajg0702/queue/logic/FreeLogic.java b/common/src/main/java/us/ajg0702/queue/logic/FreeLogic.java index 3feb389..fa16f35 100644 --- a/common/src/main/java/us/ajg0702/queue/logic/FreeLogic.java +++ b/common/src/main/java/us/ajg0702/queue/logic/FreeLogic.java @@ -28,6 +28,11 @@ public class FreeLogic implements Logic { return null; } + @Override + public int getHighestPriority(QueueServer queueServer, AdaptedServer server, AdaptedPlayer player) { + return player.hasPermission("ajqueue.priority") ? 1 : 0; + } + @Override public boolean hasAnyBypass(AdaptedPlayer player, String server) { return false; diff --git a/common/src/main/resources/config.yml b/common/src/main/resources/config.yml index 74055e5..2012927 100644 --- a/common/src/main/resources/config.yml +++ b/common/src/main/resources/config.yml @@ -1,179 +1,66 @@ -# Dont touch this number please -config-version: 35 +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# # +# _ ___ # +# (_) / _ \ # +# __ _ _ | | | | _ _ ___ _ _ ___ # +# / _` || || | | || | | | / _ \| | | | / _ \ # +# | (_| || |\ \/' /| |_| || __/| |_| || __/ # +# \__,_|| | \_/\_\ \__,_| \___| \__,_| \___| # +# _/ | # +# |__/ # +# # +# Welcome to the config for ajQueue! # +# # +# Make sure to read the comments above each option to know what that option does. # +# # +# If you have any questions, first make sure you've read the comment above the option, then # +# feel free to join my discord and ask there (invite link is on the plugin page) # +# # +# Happy configuring! # +# # +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# This is the main config for ajQueue. -# If you have any questions, make sure to read the comment above the options first, -# then feel free to join my discord and ask for support. -# Discord invite link is on the plugin page. - - - -# The time the server will wait between sending people in the queue +# The time the server will wait between sending people in the queue (in seconds, supports decimals) # Default: 5 wait-time: 5.0 -# The time that a server has to be offline to be marked as offline instead of restarting -# Default: 120 -offline-time: 120 - -# The time the server will wait between sending players update messages on what position they are in the queue. +# The time ajQueue will wait between sending players update messages on +# what position they are in the queue, their ETA, and status of the queue (in seconds) +# You can set to any negative number to disable the messages # Default: 10 message-time: 10 -# If a player is in a server, you can have the plugin make them automatically join a queue for another server -# Example with the default values: Player joins the limbo server, they will auto-join the queue for the lobbys group -# Note that you dont have to use groups. Just put the name of a server to use a single server instead. -queue-servers: - - 'limbo:lobbys' - -# Should the plugin send an actionbar to the player? -# The actionbar contains some info such as which server they are queued for, what position they are in, estimated time remaining, etc. -send-actionbar: true - -# What kick reasons should cause the player to be removed from the queue? -# For example, if one of the below kick reasons is 'banned' and the player gets kicked when trying to connect to -# a server in a queue with a message saying "You are banned from this server!" then it will kick them from the queue too. -kick-reasons: - - 'banned' - - 'blacklisted' - -# Should we completly kick the user from the server if they are in a queue-server -# and are kicked from the server with one of the above reasons? -# Note this will do nothing on servers that arent queue-servers -# (as in the config option queue-servers) -# Default: true -kick-kicked-players: true - -# Should we remove a player from the queue if they move servers? -# This will remove the player from if they switch to any other server -# Default: false -remove-player-on-server-switch: false - - -# Should we wait until the server is done loading to load the servers? -# Enable this if you have a plugin that adds servers to the server list during startup. -# Default: false -wait-to-load-servers: false - -# How long should we wait after the server finishes loading to load the server list? -# Only works if the above is enabled. -# This is in miliseconds so 1000 = 1 second -# Default: 500 -wait-to-load-servers-delay: 500 - - -# How often (in seconds) we should check for new servers to add queues for. -# If you dynamicly add servers, set this to something other than 0. -# To disable, set to 0 -# Default: 0 -reload-servers-interval: 0 - # Should we require permissions for players to be able to join queues? # If enabled, players will be required to have the permission ajqueue.queue. to be able to join queues +# Replace with the name of the server or group to let the player queue for # Default: false require-permission: false - -# Should we let players join more than one queue? -# If enabled, players will be able to be in multiple queues at once. -# If disabled, players will be removed from the previous queue when joining a new queue -# Default: true -allow-multiple-queues: true - -# If the player is queued for multiple servers, which server should we pick to use in things like placeholders and actionbars -# Options are first and last -# Default: last -multi-server-queue-pick: last - - -# THIS FEATURE IS ONLY AVAILABLE ON ajQueuePlus (https://www.spigotmc.org/resources/ajqueueplus.79123/) -# This will show players a different name than the actual proxy server name -# for example, instead of showing players "event-a", this option can make it appear as "Event A" -# With this example, you would use this: - "event-a:Event A" -# Note that currently players still have to use the normal names in queue commands and leave commands -# Format: "realname:Alias" -server-aliases: - - "event-a:Event A" - - -# How long should we wait after a server is online before sending players? -# The server will still show up as offline or restarting until this amount of time after its up -# Meant to let your server 'cool down' after lag from starting up -# In seconds -# Default: 1 -wait-after-online: 1 - - -# This is for helping with finding issues with the server pinged -# This will spam the console when enabled -# When this enabled, if servers are offline then it will spam errors. You can ignore them. -# Default: false -pinger-debug: false - - -# When a queue is paused, should we prevent players from joining it? -# Default: false -prevent-joining-paused: false - -# When a server goes back online, should we send all players in the queue instantly? -# Default: false -send-all-when-back-online: false - -# Require a permission for players to be able to join a queue from a server +# Require a permission for players to be able to join a queue from a server. # If enabled, players will need the permission ajqueue.joinfrom. to join queues. # Replace with the name of the server # Default: false joinfrom-server-permission: false -# Server groups are a group of servers that you can queue for. It will send you to the server that is the least full. -# If all servers in the group are full, it will act the same as it would when a single server is full. -# Same if all servers are offline. It will only send players to servers that are online. -# Format: "groupname:server1,server2,etc" -server-groups: - - "lobbys:lobby-1,lobby-2,lobby-3" - - -# Should we allow tab-completing in the /queue command? -# Default: true -tab-complete-queues: true - -# Should we have no wait time for these servers? -# If the server is joinable, the plugin will attempt to send players who join these queues as soon as they join. -# If the server is not immidiatly joinable, they will have to wait for the normal wait-time -# This also works with group -# NOTE: Server names are caps sensitive -send-instantly: - - "lobbys" - -# Should we log to the proxy console when a player fails to get sent to a server from the queue? -# Enable this if you are having an issue with one player stopping the queue -# Default: false -send-fail-debug: false - -# After how many (unsuccessfull) attempts of sending the player should we remove them from the queue? -# Set to -1 to disable -# Default: 10 -max-tries: 10 - # Should we enable the ajqueue.bypasspaused permission? # If enabled, anyone with the permission ajqueue.bypasspaused will be able to join paused servers # Default: false enable-bypasspaused-permission: false -# Should we check to make sure that people dont get sent quicker than wait-time? -# Default: true -check-last-player-sent-time: true -# Should we send debug info to the console when priority queue is used? -# This will print several lines to the console when a player joins a queue, -# so you should probably only use this for debugging purposes -# Default: false -priority-queue-debug: false +# What kick reasons should cause the player to be removed from the queue? +# This works on contains, so you only need to include a word or two from the kick message. +# For example, if one of the below kick reasons is 'banned' and the player gets kicked when trying to connect to +# a server in a queue with a message saying "You are banned from this server!" then it will kick them from the queue too. +kick-reasons: + - 'banned' + - 'blacklisted' + # When a player is kicked from a server, should we automatically add that player to the queue? -# You will still need to use another plugin to make sure the player doesnt get kicked from the proxy completly. +# On BungeeCord, you will still need to use another plugin to make sure the player doesn't get kicked from the proxy completely. # Default: false auto-add-to-queue-on-kick: false # The delay for the above option. @@ -182,19 +69,111 @@ auto-add-to-queue-on-kick: false auto-add-to-queue-on-kick-delay: 1 # With what kick reasons should we auto-add the player to the queue -# This wont work if auto-add-to-queue-on-kick is disabled. +# This won't work if auto-add-to-queue-on-kick is disabled. # If you set it to [], then all kick messages will cause the player to be added to the queue -# This works on contains, so you dont have to include the whole kick message, just a few words. +# This works on contains, so you don't have to include the whole kick message, just a few words. auto-add-kick-reasons: - "restarting" - "closed" + +# If a player is in a server, you can have the plugin make them automatically join a queue for another server +# Example with the default values: Player joins the limbo server, they will auto-join the queue for the lobbys group +# Note that you don't have to use groups. Just put the name of a server to use a single server instead. +# You do NOT have to set a queue server to use queues. +queue-servers: + - 'limbo:lobbys' + +# How much should we delay queueing players in queue servers? +# You should only use this if you have issues with the instant sending. +# Set to 0 or any negative number to disable +# In milliseconds. Maximum value is 3000 (3 seconds) +# Default: 0 +queue-server-delay: 0 + +# Should we completely kick the user from the server if they are in a queue-server +# and are kicked from the server with one of the above reasons? +# Note this will do nothing on servers that aren't queue-servers +# (as in the config option queue-servers) +# Default: true +kick-kicked-players: true + +# This option allows you to manually set player caps for servers +# Note that this does NOT override the player cap returned by the server. +# Format: - ':' +# Example: - 'lobbys:50' +# The example above will limit the lobbys group to have a total of 50 players. +# This works on both groups and individual servers +manual-max-players: [] + + +# Server groups are a group of servers that you can queue for. It will send you to the server that is the least full. +# If all servers in the group are full, it will act the same as it would when a single server is full. +# Same if all servers are offline. It will only send players to servers that are online. +# Format: "groupname:server1,server2,etc" +server-groups: + - "lobbys:lobby-1,lobby-2,lobby-3" + +# What balancer should we use for groups? +# If a group is not specified here, then the default one is used +# Example: - "bedwars:minigame" +# The example above will set the bedwars group to use the minigame balancer +# Balancers: +# default - Will send the player to the server in the group with the least number of players +# minigame - Will send the player to the server with the most players, until that server is full, which it will then send to the next server +# first - Will send the player to the first available server in the group (as long as it is joinable) +balancer-types: + - "bedwars:minigame" + +# If a player is in a server that is in a group and they re-queue for that group, should we allow it? +# false - prevent player from re-queueing; say "already connected" message +# true - let player re-queue; will send them to a server other than the one they're connected to +# Default: false +allow-group-requeue: false + + +# What priority should we give whitelisted players priority when the server is whitelisted? +# This will have no effect if the server isn't whitelisted +# If you set to 0, this will be disabled +# If you have the free version, set it to 1 to enable +give-whitelisted-players-priority: 0 + +# What priority should we give players that are able to bypass paused priority when the server is paused? +# This will have no effect if the server isn't paused +# If you set to 0, this will be disabled +# If you have the free version, set it to 1 to enable +give-pausedbypass-players-priority: 0 + +# What priority should we give players that are able to bypass full servers priority when the server is full? +# This will have no effect if the server isn't full +# If you are using make-room, this also applies to that +# If you set to 0, this will be disabled +# If you have the free version, set it to 1 to enable +give-fulljoin-players-priority: 0 + + +# Should we remove a player from the queue if they move servers? +# This will remove the player from if they switch to any other server +# Default: false +remove-player-on-server-switch: false + # Should we enable the server command being a queue command? # This may require extra setup on bungeecord. See the wiki: # https://wiki.ajg0702.us/ajqueue/setup/replacing-server-command # Default: false enable-server-command: false +# What servers should we make slash server commands for? +# For example, if survival is in this list, then if a player executes /survival +# then they will be put in the queue for survival +# This works for both servers and groups +# If you have ajQueuePlus, you can also make aliases. +# For example, if you have a server called lobby, and you want people to be able to use /hub, you can use this: +# - "hub:lobby" +# If you have the free version, you can only put the server name, no aliases. +slash-servers: [] + + # Should we enable priority messages? # Configure the priority messages in the option below. # Default: false @@ -209,11 +188,156 @@ priority-messages: - "*:Joining the queue with a priority of {PRIORITY}!" - "100:Wow! You have a priority of 100!" + # Should the plugin send a title to the player? # The title shows what position the player is in the queue # Default: false send-title: false +# Should we log to the proxy console when a player fails to get sent to a server from the queue? +# Enable this if you are having an issue with one player stopping the queue +# Default: false +send-fail-debug: false + +# Should the plugin send an actionbar to the player? +# The actionbar contains some info such as which server they are queued for, what position they are in, estimated time remaining, etc. +send-actionbar: true + +# THIS FEATURE IS ONLY AVAILABLE ON ajQueuePlus (https://www.spigotmc.org/resources/ajqueueplus.79123/) +# This will show players a different name than the actual proxy server name +# for example, instead of showing players "event-a", this option can make it appear as "Event A" +# With this example, you would use this: - "event-a:Event A" +# Note that currently players still have to use the normal names in queue commands and leave commands +# Format: "realname:Alias" +server-aliases: + - "event-a:Event A" + +# The time that a server has to be offline to be marked as offline instead of restarting (in seconds) +# Default: 120 +offline-time: 120 + +# On velocity, should we end a player a message when they are kicked while trying to connect to a server with the queue? +# This has no effect on bungee, because the message is sent from bungee and there's no way to change that in ajQueue +# Default: false +velocity-kick-message: false + +# Should we wait until the server is done loading to load the servers? +# Enable this if you have a plugin that adds servers to the server list during startup. +# Default: false +wait-to-load-servers: false + +# How long should we wait after the server finishes loading to load the server list? +# Only works if the above is enabled. +# This is in milliseconds so 1000 = 1 second +# Default: 500 +wait-to-load-servers-delay: 500 + +# How often (in seconds) we should check for new servers to add queues for. +# If you dynamically add servers, set this to something other than 0. +# To disable, set to 0 +# Default: 0 +reload-servers-interval: 0 + +# Should we let players join more than one queue? +# If enabled, players will be able to be in multiple queues at once. +# If disabled, players will be removed from the previous queue when joining a new queue +# Default: true +allow-multiple-queues: true + +# If the player is queued for multiple servers, which server should we pick to use in things like placeholders and actionbars +# Options are first and last +# Default: last +multi-server-queue-pick: last + +# How long should we wait after a server is online before sending players? +# The server will still show up as offline or restarting until this amount of time after its up +# Meant to let your server 'cool down' after lag from starting up +# In seconds +# Default: 1 +wait-after-online: 1 + +# This is for helping with finding issues with the server pinged +# This will spam the console when enabled +# When this enabled, if servers are offline then it will spam errors. You can ignore them. +# Default: false +pinger-debug: false + +# When a queue is paused, should we prevent players from joining it? +# (instead of having players wait in the queue until it's unpaused) +# Default: false +prevent-joining-paused: false + +# When a server goes back online, should we send all players in the queue instantly? +# Default: false +send-all-when-back-online: false + +# Should we allow tab-completing in the /queue command? +# Any server the player doesn't have permission for (require-permission) +# will not tab-complete +# Default: true +tab-complete-queues: true + +# Should we have no wait time for these servers? +# If the server is joinable, the plugin will attempt to send players who join these queues as soon as they join. +# If the server is not immediately joinable, they will have to wait for the normal wait-time +# This also works with group +# NOTE: Server names are caps sensitive +send-instantly: + - "lobbys" + +# Should we require permissions for queue-servers to work? +# If enabled, players will need to have the ajqueue.queueserver. permission +# being the target server +# Note that this will only affect queue-servers +# Default: false +require-queueserver-permission: false + +# After how many (unsuccessful) attempts of sending the player should we remove them from the queue? +# Set to -1 to disable +# Default: 10 +max-tries: 10 + +# What QueueHolder should we use? +# By default, the only QueueHolder available is 'default' +# But more may be available via addons (registered via the API) +queue-holder: default + + +# Should we enable the ajqueue.make-room permission? +# The make-room permission will force there to be room in a server. +# So, if a player with this permission queues for a server and has this permission, +# someone from the server will be moved to the lobby to make room +# This can be further configured using the next few options +# Default: false +enable-make-room-permission: false + +# What server should the make-room permission move players to? +# Default: lobby +make-room-kick-to: lobby + +# For the make-room permission, players with the lowest priority are kicked first. +# Of those players, this option decides which to kick. +# true - kick players who have been on the server the longest +# false - kick players who have been on the server the shortest +# Default: true +make-room-kick-longest-playtime: true + + +# Should we check every 4 seconds if a player has a higher priority permission than before +# If they do, they are removed and re-added to the queue (only if they would be put in a higher position) +# Default: false +re-check-priority: false + +# Should we check to make sure that people don't get sent quicker than wait-time? +# Default: true +check-last-player-sent-time: true + +# Should we send debug info to the console when priority queue is used? +# This will print several lines to the console when a player joins a queue, +# so you should probably only use this for debugging purposes +# Default: false +priority-queue-debug: false + # What protocols do servers support? # The protocol version number list can be found here: https://wiki.vg/Protocol_version_numbers # Format: server(s):protocol(s) @@ -224,90 +348,9 @@ send-title: false supported-protocols: - "1.17:755,756" - -# These are the protocol names the plugin should use. -# If you are on velocity, if the protocol is not listed here then the velocity -# api will be used to find the name of the protocol. -# If you are on bungee, only this list can be used. -protocol-names: - - "757:1.18.1" - - "756:1.17.1" - - "755:1.17" - - "754:1.16.5" - - "753:1.16.3" - - "751:1.16.2" - - "736:1.16.1" - - "735:1.16" - - "578:1.15.2" - - "575:1.15.1" - - "573:1.15" - - "498:1.14.4" - - "490:1.14.3" - - "485:1.14.2" - - "480:1.14.1" - - "477:1.14" - - "404:1.13.2" - - "401:1.13.1" - - "393:1.13" - - "340:1.12.2" - - "338:1.12.1" - - "335:1.12" - - "316:1.11.2" - - "315:1.11" - - "210:1.10.2" - - "110:1.9.4" - - "109:1.9.2" - - "108:1.9.1" - - "107:1.9" - - "47:1.8.9" - - "5:1.7.10" - -# On velocity, should we end a player a message when they are kicked while trying to connect to a server with the queue? -# This has no effect on bungee, because the message is sent from bungee and theres no way to change that in ajQueue -# Default: false -velocity-kick-message: false - # Should the updater be enabled? enable-updater: true -# What servers should we make slash server commands for? -# For example, if survival is in this list, then if a player executes /survival -# then they will be put in the queue for survival -# This works for both servers and groups -# If you have ajQueuePlus, you can also make aliases. -# For example, if you have a server called lobby, and you want people to be able to use /hub, you can use this: -# - "hub:lobby" -# If you have the free version, you can only put the server name, no aliases. -slash-servers: [] - -# What balancer should we use? -# If a group is not specified here, then the default one is used -# Example entry: - "bedwars:minigame" -# Balancers: -# default - Will send the player to the server in the group with the least number of players -# minigame - Will send the player to the server with the most players, until that server is full, which it will then send to the next server -balancer-types: - - "bedwars:minigame" - -# What priority should we give whitelisted players priority when the server is whitelisted? -# This will have no effect if the server isnt whitelisted -# If you set to 0, this will be disabled -# If you have the free version, set it to 1 to enable -give-whitelisted-players-priority: 0 - -# What priority should we give players that are able to bypass paused priority when the server is paused? -# This will have no effect if the server isnt paused -# If you set to 0, this will be disabled -# If you have the free version, set it to 1 to enable -give-pausedbypass-players-priority: 0 - -# What priority should we give players that are able to bypass full servers priority when the server is full? -# This will have no effect if the server isnt full -# If you set to 0, this will be disabled -# If you have the free version, set it to 1 to enable -give-fulljoin-players-priority: 0 - - # Should we force players to be queued every few seconds for queue-servers? # This will check every few seconds, and if a player in a queue-server is # not in the queue for the target server, it will add them. @@ -321,10 +364,34 @@ queue-command-cooldown: 3 # Should any server switch (including the initial join) count against the queue command cooldown? include-server-switch-in-cooldown: false - -# The minimum time between pinging the server. +# The minimum time between pinging the server. (in seconds) # If ajQueue is pinging your backend servers too often, raise this number minimum-ping-time: 1.0 +# In ajQueuePlus, if your permission plugin isn't yet supported, you can use this workaround to +# be able to use levels 1-10 for priority, or 15, 30, 60, and 120 for stayqueued +# If you want more levels than that, contact aj to add support for your permission plugin if possible. +# Does nothing if you are not on ajQueuePlus, or if you have a supported permission plugin +plus-level-fallback: false + # Should we print some extra stuff to the console that might help aj diagnose some issues? -debug: false \ No newline at end of file +debug: false + + + +# # # # # # # # # # # # # # # # # # # # # +# # +# End of config. Happy queue-ing :) # +# # +# # # # # # # # # # # # # # # # # # # # # + + + + +# Don't touch this number please +config-version: 44 + + +# This is ONLY here so that they can be moved to messages.yml. Please edit these in messages.yml! +protocol-names: [] +# ^ only edit these in messages.yml diff --git a/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/server/BungeeServer.java b/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/server/BungeeServer.java index 8361efd..84b6d0b 100644 --- a/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/server/BungeeServer.java +++ b/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/server/BungeeServer.java @@ -106,23 +106,17 @@ public class BungeeServer implements AdaptedServer { return offlineTime; } - @Override - public boolean canJoinFull(AdaptedPlayer player) { - if(player == null) return true; - return - player.hasPermission("ajqueue.joinfull") || - player.hasPermission("ajqueue.joinfullserver."+getName()) || - player.hasPermission("ajqueue.joinfullandbypassserver."+getName()) || - player.hasPermission("ajqueue.joinfullandbypass") || - (AjQueueAPI.getInstance().isPremium() && AjQueueAPI.getInstance().getLogic().getPermissionGetter().hasUniqueFullBypass(player, getName())) - ; - } @Override public boolean justWentOnline() { return System.currentTimeMillis()-lastOffline <= (AjQueueAPI.getInstance().getConfig().getDouble("wait-time") * 2 * 1000) && isOnline(); } + @Override + public boolean shouldWaitAfterOnline() { + return System.currentTimeMillis()-lastOffline <= (AjQueueAPI.getInstance().getConfig().getDouble("wait-after-online") * 2 * 1000) && getLastPing().isPresent(); + } + @Override public ServerInfo getHandle() { return handle; diff --git a/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/server/VelocityServer.java b/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/server/VelocityServer.java index e42268b..2ae6563 100644 --- a/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/server/VelocityServer.java +++ b/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/server/VelocityServer.java @@ -9,7 +9,6 @@ import us.ajg0702.queue.api.server.AdaptedServer; import us.ajg0702.queue.api.server.AdaptedServerInfo; import us.ajg0702.queue.api.server.AdaptedServerPing; import us.ajg0702.queue.api.util.QueueLogger; -import us.ajg0702.queue.common.utils.Debug; import us.ajg0702.queue.platforms.velocity.players.VelocityPlayer; import java.util.ArrayList; @@ -114,21 +113,13 @@ public class VelocityServer implements AdaptedServer { } @Override - public boolean canJoinFull(AdaptedPlayer player) { - if(player == null) return true; - Debug.info("on "+getName()); - return - player.hasPermission("ajqueue.joinfull") || - player.hasPermission("ajqueue.joinfullserver."+getName()) || - player.hasPermission("ajqueue.joinfullandbypassserver."+getName()) || - player.hasPermission("ajqueue.joinfullandbypass") || - (AjQueueAPI.getInstance().isPremium() && AjQueueAPI.getInstance().getLogic().getPermissionGetter().hasUniqueFullBypass(player, getName())) - ; + public boolean justWentOnline() { + return System.currentTimeMillis()-lastOffline <= (AjQueueAPI.getInstance().getConfig().getDouble("wait-time") * 2 * 1000) && isOnline(); } @Override - public boolean justWentOnline() { - return System.currentTimeMillis()-lastOffline <= (AjQueueAPI.getInstance().getConfig().getDouble("wait-time") * 2 * 1000) && isOnline(); + public boolean shouldWaitAfterOnline() { + return System.currentTimeMillis()-lastOffline <= (AjQueueAPI.getInstance().getConfig().getDouble("wait-after-online") * 2 * 1000) && getLastPing().isPresent(); } @Override diff --git a/premium/src/main/java/us/ajg0702/queue/logic/PremiumLogic.java b/premium/src/main/java/us/ajg0702/queue/logic/PremiumLogic.java index bd86144..1bf4e14 100644 --- a/premium/src/main/java/us/ajg0702/queue/logic/PremiumLogic.java +++ b/premium/src/main/java/us/ajg0702/queue/logic/PremiumLogic.java @@ -18,6 +18,15 @@ public class PremiumLogic implements Logic { return permissionGetter; } + @Override + public int getHighestPriority(QueueServer queueServer, AdaptedServer server, AdaptedPlayer player) { + int normalPriority = permissionGetter.getPriority(player); + int serverPriority = permissionGetter.getServerPriotity(queueServer.getName(), player); + int unJoinablePriority = Logic.getUnJoinablePriorities(queueServer, server, player); + + return Math.max(normalPriority, Math.max(serverPriority, unJoinablePriority)); + } + private final PermissionGetter permissionGetter; public PremiumLogic(QueueMain main) { permissionGetter = new PermissionGetterImpl(main); diff --git a/premium/src/main/java/us/ajg0702/queue/logic/permissions/PermissionGetterImpl.java b/premium/src/main/java/us/ajg0702/queue/logic/permissions/PermissionGetterImpl.java index 9cff1a4..e624b0e 100644 --- a/premium/src/main/java/us/ajg0702/queue/logic/permissions/PermissionGetterImpl.java +++ b/premium/src/main/java/us/ajg0702/queue/logic/permissions/PermissionGetterImpl.java @@ -1,9 +1,11 @@ package us.ajg0702.queue.logic.permissions; +import us.ajg0702.queue.api.AjQueueAPI; import us.ajg0702.queue.api.players.AdaptedPlayer; import us.ajg0702.queue.api.premium.PermissionGetter; import us.ajg0702.queue.api.premium.PermissionHook; import us.ajg0702.queue.common.QueueMain; +import us.ajg0702.queue.common.utils.Debug; import us.ajg0702.queue.logic.permissions.hooks.AquaCoreHook; import us.ajg0702.queue.logic.permissions.hooks.BuiltInHook; import us.ajg0702.queue.logic.permissions.hooks.LuckPermsHook; @@ -13,16 +15,15 @@ import java.util.*; public class PermissionGetterImpl implements PermissionGetter { - private final List hooks; - private final QueueMain main; + private PermissionHook builtInHook; public PermissionGetterImpl(QueueMain main) { - hooks = Arrays.asList( - new BuiltInHook(main), + AjQueueAPI.getPermissionHookRegistry().register( new LuckPermsHook(main), new UltraPermissionsHook(main), new AquaCoreHook(main) ); + builtInHook = new BuiltInHook(main); this.main = main; } @@ -30,16 +31,15 @@ public class PermissionGetterImpl implements PermissionGetter { @Override public PermissionHook getSelected() { if(selected != null) return selected; - if(hooks == null) { - throw new IllegalStateException("Hooks are not initialized yet!"); - } - for(PermissionHook hook : hooks) { - if(hook.canUse()) { + for(PermissionHook hook : AjQueueAPI.getPermissionHookRegistry().getRegisteredHooks()) { + boolean canUse = hook.canUse(); + Debug.info(hook.getName() + " "+ canUse); + if(canUse) { selected = hook; } } if(selected == null) { - throw new IllegalStateException("All hooks are unusable!"); + selected = builtInHook; } main.getLogger().info("Using "+selected.getName()+" for permissions."); return selected; diff --git a/premium/src/main/java/us/ajg0702/queue/logic/permissions/hooks/BuiltInHook.java b/premium/src/main/java/us/ajg0702/queue/logic/permissions/hooks/BuiltInHook.java index 1ea1391..e134a03 100644 --- a/premium/src/main/java/us/ajg0702/queue/logic/permissions/hooks/BuiltInHook.java +++ b/premium/src/main/java/us/ajg0702/queue/logic/permissions/hooks/BuiltInHook.java @@ -5,6 +5,8 @@ import us.ajg0702.queue.common.QueueMain; import us.ajg0702.queue.api.premium.PermissionHook; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; public class BuiltInHook implements PermissionHook { @@ -26,9 +28,41 @@ public class BuiltInHook implements PermissionHook { @Override public List getPermissions(AdaptedPlayer player) { - if(main.getPlatformMethods().getImplementationName().equals("velocity")) { - return new ArrayList<>(); + if(main.getConfig().getBoolean("plus-level-fallback")) { + List hasPermissions = new ArrayList<>(); + for (String fallbackPermission : fallbackPermissions) { + if(player.hasPermission(fallbackPermission)) { + hasPermissions.add(fallbackPermission); + } + } + if(!main.getPlatformMethods().getImplementationName().equals("velocity")) { + hasPermissions.addAll(player.getPermissions()); + } + return hasPermissions; } + + + if(main.getPlatformMethods().getImplementationName().equals("velocity")) { + return Collections.emptyList(); + } + return player.getPermissions(); } + + private final List fallbackPermissions = Arrays.asList( + "ajqueue.priority.1", + "ajqueue.priority.2", + "ajqueue.priority.3", + "ajqueue.priority.4", + "ajqueue.priority.5", + "ajqueue.priority.6", + "ajqueue.priority.7", + "ajqueue.priority.8", + "ajqueue.priority.9", + "ajqueue.priority.10", + "ajqueue.stayqueued.15", + "ajqueue.stayqueued.30", + "ajqueue.stayqueued.60", + "ajqueue.stayqueued.120" + ); } diff --git a/spigot/src/main/java/us/ajg0702/queue/spigot/SpigotMain.java b/spigot/src/main/java/us/ajg0702/queue/spigot/SpigotMain.java index abde51e..63257aa 100644 --- a/spigot/src/main/java/us/ajg0702/queue/spigot/SpigotMain.java +++ b/spigot/src/main/java/us/ajg0702/queue/spigot/SpigotMain.java @@ -110,10 +110,7 @@ public class SpigotMain extends JavaPlugin implements PluginMessageListener,List } if(subchannel.equals("inqueueevent")) { - String playername = in.readUTF(); - Player p = Bukkit.getPlayer(playername); - if(p == null) return; - QueueScoreboardActivator e = new QueueScoreboardActivator(p); + QueueScoreboardActivator e = new QueueScoreboardActivator(player); Bukkit.getPluginManager().callEvent(e); return; } diff --git a/spigot/src/main/java/us/ajg0702/queue/spigot/api/SpigotAPI.java b/spigot/src/main/java/us/ajg0702/queue/spigot/api/SpigotAPI.java index 7dcb80d..a126d18 100644 --- a/spigot/src/main/java/us/ajg0702/queue/spigot/api/SpigotAPI.java +++ b/spigot/src/main/java/us/ajg0702/queue/spigot/api/SpigotAPI.java @@ -7,6 +7,7 @@ import us.ajg0702.queue.api.spigot.MessagedResponse; import us.ajg0702.queue.spigot.SpigotMain; import us.ajg0702.queue.spigot.communication.ResponseManager; +import java.util.Collection; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Future; @@ -113,7 +114,7 @@ public class SpigotAPI extends AjQueueSpigotAPI { @Override public Future getPlayersInQueue(String queueName) { - Player p = Bukkit.getOnlinePlayers().iterator().next(); + Player p = getSomePlayer(); CompletableFuture future = new CompletableFuture<>(); @@ -121,6 +122,7 @@ public class SpigotAPI extends AjQueueSpigotAPI { String responseString = response.getResponse(); if(responseString.equals("invalid_server")) { future.completeExceptionally(new IllegalArgumentException(queueName + " does not exist!")); + return; } future.complete(Integer.valueOf(responseString)); }); @@ -137,17 +139,19 @@ public class SpigotAPI extends AjQueueSpigotAPI { @Override public Future getServerStatusString(String queueName, UUID player) { - Player p = player == null ? Bukkit.getOnlinePlayers().iterator().next() : Bukkit.getPlayer(player); + Player p = player == null ? getSomePlayer() : Bukkit.getPlayer(player); if(p == null) throw new IllegalArgumentException("Player must be online!"); String channel = player == null ? "status" : "playerstatus"; + String id = player == null ? queueName : player + queueName; CompletableFuture future = new CompletableFuture<>(); - responseManager.awaitResponse(queueName, channel, response -> { + responseManager.awaitResponse(id, channel, response -> { String responseString = response.getResponse(); if(responseString.equals("invalid_server")) { future.completeExceptionally(new IllegalArgumentException(queueName + " does not exist!")); + return; } future.complete(responseString); }); @@ -172,4 +176,10 @@ public class SpigotAPI extends AjQueueSpigotAPI { return future; } + + private Player getSomePlayer() { + Collection players = Bukkit.getOnlinePlayers(); + if(players.size() == 0) return null; + return players.iterator().next(); + } } diff --git a/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/PlaceholderExpansion.java b/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/PlaceholderExpansion.java index f4d1eae..393f099 100644 --- a/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/PlaceholderExpansion.java +++ b/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/PlaceholderExpansion.java @@ -29,8 +29,8 @@ public class PlaceholderExpansion extends me.clip.placeholderapi.expansion.Place placeholders.add(new PositionOf(plugin)); placeholders.add(new Queued(plugin)); placeholders.add(new QueuedFor(plugin)); - placeholders.add(new Status(plugin)); placeholders.add(new StatusPlayer(plugin)); + placeholders.add(new Status(plugin)); } diff --git a/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/EstimatedTime.java b/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/EstimatedTime.java index a07b022..a9e1ebb 100644 --- a/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/EstimatedTime.java +++ b/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/EstimatedTime.java @@ -32,6 +32,7 @@ public class EstimatedTime extends Placeholder { @Override public String parse(Matcher matcher, OfflinePlayer p) { Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + if(!p.isOnline()) return; try { MessagedResponse response = AjQueueSpigotAPI.getInstance() .getEstimatedTime(p.getUniqueId()) @@ -40,9 +41,7 @@ public class EstimatedTime extends Placeholder { cache.put(p.getUniqueId(), response.getEither()); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); - } catch (TimeoutException e) { - plugin.getLogger().log(Level.WARNING, "Timed out while trying to get placeholder data from proxy: ", e); - } + } catch (TimeoutException | IllegalArgumentException ignored) {} }); return cache.getOrDefault(p.getUniqueId(), "..."); diff --git a/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/InQueue.java b/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/InQueue.java index 9b83582..7ebd222 100644 --- a/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/InQueue.java +++ b/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/InQueue.java @@ -31,6 +31,7 @@ public class InQueue extends Placeholder { @Override public String parse(Matcher matcher, OfflinePlayer p) { Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + if(!p.isOnline()) return; try { Boolean response = AjQueueSpigotAPI.getInstance() .isInQueue(p.getUniqueId()) @@ -39,9 +40,7 @@ public class InQueue extends Placeholder { cache.put(p.getUniqueId(), response + ""); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); - } catch (TimeoutException e) { - plugin.getLogger().log(Level.WARNING, "Timed out while trying to get placeholder data from proxy: ", e); - } + } catch (TimeoutException | IllegalArgumentException ignored) {} }); return cache.getOrDefault(p.getUniqueId(), "..."); diff --git a/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/Position.java b/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/Position.java index 037420f..1dbf949 100644 --- a/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/Position.java +++ b/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/Position.java @@ -32,6 +32,7 @@ public class Position extends Placeholder { @Override public String parse(Matcher matcher, OfflinePlayer p) { Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + if(!p.isOnline()) return; try { MessagedResponse response = AjQueueSpigotAPI.getInstance() .getPosition(p.getUniqueId()) @@ -40,9 +41,7 @@ public class Position extends Placeholder { cache.put(p.getUniqueId(), response.getEither()); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); - } catch (TimeoutException e) { - plugin.getLogger().log(Level.WARNING, "Timed out while trying to get placeholder data from proxy: ", e); - } + } catch (TimeoutException | IllegalArgumentException ignored) {} }); return cache.getOrDefault(p.getUniqueId(), "..."); diff --git a/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/PositionOf.java b/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/PositionOf.java index a3c4cba..64a34ce 100644 --- a/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/PositionOf.java +++ b/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/PositionOf.java @@ -32,6 +32,7 @@ public class PositionOf extends Placeholder { @Override public String parse(Matcher matcher, OfflinePlayer p) { Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + if(!p.isOnline()) return; try { MessagedResponse response = AjQueueSpigotAPI.getInstance() .getTotalPositions(p.getUniqueId()) @@ -40,9 +41,7 @@ public class PositionOf extends Placeholder { cache.put(p.getUniqueId(), response.getEither()); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); - } catch (TimeoutException e) { - plugin.getLogger().log(Level.WARNING, "Timed out while trying to get placeholder data from proxy: ", e); - } + } catch (TimeoutException | IllegalArgumentException ignored) {} }); return cache.getOrDefault(p.getUniqueId(), "..."); diff --git a/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/Queued.java b/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/Queued.java index cf4d26a..91d895b 100644 --- a/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/Queued.java +++ b/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/Queued.java @@ -32,6 +32,7 @@ public class Queued extends Placeholder { @Override public String parse(Matcher matcher, OfflinePlayer p) { Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + if(!p.isOnline()) return; try { MessagedResponse response = AjQueueSpigotAPI.getInstance() .getQueueName(p.getUniqueId()) @@ -40,9 +41,7 @@ public class Queued extends Placeholder { cache.put(p.getUniqueId(), response.getEither()); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); - } catch (TimeoutException e) { - plugin.getLogger().log(Level.WARNING, "Timed out while trying to get placeholder data from proxy: ", e); - } + } catch (TimeoutException | IllegalArgumentException ignored) {} }); return cache.getOrDefault(p.getUniqueId(), "..."); diff --git a/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/QueuedFor.java b/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/QueuedFor.java index 13259e5..7dfb3ad 100644 --- a/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/QueuedFor.java +++ b/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/QueuedFor.java @@ -35,6 +35,7 @@ public class QueuedFor extends Placeholder { String cached = cache.getOrDefault(queue, "..."); Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + if(!p.isOnline()) return; try { Integer response = AjQueueSpigotAPI.getInstance() .getPlayersInQueue(queue) @@ -43,15 +44,13 @@ public class QueuedFor extends Placeholder { cache.put(queue, response + ""); } catch (InterruptedException e) { throw new RuntimeException(e); - } catch (TimeoutException e) { - plugin.getLogger().log(Level.WARNING, "Timed out while trying to get placeholder data from proxy: ", e); } catch (ExecutionException e) { if(e.getCause() instanceof IllegalArgumentException) { cache.put(queue, invalidMessage); } else { throw new RuntimeException(e); } - } + } catch (TimeoutException ignored) {} }); return cached; diff --git a/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/Status.java b/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/Status.java index af1848d..41575e0 100644 --- a/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/Status.java +++ b/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/Status.java @@ -35,6 +35,7 @@ public class Status extends Placeholder { String cached = cache.getOrDefault(queue, "..."); Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + if(!p.isOnline()) return; try { String response = AjQueueSpigotAPI.getInstance() .getServerStatusString(queue) @@ -43,15 +44,13 @@ public class Status extends Placeholder { cache.put(queue, response); } catch (InterruptedException e) { throw new RuntimeException(e); - } catch (TimeoutException e) { - plugin.getLogger().log(Level.WARNING, "Timed out while trying to get placeholder data from proxy: ", e); } catch (ExecutionException e) { if(e.getCause() instanceof IllegalArgumentException) { cache.put(queue, invalidMessage); } else { throw new RuntimeException(e); } - } + } catch (TimeoutException | IllegalArgumentException ignored) {} }); return cached; diff --git a/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/StatusPlayer.java b/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/StatusPlayer.java index 8fe71e0..a1a0bef 100644 --- a/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/StatusPlayer.java +++ b/spigot/src/main/java/us/ajg0702/queue/spigot/placeholders/placeholders/StatusPlayer.java @@ -35,7 +35,10 @@ public class StatusPlayer extends Placeholder { String queue = matcher.group(1); UUIDStringKey key = new UUIDStringKey(p.getUniqueId(), queue); + if(!p.isOnline()) return "You aren't online!"; + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + if(!p.isOnline()) return; try { String response = AjQueueSpigotAPI.getInstance() .getServerStatusString(queue, p.getUniqueId()) @@ -44,9 +47,7 @@ public class StatusPlayer extends Placeholder { cache.put(key, response); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); - } catch (TimeoutException e) { - plugin.getLogger().log(Level.WARNING, "Timed out while trying to get placeholder data from proxy: ", e); - } + } catch (TimeoutException | IllegalArgumentException ignored) {} }); return cache.getOrDefault(key, "...");