diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 75be208..10b331c 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -10,7 +10,7 @@ repositories { } dependencies { - compileOnly("net.kyori:adventure-api:4.8.1") + implementation("net.kyori:adventure-api:4.8.1") compileOnly("com.google.guava:guava:30.1.1-jre") } diff --git a/api/src/main/java/us/ajg0702/queue/api/Logic.java b/api/src/main/java/us/ajg0702/queue/api/Logic.java index aea8b29..6019d67 100644 --- a/api/src/main/java/us/ajg0702/queue/api/Logic.java +++ b/api/src/main/java/us/ajg0702/queue/api/Logic.java @@ -2,6 +2,7 @@ package us.ajg0702.queue.api; 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; @@ -18,5 +19,5 @@ public interface Logic { * @param server The server/group name that is being queued for * @param player The player that is being queued */ - void priorityLogic(List list, String server, AdaptedPlayer player); + QueuePlayer priorityLogic(QueueServer server, AdaptedPlayer player); } diff --git a/api/src/main/java/us/ajg0702/queue/api/QueueManager.java b/api/src/main/java/us/ajg0702/queue/api/QueueManager.java index 324b640..a54f73d 100644 --- a/api/src/main/java/us/ajg0702/queue/api/QueueManager.java +++ b/api/src/main/java/us/ajg0702/queue/api/QueueManager.java @@ -2,6 +2,7 @@ package us.ajg0702.queue.api; 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.queues.QueueServer; public interface QueueManager { @@ -56,4 +57,57 @@ public interface QueueManager { * Also creates/edits server groups */ void reloadServers(); + + /** + * Sends queue status action bars to players in queues + */ + void sendActionBars(); + + /** + * Tell the spigot sides to call the queue scoreboard event + */ + void sendQueueEvents(); + + /** + * Sends chat queue status messages to players in queues + */ + void sendMessages(); + + /** + * Send a chat queue status message to a specific player in a specific queue + * @param player The player that is in the queue + */ + void sendMessage(QueuePlayer player); + + /** + * Find a server by its name + * @param name The name to look for + * @return The QueueServer if found, null if not + */ + QueueServer findServer(String name); + + /** + * Attempts to send the first player in all queues to the server they are queued for + */ + void sendPlayers(); + + /** + * Attempts to send the first player in a specific queue + * @param server The queue that we should try to send. + */ + void sendPlayers(QueueServer server); + + /** + * Finds QueuePlayers that represent this player + * @param p The player to look up + * @return A list of QueuePlayers that represent this player + */ + ImmutableList findPlayerInQueues(AdaptedPlayer p); + + /** + * Gets all of the queues the player is currently queued for + * @param p The player + * @return A list of QueueServers that this player is queued for + */ + ImmutableList getPlayerQueues(AdaptedPlayer p); } 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 0b5b50a..c4e87ec 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 @@ -3,11 +3,19 @@ package us.ajg0702.queue.api.players; import net.kyori.adventure.text.Component; import us.ajg0702.queue.api.util.Handle; +import java.util.UUID; + /** * Represents a cross-platform player */ public interface AdaptedPlayer extends Handle { + /** + * Check if the plauer is currently connected + * @return True if connected, false if not + */ + boolean isConnected(); + /** * Send a player a message from a Component * @param message The message to send @@ -20,4 +28,23 @@ public interface AdaptedPlayer extends Handle { * @param message The message to send */ void sendMessage(String message); + + /** + * Checks if the player has a certain permission + * @param permission The permission to check + * @return True if they have the permission, false if not + */ + boolean hasPermission(String permission); + + /** + * Gets the name of the server the player is currently on + * @return The name of the server + */ + String getServerName(); + + /** + * Gets the player's unique id (UUID) + * @return The player's uuid + */ + UUID getUniqueId(); } 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 1c73a6c..41aafae 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,19 +1,53 @@ package us.ajg0702.queue.api.players; +import us.ajg0702.queue.api.queues.QueueServer; + import javax.annotation.Nullable; import java.util.UUID; public interface QueuePlayer { + /** * Returns the player's UUID * @return the player's UUID */ UUID getUniqueId(); + /** + * Gets the server or group this player is queued for + * @return The QueueServer this player is queued for + */ + QueueServer getQueueServer(); + + /** + * Gets the player's position in the queue + * @return The player's position. 1 being 1st, 2 being 2nd, etc + */ + int getPosition(); + /** * Get the player this represents. * Can be null because the player could not be online * @return The player if they are online, null otherwise */ @Nullable AdaptedPlayer getPlayer(); + + /** + * Sets the player that this represents. + * Will throw IllegalArgumentException if the player's uuid does not match the original. + * @param player The player to add + */ + void setPlayer(AdaptedPlayer player); + + /** + * Gets the highest priority level the player has. + * In free ajQueue, no priority is 0 and priority is 1 + * @return The priority level of this player for this server + */ + int getPriority(); + + /** + * Gets if this player has priority + */ + boolean hasPriority(); } 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 43bfdcc..f984cbf 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 @@ -117,12 +117,52 @@ public interface QueueServer { void removePlayer(QueuePlayer player); /** - * Adds a player to a queue + * Removes a player from the queue + * @param player The player to remove + */ + void removePlayer(AdaptedPlayer player); + + /** + * Adds a player to the end of the queue * NOTE: It is reccomended to use QueueManager#addToQueue - * @param player The QueuePlayer that is being added + * @param player The QueuePlayer t add */ void addPlayer(QueuePlayer player); + /** + * Adds a player to the specified position in the queue + * NOTE: It is reccomended to use QueueManager#addToQueue + * @param player The QueuePlayer to add + * @param position The position to add them + */ + void addPlayer(QueuePlayer player, int position); + + /** + * Sends the first player in the queue to the server + */ + void sendPlayer(); + + /** + * Gets the name of the server/group + * @return The name of the server/group + */ + String getName(); + + + /** + * If the player can access the server. (Bungeecord's restricted servers) + * If on a platform that doesnt have restricted servers, this will always return true. + * @param ply The player + * @return True if the player can join based on bungeecord's restricted servers system + */ + boolean canAccess(AdaptedPlayer ply); + + /** + * The alias of this server. For displaying. + * @return The alias of this server + */ + String getAlias(); + diff --git a/build.gradle.kts b/build.gradle.kts index 58aab0f..57fe8bd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -37,11 +37,7 @@ repositories { dependencies { testImplementation("junit:junit:4.12") - compileOnly("me.clip:placeholderapi:2.10.4") - compileOnly("net.kyori:adventure-text-serializer-bungeecord:4.0.0-SNAPSHOT") - - implementation("us.ajg0702:ajUtils:1.0.4") - implementation("net.kyori:adventure-text-serializer-plain:4.0.0-SNAPSHOT") + implementation(project(":common")) } @@ -58,6 +54,7 @@ tasks.shadowJar { relocate("us.ajg0702.utils", "us.ajg0702.queue.utils") relocate("org.bstats", "us.ajg0702.bstats") relocate("net.kyori", "us.ajg0702.queue.kyori") + relocate("org.spongepowered.configurate", "us.ajg0702.queue.configurate") archiveFileName.set("${archiveBaseName.get()}-${archiveVersion.get()}.${archiveExtension.get()}") } diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 8400e02..6f89f31 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -7,11 +7,13 @@ group = "us.ajg0702.queue.api" repositories { mavenCentral() + maven { url = uri("https://repo.ajg0702.us") } } dependencies { compileOnly("net.kyori:adventure-api:4.8.1") compileOnly("com.google.guava:guava:30.1.1-jre") + compileOnly("us.ajg0702:ajUtils:1.1.4") implementation(project(":api")) } diff --git a/common/src/main/java/us/ajg0702/queue/common/PlatformMethods.java b/common/src/main/java/us/ajg0702/queue/common/PlatformMethods.java new file mode 100644 index 0000000..76733ac --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/common/PlatformMethods.java @@ -0,0 +1,13 @@ +package us.ajg0702.queue.common; + +public interface PlatformMethods { + /** + * BungeeUtils.sendCustomData(p, "position", pos+""); + * BungeeUtils.sendCustomData(p, "positionof", len+""); + * BungeeUtils.sendCustomData(p, "queuename", pl.aliases.getAlias(s)); + * BungeeUtils.sendCustomData(p, "inqueue", "true"); + * BungeeUtils.sendCustomData(p, "inqueueevent", "true"); + */ + void sendJoinQueueChannelMessages(); + +} diff --git a/common/src/main/java/us/ajg0702/queue/common/QueueMain.java b/common/src/main/java/us/ajg0702/queue/common/QueueMain.java new file mode 100644 index 0000000..a273be9 --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/common/QueueMain.java @@ -0,0 +1,49 @@ +package us.ajg0702.queue.common; + +import us.ajg0702.queue.api.AliasManager; +import us.ajg0702.queue.api.Logic; +import us.ajg0702.utils.common.Config; +import us.ajg0702.utils.common.Messages; + +import java.util.logging.Logger; + +public class QueueMain { + private Config config; + public Config getConfig() { + return config; + } + + private Messages messages; + public Messages getMessages() { + return messages; + } + + private AliasManager aliasManager; + public AliasManager getAliasManager() { + return aliasManager; + } + + private Logic logic; + public Logic getLogic() { + return logic; + } + + public boolean isPremium() { + return getLogic().isPremium(); + } + + private PlatformMethods platformMethods; + public PlatformMethods getPlatformMethods() { + return platformMethods; + } + + private Logger logger; + public Logger getLogger() { + return logger; + } + + private ServerBuilder serverBuilder; + public ServerBuilder getServerBuilder() { + return serverBuilder; + } +} 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 a721102..78d9d46 100644 --- a/common/src/main/java/us/ajg0702/queue/common/QueueManagerImpl.java +++ b/common/src/main/java/us/ajg0702/queue/common/QueueManagerImpl.java @@ -3,26 +3,247 @@ package us.ajg0702.queue.common; import com.google.common.collect.ImmutableList; import us.ajg0702.queue.api.QueueManager; 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.common.players.QueuePlayerImpl; +import us.ajg0702.utils.bungee.BungeeUtils; +import us.ajg0702.utils.common.Messages; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; public class QueueManagerImpl implements QueueManager { + + private List servers; + + private final QueueMain main; + private final Messages msgs; + + public QueueManagerImpl(QueueMain main) { + this.main = main; + this.msgs = main.getMessages(); + } + @Override public boolean addToQueue(AdaptedPlayer player, QueueServer server) { - return false; + if(player == null || server == null) { + return false; + } + if(!player.isConnected()) return false; + + if(main.getConfig().getBoolean("joinfrom-server-permission") && !player.hasPermission("ajqueue.joinfrom."+player.getServerName())) { + player.sendMessage(msgs.getComponent("errors.deny-joining-from-server")); + return false; + } + + if(server.isPaused() && main.getConfig().getBoolean("prevent-joining-paused")) { + player.sendMessage(msgs.getComponent("errors.cant-join-paused", "SERVER:"+server.getAlias())); + return false; + } + + if(player.getServerName().equals(server.getName())) { + player.sendMessage(msgs.getComponent("errors.already-connected", "SERVER:"+server.getAlias())); + return false; + } + + ImmutableList beforeQueues = getPlayerQueues(player); + if(beforeQueues.size() > 0) { + if(beforeQueues.contains(server)) { + player.sendMessage(msgs.getComponent("errors.already-queued")); + return false; + } + if(!main.getConfig().getBoolean("allow-multiple-queues")) { + player.sendMessage(msgs.getComponent("status.left-last-queue", "SERVER:"+server.getAlias())); + for(QueueServer ser : beforeQueues) { + ser.removePlayer(player); + } + } + } + + ImmutableList list = server.getQueue(); + QueuePlayer queuePlayer; + if(main.isPremium()) { + queuePlayer = main.getLogic().priorityLogic(server, player); + } else { + int priority = player.hasPermission("ajqueue.priority") || + player.hasPermission("ajqueue.serverpriority."+server.getName()) ? 1 : 0; + queuePlayer = new QueuePlayerImpl(player, server, priority); + if( + priority == 1 && + server.getQueue().size() > 0 + ) { + int i = 0; + for(QueuePlayer ply : list) { + if(!ply.hasPriority()) { + server.addPlayer(queuePlayer, i); + break; + } + i++; + } + } + + if(!list.contains(queuePlayer)) { + server.addPlayer(queuePlayer); + } + } + + list = server.getQueue(); + + int pos = queuePlayer.getPosition(); + int len = list.size(); + + boolean sendInstant = main.getConfig().getStringList("send-instantly").contains(server.getName()) || server.isJoinable(p); + boolean sendInstantp = list.size() <= 1 && server.canAccess(player); + boolean timeGood = !main.getConfig().getBoolean("check-last-player-sent-time") || System.currentTimeMillis() - server.getLastSentTime() > Math.floor(main.getConfig().getDouble("wait-time") * 1000); + + if((sendInstant && (sendInstantp && timeGood))) { + sendPlayers(server); + if(!msgs.isEmpty("status.now-in-empty-queue")) { + player.sendMessage(msgs.getComponent("status.now-in-empty-queue", + "POS:"+pos, + "LEN:"+len, + "SERVER:"+server.getAlias())); + } + } else { + player.sendMessage(msgs.getComponent("status.now-in-queue", + "POS:"+pos, + "LEN:"+len, + "SERVER:"+server.getAlias(), + "SERVERNAME:"+server.getName() + )); + } + + main.getPlatformMethods().sendJoinQueueChannelMessages(); + return true; } @Override public boolean addToQueue(AdaptedPlayer player, String serverName) { - return false; + QueueServer server = findServer(serverName); + if(server == null) return false; + return addToQueue(player, server); } @Override public ImmutableList getServers() { - return null; + return ImmutableList.copyOf(servers); } @Override public ImmutableList getServerNames() { + List names = new ArrayList<>(); + for(QueueServer s : servers) { + names.add(s.getName()); + } + return ImmutableList.copyOf(names); + } + + @Override + public QueueServer getSingleServer(AdaptedPlayer player) { + ImmutableList queued = findPlayerInQueues(player); + if(queued.size() <= 0) { + return null; + } + QueueServer selected = queued.get(0).getQueueServer(); + + if(main.getConfig().getString("multi-server-queue-pick").equalsIgnoreCase("last")) { + selected = queued.get(queued.size()-1).getQueueServer(); + } + return selected; + } + + @Override + public String getQueuedName(AdaptedPlayer player) { + return getSingleServer(player).getName(); + } + + @Override + public void reloadServers() { + if(main.getConfig() == null) { + main.getLogger().severe("[MAN] Config is null"); + } + + servers.clear(); + + servers.addAll(main.getServerBuilder().getServers()); + + List groupsraw = main.getConfig().getStringList("server-groups"); + for(String groupraw : groupsraw) { + if(groupraw.isEmpty()) { + main.getLogger().warning("Empty group string! If you dont want server groups, set server-groups like this: server-groups: []"); + continue; + } + + String groupname = groupraw.split(":")[0]; + String[] serversraw = groupraw.split(":")[1].split(","); + + if(findServer(groupname) != null) { + main.getLogger().warning("The name of a group ('"+groupname+"') cannot be the same as the name of a server!"); + continue; + } + + + for(String serverraw : serversraw) { + ServerInfo si = svs.get(serverraw); + if(si == null) { + pl.getLogger().warning("Could not find server named '"+serverraw+"' in servergroup '"+groupname+"'!"); + continue; + } + servers.add(si); + } + + if(servers.size() == 0) { + pl.getLogger().warning("Server group '"+groupname+"' has no servers! Ignoring it."); + continue; + } + + this.servers.add(new QueueServer(groupname, servers)); + } + } + + @Override + public void sendActionBars() { + + } + + @Override + public void sendQueueEvents() { + + } + + @Override + public void sendMessages() { + + } + + @Override + public void sendMessage(QueuePlayer player) { + + } + + @Override + public QueueServer findServer(String name) { + return null; + } + + @Override + public void sendPlayers() { + + } + + @Override + public void sendPlayers(QueueServer server) { + + } + + @Override + public ImmutableList findPlayerInQueues(AdaptedPlayer p) { + return null; + } + + @Override + public ImmutableList getPlayerQueues(AdaptedPlayer p) { return null; } } diff --git a/common/src/main/java/us/ajg0702/queue/common/ServerBuilder.java b/common/src/main/java/us/ajg0702/queue/common/ServerBuilder.java new file mode 100644 index 0000000..bfc03dd --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/common/ServerBuilder.java @@ -0,0 +1,9 @@ +package us.ajg0702.queue.common; + +import us.ajg0702.queue.api.queues.QueueServer; + +import java.util.List; + +public interface ServerBuilder { + List getServers(); +} 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 new file mode 100644 index 0000000..523a623 --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/common/players/QueuePlayerImpl.java @@ -0,0 +1,68 @@ +package us.ajg0702.queue.common.players; + +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 java.util.UUID; + +public class QueuePlayerImpl implements QueuePlayer { + + + private AdaptedPlayer player; + private final QueueServer server; + + private final int highestPriority; + + private final UUID uuid; + + public QueuePlayerImpl(AdaptedPlayer player, QueueServer server, int highestPriority) { + this.player = player; + this.server = server; + + this.highestPriority = highestPriority; + + uuid = player.getUniqueId(); + } + + @Override + public UUID getUniqueId() { + return uuid; + } + + @Override + public QueueServer getQueueServer() { + return server; + } + + @Override + public int getPosition() { + return getQueueServer().getQueue().indexOf(this)+1; + } + + @Nullable + @Override + public AdaptedPlayer getPlayer() { + if(!player.isConnected()) return null; + return player; + } + + @Override + public void setPlayer(AdaptedPlayer player) { + if(!player.getUniqueId().equals(getUniqueId())) { + throw new IllegalArgumentException("UUIDs do not match"); + } + this.player = player; + } + + @Override + public int getPriority() { + return highestPriority; + } + + @Override + public boolean hasPriority() { + return highestPriority > 0; + } +}