diff --git a/api/src/main/java/us/ajg0702/queue/api/Implementation.java b/api/src/main/java/us/ajg0702/queue/api/Implementation.java new file mode 100644 index 0000000..b24d5e6 --- /dev/null +++ b/api/src/main/java/us/ajg0702/queue/api/Implementation.java @@ -0,0 +1,11 @@ +package us.ajg0702.queue.api; + +import us.ajg0702.queue.api.commands.IBaseCommand; + +public interface Implementation { + void registerCommand(IBaseCommand command); + void unregisterCommand(String name); + default void unregisterCommand(IBaseCommand command) { + unregisterCommand(command.getName()); + } +} diff --git a/api/src/main/java/us/ajg0702/queue/api/players/AdaptedPlayer.java b/api/src/main/java/us/ajg0702/queue/api/players/AdaptedPlayer.java index 2f63a0d..5d3ad20 100644 --- a/api/src/main/java/us/ajg0702/queue/api/players/AdaptedPlayer.java +++ b/api/src/main/java/us/ajg0702/queue/api/players/AdaptedPlayer.java @@ -79,4 +79,8 @@ public interface AdaptedPlayer extends Handle, Audience { String getName(); List getPermissions(); + + default boolean equals(AdaptedPlayer other) { + return this.getUniqueId().equals(other.getUniqueId()); + } } diff --git a/api/src/main/java/us/ajg0702/queue/api/premium/PermissionGetter.java b/api/src/main/java/us/ajg0702/queue/api/premium/PermissionGetter.java index d050a44..8960206 100644 --- a/api/src/main/java/us/ajg0702/queue/api/premium/PermissionGetter.java +++ b/api/src/main/java/us/ajg0702/queue/api/premium/PermissionGetter.java @@ -11,4 +11,6 @@ public interface PermissionGetter { int getPriority(AdaptedPlayer player); int getServerPriotity(String server, AdaptedPlayer player); + + boolean hasContextBypass(AdaptedPlayer player, String server); } diff --git a/build.gradle.kts b/build.gradle.kts index 7536864..b418adf 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,7 +12,7 @@ repositories { } allprojects { - version = "2.0.8" + version = "2.0.9" 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 new file mode 100644 index 0000000..c625e80 --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/SlashServer/SlashServerCommand.java @@ -0,0 +1,55 @@ +package us.ajg0702.queue.commands.commands.SlashServer; + +import com.google.common.collect.ImmutableList; +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.List; +import java.util.Locale; + +public class SlashServerCommand extends BaseCommand { + + final QueueMain main; + final String server; + public SlashServerCommand(QueueMain main, String server) { + this.main = main; + this.server = server; + } + + @Override + public String getName() { + return server; + } + + @Override + public ImmutableList getAliases() { + return ImmutableList.of(); + } + + @Override + public String getPermission() { + return null; + } + + @Override + public Messages getMessages() { + return main.getMessages(); + } + + @Override + public void execute(ICommandSender sender, String[] args) { + if(!sender.isPlayer()) { + sender.sendMessage(getMessages().getComponent("errors.player-only")); + return; + } + main.getQueueManager().addToQueue(main.getPlatformMethods().senderToPlayer(sender), server); + } + + @Override + public List autoComplete(ICommandSender sender, String[] args) { + return new ArrayList<>(); + } +} 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 05e28c0..92205b7 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 @@ -51,7 +51,7 @@ public class Pause extends SubCommand { List servers; QueueServer queueServer = main.getQueueManager().findServer(args[0]); if(queueServer == null && !args[0].equalsIgnoreCase("all")) { - sender.sendMessage(getMessages().getComponent("commands.pause.no-server", "SERVER:"+args[1])); + sender.sendMessage(getMessages().getComponent("commands.pause.no-server", "SERVER:"+args[0])); return; } else if(queueServer == null && args[0].equalsIgnoreCase("all")) { servers = main.getQueueManager().getServers(); 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 90c8bc7..c45b0aa 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 @@ -54,6 +54,7 @@ public class Reload extends SubCommand { main.getTaskManager().rescheduleTasks(); main.getQueueManager().reloadServers(); main.getMessages().reload(); + main.getSlashServerManager().reload(); main.getUpdater().setEnabled(main.getConfig().getBoolean("enable-updater")); 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 dc4c1af..576d3c2 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 @@ -43,8 +43,13 @@ public class Send extends SubCommand { public void execute(ICommandSender sender, String[] args) { if(!checkPermission(sender)) return; + if(args.length < 2) { + sender.sendMessage(getMessages().getComponent("commands.send.usage")); + return; + } + if(main.getQueueManager().findServer(args[1]) == null) { - sender.sendMessage(getMessages().getComponent("errors.server-not-exist", "SERVER:"+args[2])); + sender.sendMessage(getMessages().getComponent("errors.server-not-exist", "SERVER:"+args[1])); return; } @@ -53,7 +58,7 @@ public class Send extends SubCommand { AdaptedPlayer ply = main.getPlatformMethods().getPlayer(args[0]); if(ply == null) { - sender.sendMessage(Component.text("player not found")); + sender.sendMessage(Component.text("player not found (even though it was in playerNames)")); return; } if(ply.getName() == null) { 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 2e94c11..d73b691 100644 --- a/common/src/main/java/us/ajg0702/queue/common/QueueMain.java +++ b/common/src/main/java/us/ajg0702/queue/common/QueueMain.java @@ -107,6 +107,16 @@ public class QueueMain extends AjQueueAPI { return updater; } + private final Implementation implementation; + public Implementation getImplementation() { + return implementation; + } + + private SlashServerManager slashServerManager; + public SlashServerManager getSlashServerManager() { + return slashServerManager; + } + @Override public void shutdown() { taskManager.shutdown(); @@ -117,7 +127,8 @@ public class QueueMain extends AjQueueAPI { private final File dataFolder; - public QueueMain(QueueLogger logger, PlatformMethods platformMethods, File dataFolder) { + public QueueMain(Implementation implementation, QueueLogger logger, PlatformMethods platformMethods, File dataFolder) { + this.implementation = implementation; logicGetter = new LogicGetterImpl(); @@ -147,6 +158,8 @@ public class QueueMain extends AjQueueAPI { return; } + slashServerManager = new SlashServerManager(this); + //noinspection ResultOfMethodCallIgnored messages.getComponent("one").replaceText(b -> b.match(Pattern.compile("\\e")).replacement("a")); @@ -232,6 +245,7 @@ public class QueueMain extends AjQueueAPI { d.put("commands.pause.paused.false", "&aun-paused"); d.put("commands.send.player-not-found", "&cThat player could not be found. Make sure they are online!"); + d.put("commands.send.usage", "Usage: /ajqueue send "); d.put("commands.listqueues.header", "&9Queues:"); d.put("commands.listqueues.format", "{COLOR}{NAME}&7: {COUNT} queued"); 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 15ee6af..703105e 100644 --- a/common/src/main/java/us/ajg0702/queue/common/QueueManagerImpl.java +++ b/common/src/main/java/us/ajg0702/queue/common/QueueManagerImpl.java @@ -14,18 +14,12 @@ import us.ajg0702.utils.common.Messages; import us.ajg0702.utils.common.TimeUtils; import java.time.Duration; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; +import java.util.*; +import java.util.concurrent.*; public class QueueManagerImpl implements QueueManager { - private List servers = new CopyOnWriteArrayList<>(); + private CopyOnWriteArrayList servers = new CopyOnWriteArrayList<>(); private final QueueMain main; private final Messages msgs; @@ -272,7 +266,7 @@ public class QueueManagerImpl implements QueueManager { List oldServers = ImmutableList.copyOf(servers); - servers = buildServers(); + servers = new CopyOnWriteArrayList<>(buildServers()); List groupsRaw = main.getConfig().getStringList("server-groups"); for(String groupRaw : groupsRaw) { @@ -506,7 +500,8 @@ public class QueueManagerImpl implements QueueManager { sendPlayers(null); } - final HashMap sendingNowAntiSpam = new HashMap<>(); + + final ConcurrentHashMap sendingNowAntiSpam = new ConcurrentHashMap<>(); final HashMap sendingAttempts = new HashMap<>(); @Override @@ -640,6 +635,9 @@ public class QueueManagerImpl implements QueueManager { @Override public void clear(AdaptedPlayer player) { - sendingNowAntiSpam.remove(player); + for (AdaptedPlayer next : sendingNowAntiSpam.keySet()) { + if(!next.equals(player)) continue; + sendingNowAntiSpam.remove(next); + } } } diff --git a/common/src/main/java/us/ajg0702/queue/common/SlashServerManager.java b/common/src/main/java/us/ajg0702/queue/common/SlashServerManager.java new file mode 100644 index 0000000..584e92a --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/common/SlashServerManager.java @@ -0,0 +1,31 @@ +package us.ajg0702.queue.common; + +import us.ajg0702.queue.api.Implementation; +import us.ajg0702.queue.commands.commands.SlashServer.SlashServerCommand; + +import java.util.ArrayList; +import java.util.List; + +public class SlashServerManager { + + private final List serverCommands = new ArrayList<>(); + + private final QueueMain main; + private final Implementation implementation; + public SlashServerManager(QueueMain main) { + this.main = main; + this.implementation = this.main.getImplementation(); + reload(); + } + public void reload() { + serverCommands.forEach(implementation::unregisterCommand); + serverCommands.clear(); + + List slashServerServers = main.getConfig().getStringList("slash-servers"); + for(String server : slashServerServers) { + SlashServerCommand command = new SlashServerCommand(main, server); + serverCommands.add(command); + implementation.registerCommand(command); + } + } +} 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 23fd963..0047a6c 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 @@ -130,9 +130,10 @@ public class QueueServerImpl implements QueueServer { @Override public void updatePing() { + boolean pingerDebug = main.getConfig().getBoolean("pinger-debug"); HashMap> pingsFutures = new HashMap<>(); for(AdaptedServer server : servers) { - if(main.getConfig().getBoolean("pinger-debug")) { + if(pingerDebug) { main.getLogger().info("[pinger] ["+server.getServerInfo().getName()+"] sending ping"); } pingsFutures.put(server, server.ping()); @@ -145,13 +146,15 @@ public class QueueServerImpl implements QueueServer { try { ping = futurePing.get(5, TimeUnit.SECONDS); } catch (InterruptedException | ExecutionException | TimeoutException e) { - if(main.getConfig().getBoolean("pinger-debug")) { + if(pingerDebug) { main.getLogger().info("[pinger] ["+server.getServerInfo().getName()+"] offline:"); e.printStackTrace(); } } - if(ping != null && main.getConfig().getBoolean("pinger-debug")) { + if(ping != null && pingerDebug) { main.getLogger().info("[pinger] ["+server.getServerInfo().getName()+"] online. motd: "+ping.getPlainDescription()+" players: "+ping.getPlayerCount()+"/"+ping.getMaxPlayers()); + } else if(ping == null && pingerDebug) { + main.getLogger().info("[pinger] ["+server.getServerInfo().getName()+"] offline (unknown)"); } pings.put(server, ping); @@ -207,6 +210,10 @@ public class QueueServerImpl implements QueueServer { } } } + + if(pingerDebug) { + main.getLogger().info("[pinger] ["+server.getServerInfo().getName()+"] Success"); + } } } diff --git a/common/src/main/resources/config.yml b/common/src/main/resources/config.yml index bc75f67..7ddcf6b 100644 --- a/common/src/main/resources/config.yml +++ b/common/src/main/resources/config.yml @@ -1,5 +1,5 @@ # Dont touch this number please -config-version: 28 +config-version: 29 # This is the main config for ajQueue. @@ -261,4 +261,10 @@ protocol-names: velocity-kick-message: false # Should the updater be enabled? -enable-updater: true \ No newline at end of file +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 +slash-servers: [] \ No newline at end of file diff --git a/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/BungeeQueue.java b/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/BungeeQueue.java index 7675a92..469a0f0 100644 --- a/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/BungeeQueue.java +++ b/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/BungeeQueue.java @@ -11,6 +11,7 @@ import net.md_5.bungee.event.EventHandler; import org.bstats.bungeecord.Metrics; import org.bstats.charts.SimplePie; import org.checkerframework.checker.nullness.qual.NonNull; +import us.ajg0702.queue.api.Implementation; import us.ajg0702.queue.api.commands.IBaseCommand; import us.ajg0702.queue.api.util.QueueLogger; import us.ajg0702.queue.commands.BaseCommand; @@ -25,14 +26,18 @@ import us.ajg0702.queue.platforms.bungeecord.server.BungeeServer; import java.io.File; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; -public class BungeeQueue extends Plugin implements Listener { +public class BungeeQueue extends Plugin implements Listener, Implementation { private QueueMain main; List commands; + Map commandMap; + @Override public void onEnable() { QueueLogger logger = new BungeeLogger(getLogger()); @@ -41,6 +46,7 @@ public class BungeeQueue extends Plugin implements Listener { adventure = BungeeAudiences.create(this); main = new QueueMain( + this, logger, new BungeeMethods(this, getProxy(), logger), dataFolder @@ -56,9 +62,10 @@ public class BungeeQueue extends Plugin implements Listener { new ManageCommand(main) ); + commandMap = new HashMap<>(); + for(IBaseCommand command : commands) { - getProxy().getPluginManager() - .registerCommand(this, new BungeeCommand((BaseCommand) command)); + registerCommand(command); } getProxy().getPluginManager().registerListener(this, this); @@ -129,4 +136,20 @@ public class BungeeQueue extends Plugin implements Listener { false ); } + + @Override + public void unregisterCommand(String name) { + BungeeCommand bungeeCommand = commandMap.get(name); + if(bungeeCommand == null) return; + getProxy().getPluginManager().unregisterCommand(bungeeCommand); + commandMap.remove(name); + } + + @Override + public void registerCommand(IBaseCommand command) { + BungeeCommand bungeeCommand = new BungeeCommand((BaseCommand) command); + commandMap.put(command.getName(), bungeeCommand); + getProxy().getPluginManager() + .registerCommand(this, bungeeCommand); + } } diff --git a/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/VelocityQueue.java b/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/VelocityQueue.java index b1b1696..55717c6 100644 --- a/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/VelocityQueue.java +++ b/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/VelocityQueue.java @@ -18,6 +18,7 @@ import net.kyori.adventure.text.Component; import org.bstats.charts.SimplePie; import org.bstats.velocity.Metrics; import org.slf4j.Logger; +import us.ajg0702.queue.api.Implementation; import us.ajg0702.queue.api.commands.IBaseCommand; import us.ajg0702.queue.commands.BaseCommand; import us.ajg0702.queue.commands.commands.leavequeue.LeaveCommand; @@ -44,7 +45,7 @@ import java.util.Optional; authors = {"ajgeiss0702"} ) -public class VelocityQueue { +public class VelocityQueue implements Implementation { final ProxyServer proxyServer; final VelocityLogger logger; @@ -66,9 +67,15 @@ public class VelocityQueue { List commands; + CommandManager commandManager; + @Subscribe public void onProxyInit(ProxyInitializeEvent e) { + + commandManager = proxyServer.getCommandManager(); + main = new QueueMain( + this, logger, new VelocityMethods(this, proxyServer, logger), dataFolder @@ -81,20 +88,13 @@ public class VelocityQueue { new ManageCommand(main) ); - CommandManager commandManager = proxyServer.getCommandManager(); - proxyServer.getChannelRegistrar().register(MinecraftChannelIdentifier.create("ajqueue", "tospigot")); proxyServer.getChannelRegistrar().register(MinecraftChannelIdentifier.from("ajqueue:toproxy")); for(IBaseCommand command : commands) { - commandManager.register( - commandManager.metaBuilder(command.getName()) - .aliases(command.getAliases().toArray(new String[]{})) - .build(), - new VelocityCommand(main, (BaseCommand) command) - ); + registerCommand(command); } @@ -138,7 +138,6 @@ public class VelocityQueue { main.getEventHandler().onPlayerLeave(new VelocityPlayer(e.getPlayer())); } - @SuppressWarnings("SimplifyOptionalCallChains") @Subscribe public void onKick(KickedFromServerEvent e) { if(!e.getPlayer().getCurrentServer().isPresent()) return; // if the player is kicked on initial join, we dont care @@ -152,4 +151,18 @@ public class VelocityQueue { ); } + @Override + public void unregisterCommand(String name) { + commandManager.unregister(name); + } + + @Override + public void registerCommand(IBaseCommand command) { + commandManager.register( + commandManager.metaBuilder(command.getName()) + .aliases(command.getAliases().toArray(new String[]{})) + .build(), + new VelocityCommand(main, (BaseCommand) command) + ); + } } 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 a9bcc87..eb1c545 100644 --- a/premium/src/main/java/us/ajg0702/queue/logic/PremiumLogic.java +++ b/premium/src/main/java/us/ajg0702/queue/logic/PremiumLogic.java @@ -36,7 +36,11 @@ public class PremiumLogic implements Logic { QueueLogger logger = main.getLogger(); boolean debug = main.getConfig().getBoolean("priority-queue-debug"); - if(player.hasPermission("ajqueue.bypass") || player.hasPermission("ajqueue.serverbypass."+server.getName())) { + if( + player.hasPermission("ajqueue.bypass") || + player.hasPermission("ajqueue.serverbypass."+server.getName()) || + permissionGetter.hasContextBypass(player, server.getName()) + ) { if(debug) { logger.info("[priority] "+player.getName()+" bypass"); } 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 6ca9d1a..c2b02d2 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 @@ -60,6 +60,15 @@ public class PermissionGetterImpl implements PermissionGetter { return getHighestPermission(player, "ajqueue.serverpriority."+server+"."); } + @Override + public boolean hasContextBypass(AdaptedPlayer player, String server) { + if(getSelected() == null) { + return false; + } + List perms = getSelected().getPermissions(player); + return perms.contains("ajqueue.serverbypass."+server); + } + private int getHighestPermission(AdaptedPlayer player, String prefix) { if(getSelected() == null) { return -1; diff --git a/premium/src/main/java/us/ajg0702/queue/logic/permissions/hooks/LuckPermsHook.java b/premium/src/main/java/us/ajg0702/queue/logic/permissions/hooks/LuckPermsHook.java index ed892ce..ed7401b 100644 --- a/premium/src/main/java/us/ajg0702/queue/logic/permissions/hooks/LuckPermsHook.java +++ b/premium/src/main/java/us/ajg0702/queue/logic/permissions/hooks/LuckPermsHook.java @@ -2,9 +2,11 @@ package us.ajg0702.queue.logic.permissions.hooks; import net.luckperms.api.LuckPerms; import net.luckperms.api.LuckPermsProvider; +import net.luckperms.api.context.Context; import net.luckperms.api.model.user.User; import net.luckperms.api.node.Node; import net.luckperms.api.node.NodeType; +import net.luckperms.api.query.QueryMode; import net.luckperms.api.query.QueryOptions; import us.ajg0702.queue.api.players.AdaptedPlayer; import us.ajg0702.queue.common.QueueMain; @@ -43,7 +45,40 @@ public class LuckPermsHook implements PermissionHook { for (Node node : nodes) { if (!node.getType().equals(NodeType.PERMISSION)) continue; if (!node.getValue()) continue; - perms.add(node.getKey()); + String permission = node.getKey(); + + + if(permission.equalsIgnoreCase("ajqueue.contextbypass")) { + boolean skip = false; + for(Context context : node.getContexts()) { + if(context.getKey().equalsIgnoreCase("server")) { + skip = true; + perms.add("ajqueue.serverbypass."+context.getValue()); + } + } + if(skip) continue; + } + + if(permission.toLowerCase(Locale.ROOT).startsWith("ajqueue.contextpriority.")) { + boolean skip = false; + int level; + try { + level = Integer.parseInt(permission.substring(0, 24)); + } catch(NumberFormatException e) { + main.getLogger().warning("A non-number is in the priority permission "+permission); + continue; + } + for(Context context : node.getContexts()) { + if(context.getKey().equalsIgnoreCase("server")) { + skip = true; + perms.add("ajqueue.serverpriority."+context.getValue()+"."+level); + } + } + if(skip) continue; + } + + + perms.add(permission); } return perms;