diff --git a/.gitignore b/.gitignore index 4c72aca..915ff76 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ dependency-reduced-pom.xml .gradle build .DS_Store -.nosync \ No newline at end of file +.nosync +libs/**.* diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 82467c6..5474105 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,10 +12,10 @@ build: stage: build script: - rm -rf build - - ./gradlew shadowJar + - gradle :free:shadowJar artifacts: paths: - - build/libs + - free/build/libs pages: stage: build @@ -23,8 +23,8 @@ pages: only: - master script: - - ./gradlew javadoc - - mv build/docs/javadoc public + - gradle :api:javadoc + - mv api/build/docs/javadoc public artifacts: paths: - public @@ -34,7 +34,7 @@ test: dependencies: - build script: - - ./gradlew test + - gradle test deploy to maven repo: stage: deploy @@ -43,7 +43,7 @@ deploy to maven repo: dependencies: - build script: - - ./gradlew publish --stacktrace + - gradle :api:publish --stacktrace upload to updater: stage: deploy @@ -52,6 +52,6 @@ upload to updater: dependencies: - build script: - - cd build/libs + - cd free/build/libs - files=(*) - curl -i -F "submit=true" -F "secret=$UPLOAD_SECRET" -F "file=@${files[0]}" https://ajg0702.us/pl/updater/upload.php diff --git a/README.md b/README.md index 2ecd4f2..ca3914c 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,15 @@ # ajQueue -ajQueue is (as far as I can tell) the best queue plugin out there (even better than queue plugins that cost $10, and ajQueue is free :D). -This is the source code for ajQueue. If you make changes, open a merge request and ill probably approve it, as long as its not dumb :p +[Wiki](https://wiki.ajg0702.us/ajqueue/) | +[Spigot (free)](https://www.spigotmc.org/resources/ajqueue.78266/) | +[Spigot (premium)](https://www.spigotmc.org/resources/ajqueueplus.79123/) -## My dumb code -If you say my code is ugly, fix it and open a merge reguest before making fun of it ;) +ajQueue is (as far as I can tell) the best queue plugin out there. +It was made because I wasn't satisfied with the existing queue plugins, all of them either being massively overpriced, +or lacking basic features -## ajQueuePlus -The source code for ajQueuePlus will probably stay private. \ No newline at end of file +# Contributing +As long as you don't break anything, i'll probably accept any merge requests you submit. +I like to have the least number of steps possible for server owners updating my plugin. + +If you need *any* help making your changes, feel free to contact me on discord. The invite link is on the plugin page ;) diff --git a/api/build.gradle.kts b/api/build.gradle.kts new file mode 100644 index 0000000..e0874fc --- /dev/null +++ b/api/build.gradle.kts @@ -0,0 +1,46 @@ +plugins { + `java-library` + `maven-publish` +} + +group = "us.ajg0702.queue.api" + +repositories { + //mavenLocal() + mavenCentral() + + maven { url = uri("https://repo.ajg0702.us") } +} + +dependencies { + implementation("net.kyori:adventure-api:4.8.1") + implementation("net.kyori:adventure-text-serializer-plain:4.0.0-SNAPSHOT") + compileOnly("com.google.guava:guava:30.1.1-jre") + + compileOnly("us.ajg0702:ajUtils:1.1.7") +} + +publishing { + publications { + create("mavenJava") { + artifact(tasks["jar"]) + } + } + + repositories { + + val mavenUrl = "https://repo.ajg0702.us/releases" + + if(!System.getenv("REPO_TOKEN").isNullOrEmpty()) { + maven { + url = uri(mavenUrl) + name = "ajRepo" + + credentials { + username = "plugins" + password = System.getenv("REPO_TOKEN") + } + } + } + } +} \ No newline at end of file diff --git a/api/src/main/java/us/ajg0702/queue/api/AliasManager.java b/api/src/main/java/us/ajg0702/queue/api/AliasManager.java new file mode 100644 index 0000000..23265f6 --- /dev/null +++ b/api/src/main/java/us/ajg0702/queue/api/AliasManager.java @@ -0,0 +1,18 @@ +package us.ajg0702.queue.api; + +@SuppressWarnings("unused") +public interface AliasManager { + /** + * Gets an alias from the server/group's name + * @param server The original name of the server + * @return The set alias (set in the config) + */ + String getAlias(String server); + + /** + * Gets the name of the server/group from an alias + * @param alias The alias + * @return The name of the server/group + */ + String getServer(String alias); +} diff --git a/api/src/main/java/us/ajg0702/queue/api/EventHandler.java b/api/src/main/java/us/ajg0702/queue/api/EventHandler.java new file mode 100644 index 0000000..4b41130 --- /dev/null +++ b/api/src/main/java/us/ajg0702/queue/api/EventHandler.java @@ -0,0 +1,23 @@ +package us.ajg0702.queue.api; + +import net.kyori.adventure.text.Component; +import us.ajg0702.queue.api.players.AdaptedPlayer; +import us.ajg0702.queue.api.server.AdaptedServer; + +public interface EventHandler { + + void handleMessage(AdaptedPlayer reciever, byte[] data); + + void onPlayerJoin(AdaptedPlayer player); + + void onPlayerLeave(AdaptedPlayer player); + + /** + * Called when a player joins a server or switches between servers + * @param player the player + */ + void + onPlayerJoinServer(AdaptedPlayer player); + + void onServerKick(AdaptedPlayer player, AdaptedServer from, Component reason, boolean moving); +} diff --git a/api/src/main/java/us/ajg0702/queue/api/Logic.java b/api/src/main/java/us/ajg0702/queue/api/Logic.java new file mode 100644 index 0000000..781a944 --- /dev/null +++ b/api/src/main/java/us/ajg0702/queue/api/Logic.java @@ -0,0 +1,29 @@ +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; + +@SuppressWarnings({"SameReturnValue", "unused"}) + +public interface Logic { + /** + * Returns if the plugin is premium or not + * @return True if premium, false if not + */ + boolean isPremium(); + + /** + * The priority logic that is executed if the plugin is premium. + * @param server The server/group name that is being queued for + * @param player The player that is being queued + */ + QueuePlayer priorityLogic(QueueServer server, AdaptedPlayer player); + + /** + * The logic for checking if a player has been disconnected for too long + * @param player The player to check + * @return true if the player has been disconnected for too long and should be removed from the queue + */ + boolean playerDisconnectedTooLong(QueuePlayer player); +} diff --git a/api/src/main/java/us/ajg0702/queue/api/LogicGetter.java b/api/src/main/java/us/ajg0702/queue/api/LogicGetter.java new file mode 100644 index 0000000..af2b7e9 --- /dev/null +++ b/api/src/main/java/us/ajg0702/queue/api/LogicGetter.java @@ -0,0 +1,13 @@ +package us.ajg0702.queue.api; + +import us.ajg0702.queue.api.players.AdaptedPlayer; +import us.ajg0702.utils.common.Config; + +import java.util.List; + +@SuppressWarnings("unused") +public interface LogicGetter { + Logic constructLogic(); + AliasManager constructAliasManager(Config config); + List getPermissions(AdaptedPlayer player); +} diff --git a/api/src/main/java/us/ajg0702/queue/api/PlatformMethods.java b/api/src/main/java/us/ajg0702/queue/api/PlatformMethods.java new file mode 100644 index 0000000..14bfcc4 --- /dev/null +++ b/api/src/main/java/us/ajg0702/queue/api/PlatformMethods.java @@ -0,0 +1,50 @@ +package us.ajg0702.queue.api; + +import us.ajg0702.queue.api.commands.IBaseCommand; +import us.ajg0702.queue.api.commands.ICommandSender; +import us.ajg0702.queue.api.players.AdaptedPlayer; +import us.ajg0702.queue.api.server.AdaptedServer; + +import java.util.List; + +public interface PlatformMethods { + + /** + * Sends a plugin message on the plugin messaging channel + * @param player The player to send the message through + * @param channel The (sub)channel + * @param data The data + */ + @SuppressWarnings("EmptyMethod") + void sendPluginMessage(AdaptedPlayer player, String channel, String... data); + + /** + * Converts a command sender to an AdaptedPlayer + * @param sender the commandsender + * @return the AdaptedPlayer + */ + AdaptedPlayer senderToPlayer(ICommandSender sender); + + String getPluginVersion(); + + List getOnlinePlayers(); + List getPlayerNames(boolean lowercase); + AdaptedPlayer getPlayer(String name); + + List getServerNames(); + + String getImplementationName(); + + List getCommands(); + + /** + * Checks if a plugin is installed + * @param pluginName The name of the plugin to check for (case in-sensitive) + * @return if the plugin is on the server + */ + boolean hasPlugin(String pluginName); + + AdaptedServer getServer(String name); + + List getServers(); +} diff --git a/api/src/main/java/us/ajg0702/queue/api/QueueManager.java b/api/src/main/java/us/ajg0702/queue/api/QueueManager.java new file mode 100644 index 0000000..f8f49f0 --- /dev/null +++ b/api/src/main/java/us/ajg0702/queue/api/QueueManager.java @@ -0,0 +1,121 @@ +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 { + + /** + * Adds a player to a queue + * @param player The player to be added + * @param server The server or group to add the player to + * @return True if adding was successfull, false if not. + */ + boolean addToQueue(AdaptedPlayer player, QueueServer server); + + /** + * Adds a player to a queue + * @param player The player to be added + * @param serverName The name of the server or group to add the player too + * @return True if adding was successfull, false if not. + */ + @SuppressWarnings("UnusedReturnValue") + boolean addToQueue(AdaptedPlayer player, String serverName); + + /** + * Gets a list of QueueServers (servers and groups) + * @return A list of QueueServerss + */ + ImmutableList getServers(); + + /** + * Gets a list of QueueServer (servers and groups) names + * @return A list of QueueServer names + */ + ImmutableList getServerNames(); + + /** + * Get a single server the player is queued for. Depends on the multi-server-queue-pick option in the config + * @param player The player + * @return The server that was chosen that the player is queued for. + */ + QueueServer getSingleServer(AdaptedPlayer player); + + /** + * Get the name of the server the player is queued for. + * If multiple servers are queued for, it will use the multi-server-queue-pick option in the config + * @param player The player + * @return The name of the server, the placeholder none message if not queued + */ + String getQueuedName(AdaptedPlayer player); + + /** + * Checks servers that are in bungeecord and adds any it doesnt + * know about. + * + * 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 queuePlayer The player that is in the queue + */ + void sendMessage(QueuePlayer queuePlayer); + + /** + * Updates info about the servers + */ + void updateServers(); + + /** + * 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); + + void clear(AdaptedPlayer player); +} diff --git a/api/src/main/java/us/ajg0702/queue/api/commands/IBaseCommand.java b/api/src/main/java/us/ajg0702/queue/api/commands/IBaseCommand.java new file mode 100644 index 0000000..b4bc659 --- /dev/null +++ b/api/src/main/java/us/ajg0702/queue/api/commands/IBaseCommand.java @@ -0,0 +1,28 @@ +package us.ajg0702.queue.api.commands; + +import com.google.common.collect.ImmutableList; +import us.ajg0702.utils.common.Messages; + +import java.util.List; + +@SuppressWarnings("unused") +public interface IBaseCommand { + + String getName(); + + ImmutableList getAliases(); + + ImmutableList getSubCommands(); + + String getPermission(); + + boolean showInTabComplete(); + + Messages getMessages(); + + void addSubCommand(ISubCommand subCommand); + + void execute(ICommandSender sender, String[] args); + + List autoComplete(ICommandSender sender, String[] args); +} diff --git a/api/src/main/java/us/ajg0702/queue/api/commands/ICommandSender.java b/api/src/main/java/us/ajg0702/queue/api/commands/ICommandSender.java new file mode 100644 index 0000000..9bc925a --- /dev/null +++ b/api/src/main/java/us/ajg0702/queue/api/commands/ICommandSender.java @@ -0,0 +1,9 @@ +package us.ajg0702.queue.api.commands; + +import net.kyori.adventure.audience.Audience; +import us.ajg0702.queue.api.util.Handle; + +public interface ICommandSender extends Handle, Audience { + boolean hasPermission(String permission); + boolean isPlayer(); +} diff --git a/api/src/main/java/us/ajg0702/queue/api/commands/ISubCommand.java b/api/src/main/java/us/ajg0702/queue/api/commands/ISubCommand.java new file mode 100644 index 0000000..f093cc1 --- /dev/null +++ b/api/src/main/java/us/ajg0702/queue/api/commands/ISubCommand.java @@ -0,0 +1,4 @@ +package us.ajg0702.queue.api.commands; + +public interface ISubCommand extends IBaseCommand { +} 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 new file mode 100644 index 0000000..7e725e4 --- /dev/null +++ b/api/src/main/java/us/ajg0702/queue/api/players/AdaptedPlayer.java @@ -0,0 +1,76 @@ +package us.ajg0702.queue.api.players; + +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.Component; +import org.jetbrains.annotations.NotNull; +import us.ajg0702.queue.api.server.AdaptedServer; +import us.ajg0702.queue.api.util.Handle; + +import java.util.List; +import java.util.UUID; + +/** + * Represents a cross-platform player + */ +@SuppressWarnings("unused") +public interface AdaptedPlayer extends Handle, Audience { + + /** + * Check if the plauer is currently connected + * @return True if connected, false if not + */ + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + boolean isConnected(); + + /** + * Send a player a message from a Component + * @param message The message to send + */ + void sendMessage(@NotNull Component message); + + /** + * Sends an actionbar message to the player + * @param message The message to send + */ + void sendActionBar(@NotNull Component message); + + /** + * Send a player a message from a string + * Converted to Component internally + * @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(); + + /** + * Sends the player to a different server. + * Does not use the queue. + */ + void connect(AdaptedServer server); + + /** + * Gets the player's username + * @return the player's username + */ + String getName(); + + List getPermissions(); +} 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 new file mode 100644 index 0000000..7008553 --- /dev/null +++ b/api/src/main/java/us/ajg0702/queue/api/players/QueuePlayer.java @@ -0,0 +1,71 @@ +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(); + + /** + * Gets the player's username + * @return the player's username + */ + String getName(); + + /** + * Returns the number of miliseconds since this player was online + * @return The number of miliseconds since this player was online + */ + long getTimeSinceOnline(); + + /** + * Gets the max number of seconds this player is allowed to be offline before getting removed from the queue. + * @return the max number of seconds this player can be offline before being removed from the queue + */ + int getMaxOfflineTime(); +} 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 new file mode 100644 index 0000000..be6fc20 --- /dev/null +++ b/api/src/main/java/us/ajg0702/queue/api/queues/QueueServer.java @@ -0,0 +1,230 @@ +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.server.AdaptedServer; +import us.ajg0702.queue.api.server.AdaptedServerPing; + +import java.util.HashMap; +import java.util.List; +import java.util.UUID; + +/** + * Represents a server or a group that can be queued for + */ +@SuppressWarnings("unused") +public interface QueueServer { + + /** + * Get the players who are queued. + * @return The players who are queued + */ + ImmutableList getQueue(); + + /** + * Get the status of the server as a string + * @param p The player that you are checking for. Used for checking restricted servers + * @return The status of the server as a string + */ + String getStatusString(AdaptedPlayer p); + + /** + * Get the status of the server as a string. + * Does not check if the player has access using restricted mode. May show online if it is restricted + * @return The status of the server as a string + */ + String getStatusString(); + + /** + * Sends a server ping and uses the response to update online status, player count status, and whitelist status + */ + void updatePing(); + + /** + * Gets the time the server has been offline, in miliseconds + * @return The number of miliseconds the server has been offline for + */ + int getOfflineTime(); + + /** + * Gets how long since the last person was sent + * @return The number of miliseconds since the last person was sent + */ + long getLastSentTime(); + + /** + * Sets the time the last person was sent + * @param lastSentTime the time the last person was sent + */ + void setLastSentTime(long lastSentTime); + + + + /** + * Gets if the server is whitelisted or not + * @return True if whitelisted, false if not + */ + boolean isWhitelisted(); + + /** + * Sets if the server is whitelisted or not + */ + void setWhitelisted(boolean whitelisted); + + /** + * Gets the list of players who are whitelisted + * @return The list of player UUIDs who are whitelisted + */ + ImmutableList getWhitelistedPlayers(); + + /** + * Sets the list of UUIDs that are whitelisted + */ + void setWhitelistedPlayers(List whitelistedPlayers); + + /** + * Checks if the server is joinable by a player + * @param p The player to see if they can join + * @return If the server is joinable + */ + boolean isJoinable(AdaptedPlayer p); + + /** + * Pauses or unpauses a server + * @param paused true = paused, false = unpaused + */ + void setPaused(boolean paused); + + /** + * Checks if the server is paused + * @return True if the server is paused, false if its not + */ + boolean isPaused(); + + /** + * Checks if the server is online + * @return True if the server is online, false if not + */ + boolean isOnline(); + + /** + * Checks if the server went online within the time set in the config + * @return If the sevrer just came online + */ + boolean justWentOnline(); + + /** + * Checks if the server is full + * @return If the server is full + */ + boolean isFull(); + + /** + * Removes a player from the queue + * @param player The player to remove + */ + void removePlayer(QueuePlayer player); + + /** + * 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 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(); + + /** + * Get the servers that this QueueServer represents + * @return A list of servers that this QueueServer represents + */ + ImmutableList getServers(); + + /** + * Gets the names of the servers in this group + * @return A list of names + */ + ImmutableList getServerNames(); + + + /** + * Returns if this server is a group + * @return True if this server is a group + */ + boolean isGroup(); + + /** + * Finds the player in this queue and returns the representative QueuePlayer + * @return The QueuePlayer representing the player, null if not found + */ + QueuePlayer findPlayer(AdaptedPlayer 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 + */ + QueuePlayer findPlayer(UUID uuid); + + + /** + * Gets the most ideal server in this group to join + * @param player The player that would be joining + * @return The ideal server to join + */ + AdaptedServer getIdealServer(AdaptedPlayer player); + + /** + * Gets the last server pings + * @return The last server pings for this server/group + */ + HashMap getLastPings(); + + + /** + * elliot is bad + * @return true because elliot is bad + */ + @SuppressWarnings({"unused", "SameReturnValue"}) + default boolean elliot_is_bad() { + return true; + } +} 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 new file mode 100644 index 0000000..494e6db --- /dev/null +++ b/api/src/main/java/us/ajg0702/queue/api/server/AdaptedServer.java @@ -0,0 +1,41 @@ +package us.ajg0702.queue.api.server; + +import us.ajg0702.queue.api.players.AdaptedPlayer; +import us.ajg0702.queue.api.util.Handle; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +@SuppressWarnings("unused") +public interface AdaptedServer extends Handle { + + /** + * Gets the ServerInfo for this server + * @return The AdaptedServerInfo for this server + */ + AdaptedServerInfo getServerInfo(); + + /** + * Gets the server's name + * @return the server's name + */ + String getName(); + + /** + * Pings the server and gets info back + * @return A CompletableFuture with the ServerPing + */ + CompletableFuture ping(); + + /** + * If the player can access the server + * Uses bungeecord's restricted server feature + * Will always return true on other platforms + * @param player The player to check + * @return False if the server is restricted and the player does not have permission to join. + */ + @SuppressWarnings("SameReturnValue") + boolean canAccess(AdaptedPlayer player); + + List getPlayers(); +} diff --git a/api/src/main/java/us/ajg0702/queue/api/server/AdaptedServerInfo.java b/api/src/main/java/us/ajg0702/queue/api/server/AdaptedServerInfo.java new file mode 100644 index 0000000..3c04b42 --- /dev/null +++ b/api/src/main/java/us/ajg0702/queue/api/server/AdaptedServerInfo.java @@ -0,0 +1,13 @@ +package us.ajg0702.queue.api.server; + +import us.ajg0702.queue.api.util.Handle; + +public interface AdaptedServerInfo extends Handle { + + /** + * Gets the name of the server + * @return The name of the server + */ + String getName(); + +} diff --git a/api/src/main/java/us/ajg0702/queue/api/server/AdaptedServerPing.java b/api/src/main/java/us/ajg0702/queue/api/server/AdaptedServerPing.java new file mode 100644 index 0000000..8257d97 --- /dev/null +++ b/api/src/main/java/us/ajg0702/queue/api/server/AdaptedServerPing.java @@ -0,0 +1,31 @@ +package us.ajg0702.queue.api.server; + +import net.kyori.adventure.text.Component; +import us.ajg0702.queue.api.util.Handle; + +@SuppressWarnings("unused") +public interface AdaptedServerPing extends Handle { + /** + * Gets the component of the description (aka MOTD) + * @return A compoent of the description + */ + Component getDescriptionComponent(); + + /** + * Gets the description stripped of any color or styling + * @return The description, but no colors + */ + String getPlainDescription(); + + /** + * Gets the number of players currently online + * @return The number of players online + */ + int getPlayerCount(); + + /** + * Gets the maximum number of players that can join. + * @return The maximum number of players that can join + */ + int getMaxPlayers(); +} diff --git a/api/src/main/java/us/ajg0702/queue/api/util/Handle.java b/api/src/main/java/us/ajg0702/queue/api/util/Handle.java new file mode 100644 index 0000000..4210519 --- /dev/null +++ b/api/src/main/java/us/ajg0702/queue/api/util/Handle.java @@ -0,0 +1,5 @@ +package us.ajg0702.queue.api.util; + +public interface Handle { + Object getHandle(); +} diff --git a/api/src/main/java/us/ajg0702/queue/api/util/QueueLogger.java b/api/src/main/java/us/ajg0702/queue/api/util/QueueLogger.java new file mode 100644 index 0000000..412b468 --- /dev/null +++ b/api/src/main/java/us/ajg0702/queue/api/util/QueueLogger.java @@ -0,0 +1,9 @@ +package us.ajg0702.queue.api.util; + +public interface QueueLogger { + void warn(String message); + void warning(String message); + void info(String message); + void error(String message); + void severe(String message); +} diff --git a/build.gradle.kts b/build.gradle.kts index 24f0451..523a82c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,60 +4,42 @@ plugins { `maven-publish` } -group = "us.ajg0702" -version = "1.9.8" - repositories { mavenCentral() - mavenLocal() - - maven { url = uri("https://jitpack.io") } - maven { url = uri("https://gitlab.com/api/v4/projects/19978391/packages/maven") } - maven { url = uri("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") } - maven { url = uri("https://repo.extendedclip.com/content/repositories/placeholderapi/") } - maven { url = uri("https://repo.codemc.org/repository/maven-public") } - maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") } - maven { url = uri("https://repo.codemc.io/repository/nms/") } maven { url = uri("https://repo.ajg0702.us") } + maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") } } +allprojects { + version = "2.0.0" + group = "us.ajg0702" + + tasks.withType().configureEach { + useJUnitPlatform() + + ignoreFailures = false + failFast = true + maxParallelForks = (Runtime.getRuntime().availableProcessors() - 1).takeIf { it > 0 } ?: 1 + + reports.html.isEnabled = false + reports.junitXml.isEnabled = false + } + + +} + + dependencies { testImplementation("junit:junit:4.12") - testImplementation("net.kyori:adventure-text-serializer-bungeecord:4.0.0-SNAPSHOT") - testImplementation("net.kyori:adventure-text-serializer-plain:4.0.0-SNAPSHOT") - compileOnly("com.github.MyzelYam:PremiumVanishAPI:2.0.3") - compileOnly("net.md-5:bungeecord-api:1.14-SNAPSHOT") - compileOnly(group = "org.spigotmc", name = "spigot", version = "1.16.5-R0.1-SNAPSHOT") - 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("org.bstats:bstats-bungeecord:2.2.1") - implementation("net.kyori:adventure-text-serializer-plain:4.0.0-SNAPSHOT") + implementation(project(":free")) } -tasks.withType { - include("**/*.yml") - filter( - "tokens" to mapOf( - "VERSION" to project.version.toString() - ) - ) -} - -tasks.shadowJar { - relocate("us.ajg0702.utils", "us.ajg0702.queue.utils") - relocate("org.bstats", "us.ajg0702.bstats") - relocate("net.kyori", "us.ajg0702.queue.kyori") - archiveFileName.set("${baseName}-${version}.${extension}") -} - publishing { publications { create("mavenJava") { - artifact(tasks["jar"]) + artifact(tasks["shadowJar"]) } } diff --git a/common/build.gradle.kts b/common/build.gradle.kts new file mode 100644 index 0000000..4cdefba --- /dev/null +++ b/common/build.gradle.kts @@ -0,0 +1,51 @@ +plugins { + `java-library` + `maven-publish` +} + +group = "us.ajg0702.queue.common" + +repositories { + //mavenLocal() + mavenCentral() + maven { url = uri("https://repo.ajg0702.us") } +} + +dependencies { + compileOnly("net.kyori:adventure-api:4.8.1") + compileOnly("net.kyori:adventure-text-serializer-plain:4.0.0-SNAPSHOT") + + compileOnly("com.google.guava:guava:30.1.1-jre") + compileOnly("us.ajg0702:ajUtils:1.1.7") + + compileOnly("org.slf4j:slf4j-log4j12:1.7.29") + + compileOnly("org.spongepowered:configurate-yaml:4.0.0") + + implementation(project(":api")) +} + +publishing { + publications { + create("mavenJava") { + artifact(tasks["jar"]) + } + } + + repositories { + + val mavenUrl = "https://repo.ajg0702.us/releases" + + if(!System.getenv("REPO_TOKEN").isNullOrEmpty()) { + maven { + url = uri(mavenUrl) + name = "ajRepo" + + credentials { + username = "plugins" + password = System.getenv("REPO_TOKEN") + } + } + } + } +} \ No newline at end of file diff --git a/common/src/main/java/us/ajg0702/queue/commands/BaseCommand.java b/common/src/main/java/us/ajg0702/queue/commands/BaseCommand.java new file mode 100644 index 0000000..b2e0718 --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/commands/BaseCommand.java @@ -0,0 +1,67 @@ +package us.ajg0702.queue.commands; + +import com.google.common.collect.ImmutableList; +import net.kyori.adventure.text.Component; +import us.ajg0702.queue.api.commands.IBaseCommand; +import us.ajg0702.queue.api.commands.ICommandSender; +import us.ajg0702.queue.api.commands.ISubCommand; +import us.ajg0702.utils.common.Messages; + +import java.util.List; + +public class BaseCommand implements IBaseCommand { + @Override + public String getName() { + return null; + } + + @Override + public ImmutableList getAliases() { + return null; + } + + @SuppressWarnings("unused") + @Override + public ImmutableList getSubCommands() { + return null; + } + + @Override + public String getPermission() { + return null; + } + + @Override + public boolean showInTabComplete() { + return true; + } + + @Override + public Messages getMessages() { + return null; + } + + @SuppressWarnings("unused") + @Override + public void addSubCommand(ISubCommand subCommand) { + + } + + @Override + public void execute(ICommandSender sender, String[] args) { + sender.sendMessage(Component.text("Unimplemented command")); + } + + public boolean checkPermission(ICommandSender sender) { + if(getPermission() != null && !sender.hasPermission(getPermission())) { + sender.sendMessage(getMessages().getComponent("noperm")); + return false; + } + return true; + } + + @Override + public List autoComplete(ICommandSender sender, String[] args) { + return null; + } +} diff --git a/common/src/main/java/us/ajg0702/queue/commands/SubCommand.java b/common/src/main/java/us/ajg0702/queue/commands/SubCommand.java new file mode 100644 index 0000000..86e1cfa --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/commands/SubCommand.java @@ -0,0 +1,7 @@ +package us.ajg0702.queue.commands; + +import us.ajg0702.queue.api.commands.ISubCommand; + +public class SubCommand extends BaseCommand implements ISubCommand { + +} diff --git a/common/src/main/java/us/ajg0702/queue/commands/commands/PlayerSender.java b/common/src/main/java/us/ajg0702/queue/commands/commands/PlayerSender.java new file mode 100644 index 0000000..57da37c --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/PlayerSender.java @@ -0,0 +1,28 @@ +package us.ajg0702.queue.commands.commands; + +import us.ajg0702.queue.api.commands.ICommandSender; +import us.ajg0702.queue.api.players.AdaptedPlayer; + +public class PlayerSender implements ICommandSender { + + final AdaptedPlayer handle; + + public PlayerSender(AdaptedPlayer handle) { + this.handle = handle; + } + + @Override + public boolean hasPermission(String permission) { + return handle.hasPermission(permission); + } + + @Override + public boolean isPlayer() { + return true; + } + + @Override + public AdaptedPlayer getHandle() { + return handle; + } +} 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 new file mode 100644 index 0000000..336a621 --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/leavequeue/LeaveCommand.java @@ -0,0 +1,115 @@ +package us.ajg0702.queue.commands.commands.leavequeue; + +import com.google.common.collect.ImmutableList; +import us.ajg0702.queue.api.commands.ICommandSender; +import us.ajg0702.queue.api.commands.ISubCommand; +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.commands.BaseCommand; +import us.ajg0702.queue.common.QueueMain; +import us.ajg0702.utils.common.Messages; + +import java.util.ArrayList; +import java.util.List; + +public class LeaveCommand extends BaseCommand { + + + private final QueueMain main; + + public LeaveCommand(QueueMain main) { + this.main = main; + } + + @Override + public String getName() { + return "leavequeue"; + } + + @Override + public ImmutableList getAliases() { + return ImmutableList.of("leaveq"); + } + + @Override + public ImmutableList getSubCommands() { + 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; + } + AdaptedPlayer player = main.getPlatformMethods().senderToPlayer(sender); + List servers = main.getQueueManager().getPlayerQueues(player); + + if(servers.size() == 0) { + sender.sendMessage(getMessages().getComponent("commands.leave.no-queues")); + return; + } + + + if(servers.size() == 1) { + servers.get(0).removePlayer(player); + sender.sendMessage(getMessages().getComponent("commands.leave-queue", "SERVER:"+servers.get(0).getAlias())); + return; + } + + + if(args.length <= 0) { + sender.sendMessage(getMessages().getComponent("commands.leave.more-args", "QUEUES:"+getQueueList(servers))); + return; + } + + String leaving = args[0]; + QueueServer leavingServer = main.getQueueManager().findServer(leaving); + if(leavingServer == null) { + sender.sendMessage(getMessages().getComponent("commands.leave.not-queued", "QUEUES:"+getQueueList(servers))); + return; + } + QueuePlayer queuePlayer = leavingServer.findPlayer(player); + if(queuePlayer == null) { + sender.sendMessage(getMessages().getComponent("commands.leave.not-queued", "QUEUES:"+getQueueList(servers))); + return; + } + + + leavingServer.removePlayer(queuePlayer); + sender.sendMessage(getMessages().getComponent("commands.leave-queue", "SERVER:"+leavingServer.getAlias())); + + } + + private String getQueueList(List servers) { + StringBuilder queueList = new StringBuilder(); + for(QueueServer server : servers) { + queueList.append(getMessages().getString("commands.leave.queues-list-format").replaceAll("\\{NAME}", server.getName())); + } + if(queueList.length() > 2) { + queueList = new StringBuilder(queueList.substring(0, queueList.length() - 2)); + } + return queueList.toString(); + } + + @Override + public List autoComplete(ICommandSender sender, String[] args) { + List servers = main.getQueueManager().findPlayerInQueues(main.getPlatformMethods().senderToPlayer(sender)); + List serverNames = new ArrayList<>(); + for(QueuePlayer queuePlayer : servers) { + serverNames.add(queuePlayer.getQueueServer().getName()); + } + return serverNames; + } +} 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 new file mode 100644 index 0000000..29d4e0e --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/listqueues/ListCommand.java @@ -0,0 +1,84 @@ +package us.ajg0702.queue.commands.commands.listqueues; + +import com.google.common.collect.ImmutableList; +import net.kyori.adventure.text.Component; +import us.ajg0702.queue.api.commands.ICommandSender; +import us.ajg0702.queue.api.commands.ISubCommand; +import us.ajg0702.queue.api.players.AdaptedPlayer; +import us.ajg0702.queue.api.queues.QueueServer; +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; + +public class ListCommand extends BaseCommand { + + private final QueueMain main; + + public ListCommand(QueueMain main) { + this.main = main; + } + + @Override + public String getName() { + return "listqueues"; + } + + @Override + public ImmutableList getAliases() { + return ImmutableList.of("listq"); + } + + @Override + public ImmutableList getSubCommands() { + return ImmutableList.builder().build(); + } + + @Override + public String getPermission() { + return "ajqueue.listqueues"; + } + + @Override + public Messages getMessages() { + return main.getMessages(); + } + + @Override + public void execute(ICommandSender sender, String[] args) { + if(!checkPermission(sender)) return; + + + AdaptedPlayer spp = null; + if(sender.isPlayer()) { + spp = main.getPlatformMethods().senderToPlayer(sender); + } + + + Component m = main.getMessages().getComponent("commands.listqueues.header"); + for(QueueServer s : main.getQueueManager().getServers()) { + String color = "&a"; + if(!s.isOnline()) { + color = "&c"; + } else if(!s.isJoinable(spp)) { + color = "&e"; + } + + m = m.append(Component.text("\n")); + m = m.append(main.getMessages().getComponent("commands.listqueues.format", + "COLOR:" + main.getMessages().color(color), + "NAME:" + s.getAlias(), + "COUNT:" + s.getQueue().size(), + "STATUS:" + s.getStatusString(spp) + )); + } + sender.sendMessage(m); + } + + @Override + public List autoComplete(ICommandSender sender, String[] args) { + return new ArrayList<>(); + } +} diff --git a/common/src/main/java/us/ajg0702/queue/commands/commands/manage/ISP.java b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/ISP.java new file mode 100644 index 0000000..ad29978 --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/ISP.java @@ -0,0 +1,55 @@ +package us.ajg0702.queue.commands.commands.manage; + +import com.google.common.collect.ImmutableList; +import net.kyori.adventure.text.Component; +import us.ajg0702.queue.api.commands.ICommandSender; +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.List; + +public class ISP extends SubCommand { + + final QueueMain main; + public ISP(QueueMain main) { + this.main = main; + } + + @Override + public String getName() { + return "isp"; + } + + @Override + public ImmutableList getAliases() { + return ImmutableList.of(); + } + + @Override + public boolean showInTabComplete() { + return false; + } + + @Override + public String getPermission() { + return null; + } + + @Override + public Messages getMessages() { + return main.getMessages(); + } + + @Override + public void execute(ICommandSender sender, String[] args) { + if(!checkPermission(sender)) return; + sender.sendMessage(Component.text(main.getLogic().isPremium())); + } + + @Override + public List autoComplete(ICommandSender sender, String[] args) { + return new ArrayList<>(); + } +} 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 new file mode 100644 index 0000000..e97d81f --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/ManageCommand.java @@ -0,0 +1,97 @@ +package us.ajg0702.queue.commands.commands.manage; + +import com.google.common.collect.ImmutableList; +import net.kyori.adventure.text.Component; +import us.ajg0702.queue.api.commands.ICommandSender; +import us.ajg0702.queue.api.commands.ISubCommand; +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.Locale; + +public class ManageCommand extends BaseCommand { + + final QueueMain main; + + public ManageCommand(QueueMain main) { + this.main = main; + + addSubCommand(new Reload(main)); + addSubCommand(new Tasks(main)); + addSubCommand(new Version(main)); + addSubCommand(new Pause(main)); + addSubCommand(new ISP(main)); + addSubCommand(new QueueList(main)); + addSubCommand(new Send(main)); + addSubCommand(new PermissionList(main)); + } + + + @Override + public String getName() { + return "ajqueue"; + } + + @Override + public ImmutableList getAliases() { + return ImmutableList.of("ajq"); + } + + final List subCommands = new ArrayList<>(); + + @Override + public ImmutableList getSubCommands() { + return ImmutableList.copyOf(subCommands); + } + + @Override + public String getPermission() { + return "ajqueue.manage"; + } + + @Override + public Messages getMessages() { + return main.getMessages(); + } + + @Override + public void addSubCommand(ISubCommand subCommand) { + subCommands.add(subCommand); + } + + @Override + public void execute(ICommandSender sender, String[] args) { + if(args.length > 0) { + for(ISubCommand subCommand : subCommands) { + if(args[0].equalsIgnoreCase(subCommand.getName()) || subCommand.getAliases().contains(args[0].toLowerCase(Locale.ROOT))) { + subCommand.execute(sender, Arrays.copyOfRange(args, 1, args.length)); + return; + } + } + } + sender.sendMessage(Component.text("/ajQueue ")); + } + + @Override + public List autoComplete(ICommandSender sender, String[] args) { + if(args.length > 1) { + for(ISubCommand subCommand : subCommands) { + if(args[0].equalsIgnoreCase(subCommand.getName()) || subCommand.getAliases().contains(args[0].toLowerCase(Locale.ROOT))) { + return subCommand.autoComplete(sender, Arrays.copyOfRange(args, 1, args.length)); + } + } + return new ArrayList<>(); + } + List commands = new ArrayList<>(); + for(ISubCommand subCommand : subCommands) { + if(!subCommand.showInTabComplete()) continue; + commands.add(subCommand.getName()); + commands.addAll(subCommand.getAliases()); + } + return commands; + } +} 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 new file mode 100644 index 0000000..a165642 --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Pause.java @@ -0,0 +1,76 @@ +package us.ajg0702.queue.commands.commands.manage; + +import com.google.common.collect.ImmutableList; +import us.ajg0702.queue.api.commands.ICommandSender; +import us.ajg0702.queue.api.queues.QueueServer; +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.Arrays; +import java.util.List; + +public class Pause extends SubCommand { + + final QueueMain main; + public Pause(QueueMain main) { + this.main = main; + } + + @Override + public String getName() { + return "pause"; + } + + @Override + public ImmutableList getAliases() { + return ImmutableList.of(); + } + + @Override + public String getPermission() { + return "ajqueue.manage.pause"; + } + + @Override + public Messages getMessages() { + return main.getMessages(); + } + + @Override + public void execute(ICommandSender sender, String[] args) { + if(!checkPermission(sender)) return; + + if(args.length < 1) { + sender.sendMessage(getMessages().getComponent("commands.pause.more-args")); + return; + } + + QueueServer server = main.getQueueManager().findServer(args[0]); + if(server == null) { + sender.sendMessage(getMessages().getComponent("commands.pause.no-server", "SERVER:"+args[1])); + return; + } + if(args.length == 1) { + server.setPaused(!server.isPaused()); + } else { + server.setPaused(args[1].equalsIgnoreCase("on") || args[1].equalsIgnoreCase("true")); + } + sender.sendMessage(getMessages().getComponent("commands.pause.success", + "SERVER:"+server.getName(), + "PAUSED:"+getMessages().getString("commands.pause.paused."+server.isPaused()) + )); + } + + @Override + public List autoComplete(ICommandSender sender, String[] args) { + if(args.length == 1) { + return main.getQueueManager().getServerNames(); + } + if(args.length == 2) { + return Arrays.asList("on", "off", "true", "false"); + } + return new ArrayList<>(); + } +} diff --git a/common/src/main/java/us/ajg0702/queue/commands/commands/manage/PermissionList.java b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/PermissionList.java new file mode 100644 index 0000000..84c340d --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/PermissionList.java @@ -0,0 +1,65 @@ +package us.ajg0702.queue.commands.commands.manage; + +import com.google.common.collect.ImmutableList; +import net.kyori.adventure.text.Component; +import us.ajg0702.queue.api.commands.ICommandSender; +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.List; +import java.util.Locale; + +public class PermissionList extends SubCommand { + + final QueueMain main; + public PermissionList(QueueMain main) { + this.main = main; + } + + @Override + public String getName() { + return "permissionlist"; + } + + @Override + public ImmutableList getAliases() { + return ImmutableList.of(); + } + + @Override + public boolean showInTabComplete() { + return false; + } + + @Override + public String getPermission() { + return null; + } + + @Override + public Messages getMessages() { + return main.getMessages(); + } + + @Override + public void execute(ICommandSender sender, String[] args) { + if(!checkPermission(sender)) return; + List permissions = main.getLogicGetter().getPermissions(main.getPlatformMethods().senderToPlayer(sender)); + if(permissions == null) { + sender.sendMessage(Component.text("no permission handler")); + return; + } + + permissions.forEach(s -> { + if(!s.toLowerCase(Locale.ROOT).contains("ajqueue")) return; + sender.sendMessage(Component.text(s)); + }); + } + + @Override + public List autoComplete(ICommandSender sender, String[] args) { + return new ArrayList<>(); + } +} 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 new file mode 100644 index 0000000..1aa49e3 --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/QueueList.java @@ -0,0 +1,93 @@ +package us.ajg0702.queue.commands.commands.manage; + +import com.google.common.collect.ImmutableList; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.PatternReplacementResult; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import us.ajg0702.queue.api.commands.ICommandSender; +import us.ajg0702.queue.api.players.QueuePlayer; +import us.ajg0702.queue.api.queues.QueueServer; +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.List; +import java.util.regex.Pattern; + +public class QueueList extends SubCommand { + + final QueueMain main; + public QueueList(QueueMain main) { + this.main = main; + } + + @Override + public String getName() { + return "list"; + } + + @Override + public ImmutableList getAliases() { + return ImmutableList.of(); + } + + @Override + public String getPermission() { + return "ajqueue.manage.list"; + } + + @Override + public Messages getMessages() { + return main.getMessages(); + } + + @Override + public void execute(ICommandSender sender, String[] args) { + if(!checkPermission(sender)) return; + int total = 0; + for(QueueServer server : main.getQueueManager().getServers()) { + + Component msg = getMessages().getComponent("list.format", + "SERVER:"+server.getName() + ); + Component playerList = Component.empty(); + List players = server.getQueue(); + boolean none = true; + for(QueuePlayer p : players) { + playerList = playerList.append(getMessages().getComponent("list.playerlist", + "NAME:" + p.getName() + )); + none = false; + } + if(none) { + playerList = playerList.append(getMessages().getComponent("list.none")); + playerList = playerList.append(Component.text(", ")); + } + Component finalPlayerList = playerList; + msg = msg.replaceText(b -> b.match(Pattern.compile("\\{LIST}")).replacement(finalPlayerList)); + char[] commaCountString = PlainTextComponentSerializer.plainText().serialize(msg).toCharArray(); + int commas = 0; + for(Character fChar : commaCountString) { + if(fChar == ',') commas++; + } + + int finalCommas = commas; + msg = msg.replaceText(b -> b.match(",(?!.*,)").replacement("").condition((r, c, re) -> { + if(c == finalCommas) { + return PatternReplacementResult.REPLACE; + } + return PatternReplacementResult.CONTINUE; + })); + total += players.size(); + msg = msg.replaceText(b -> b.match(Pattern.compile("\\{COUNT}")).replacement(players.size()+"")); + sender.sendMessage(msg); + } + sender.sendMessage(getMessages().getComponent("list.total", "TOTAL:"+total)); + } + + @Override + public java.util.List autoComplete(ICommandSender sender, String[] args) { + return new ArrayList<>(); + } +} 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 new file mode 100644 index 0000000..6793df3 --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Reload.java @@ -0,0 +1,65 @@ +package us.ajg0702.queue.commands.commands.manage; + +import com.google.common.collect.ImmutableList; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.spongepowered.configurate.ConfigurateException; +import us.ajg0702.queue.api.commands.ICommandSender; +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.List; + +public class Reload extends SubCommand { + + final QueueMain main; + public Reload(QueueMain main) { + this.main = main; + } + + @Override + public String getName() { + return "reload"; + } + + @Override + public ImmutableList getAliases() { + return ImmutableList.of(); + } + + @Override + public String getPermission() { + return "ajqueue.manage.reload"; + } + + @Override + public Messages getMessages() { + return main.getMessages(); + } + + @Override + public void execute(ICommandSender sender, String[] args) { + if(!checkPermission(sender)) return; + main.getMessages().reload(); + try { + main.getConfig().reload(); + } catch (ConfigurateException e) { + sender.sendMessage(Component.text("An error occurred while reloading. Check the console").color(NamedTextColor.RED)); + e.printStackTrace(); + return; + } + main.setTimeBetweenPlayers(); + main.getTaskManager().rescheduleTasks(); + main.getQueueManager().reloadServers(); + main.getMessages().reload(); + + sender.sendMessage(getMessages().getComponent("commands.reload")); + } + + @Override + public List autoComplete(ICommandSender sender, String[] args) { + return new ArrayList<>(); + } +} 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 new file mode 100644 index 0000000..dc4c1af --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Send.java @@ -0,0 +1,101 @@ +package us.ajg0702.queue.commands.commands.manage; + +import com.google.common.collect.ImmutableList; +import net.kyori.adventure.text.Component; +import us.ajg0702.queue.api.commands.ICommandSender; +import us.ajg0702.queue.api.players.AdaptedPlayer; +import us.ajg0702.queue.api.server.AdaptedServer; +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.List; + +public class Send extends SubCommand { + + final QueueMain main; + public Send(QueueMain main) { + this.main = main; + } + + @Override + public String getName() { + return "send"; + } + + @Override + public ImmutableList getAliases() { + return ImmutableList.of(); + } + + @Override + public String getPermission() { + return "ajqueue.manage.send"; + } + + @Override + public Messages getMessages() { + return main.getMessages(); + } + + @Override + public void execute(ICommandSender sender, String[] args) { + if(!checkPermission(sender)) return; + + if(main.getQueueManager().findServer(args[1]) == null) { + sender.sendMessage(getMessages().getComponent("errors.server-not-exist", "SERVER:"+args[2])); + return; + } + + List playerNames = main.getPlatformMethods().getPlayerNames(true); + if(playerNames.contains(args[0].toLowerCase())) { + + AdaptedPlayer ply = main.getPlatformMethods().getPlayer(args[0]); + if(ply == null) { + sender.sendMessage(Component.text("player not found")); + return; + } + if(ply.getName() == null) { + sender.sendMessage(Component.text("name null")); + } + main.getQueueManager().addToQueue(ply, args[1]); + sender.sendMessage(getMessages().getComponent("send", + "PLAYER:"+ply.getName(), + "SERVER:"+args[1]) + ); + } else if(main.getQueueManager().getServerNames().contains(args[0])) { + + AdaptedServer from = main.getPlatformMethods().getServer(args[0]); + if(from == null) { + sender.sendMessage(getMessages().getComponent("errors.server-not-exist", "SERVER:"+args[0])); + return; + } + List players = new ArrayList<>(from.getPlayers()); + for(AdaptedPlayer ply : players) { + main.getQueueManager().addToQueue(ply, args[1]); + } + + sender.sendMessage(getMessages().getComponent("send", "PLAYER:"+args[0], "SERVER:"+args[1])); + + } else { + sender.sendMessage(getMessages().getComponent("commands.send.player-not-found")); + } + } + + @Override + public List autoComplete(ICommandSender sender, String[] args) { + if(args.length == 1) { + List options = new ArrayList<>(main.getPlatformMethods().getServerNames()); + options.addAll(main.getPlatformMethods().getPlayerNames(false)); + return options; + } + if(args.length == 2) { + return main.getQueueManager().getServerNames(); + } + return new ArrayList<>(); + } + + + +} diff --git a/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Tasks.java b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Tasks.java new file mode 100644 index 0000000..6d44014 --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Tasks.java @@ -0,0 +1,55 @@ +package us.ajg0702.queue.commands.commands.manage; + +import com.google.common.collect.ImmutableList; +import net.kyori.adventure.text.Component; +import us.ajg0702.queue.api.commands.ICommandSender; +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.List; + +public class Tasks extends SubCommand { + + final QueueMain main; + public Tasks(QueueMain main) { + this.main = main; + } + + @Override + public String getName() { + return "tasks"; + } + + @Override + public ImmutableList getAliases() { + return ImmutableList.of(); + } + + @Override + public String getPermission() { + return "ajqueue.manage.tasks"; + } + + @Override + public boolean showInTabComplete() { + return false; + } + + @Override + public Messages getMessages() { + return main.getMessages(); + } + + @Override + public void execute(ICommandSender sender, String[] args) { + if(!checkPermission(sender)) return; + sender.sendMessage(Component.text(main.getTaskManager().taskStatus())); + } + + @Override + public List autoComplete(ICommandSender sender, String[] args) { + return new ArrayList<>(); + } +} diff --git a/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Version.java b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Version.java new file mode 100644 index 0000000..f7d019e --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/manage/Version.java @@ -0,0 +1,50 @@ +package us.ajg0702.queue.commands.commands.manage; + +import com.google.common.collect.ImmutableList; +import net.kyori.adventure.text.Component; +import us.ajg0702.queue.api.commands.ICommandSender; +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.List; + +public class Version extends SubCommand { + + final QueueMain main; + public Version(QueueMain main) { + this.main = main; + } + + @Override + public String getName() { + return "version"; + } + + @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(!checkPermission(sender)) return; + sender.sendMessage(Component.text(main.getPlatformMethods().getPluginVersion())); + } + + @Override + public List autoComplete(ICommandSender sender, String[] args) { + return new ArrayList<>(); + } +} 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 new file mode 100644 index 0000000..474aeb1 --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/commands/commands/queue/QueueCommand.java @@ -0,0 +1,82 @@ +package us.ajg0702.queue.commands.commands.queue; + +import com.google.common.collect.ImmutableList; +import us.ajg0702.queue.api.commands.ICommandSender; +import us.ajg0702.queue.api.commands.ISubCommand; +import us.ajg0702.queue.api.players.AdaptedPlayer; +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; + +public class QueueCommand extends BaseCommand { + + private final QueueMain main; + + public QueueCommand(QueueMain main) { + this.main = main; + } + + @Override + public String getName() { + return "queue"; + } + + @Override + public ImmutableList getAliases() { + List aliases = new ArrayList<>(Arrays.asList("move", "joinqueue", "joinq")); + if(main.getConfig().getBoolean("enable-server-command")) { + aliases.add("server"); + } + return ImmutableList.copyOf(aliases); + } + + @Override + public ImmutableList getSubCommands() { + return ImmutableList.builder().build(); + } + + @Override + public String getPermission() { + return null; + } + + @Override + public Messages getMessages() { + return main.getMessages(); + } + + @Override + public void execute(ICommandSender sender, String[] args) { + if(!checkPermission(sender)) return; + if(!sender.isPlayer()) { + sender.sendMessage(getMessages().getComponent("errors.player-only")); + return; + } + AdaptedPlayer player = main.getPlatformMethods().senderToPlayer(sender); + + if(args.length > 0) { + if(main.getConfig().getBoolean("require-permission") && !player.hasPermission("ajqueue.queue."+args[0])) { + sender.sendMessage(getMessages().getComponent("noperm")); + return; + } + main.getQueueManager().addToQueue(player, args[0]); + } else { + sender.sendMessage(getMessages().getComponent("commands.joinqueue.usage")); + } + } + + @Override + public List autoComplete(ICommandSender sender, String[] args) { + if(!main.getConfig().getBoolean("tab-complete-queues")) { + return new ArrayList<>(); + } + if(args.length == 1) { + return main.getQueueManager().getServerNames(); + } + return new ArrayList<>(); + } +} diff --git a/common/src/main/java/us/ajg0702/queue/common/EventHandlerImpl.java b/common/src/main/java/us/ajg0702/queue/common/EventHandlerImpl.java new file mode 100644 index 0000000..9316cbd --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/common/EventHandlerImpl.java @@ -0,0 +1,205 @@ +package us.ajg0702.queue.common; + +import com.google.common.collect.ImmutableList; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import us.ajg0702.queue.api.EventHandler; +import us.ajg0702.queue.api.commands.IBaseCommand; +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 us.ajg0702.queue.commands.commands.PlayerSender; +import us.ajg0702.queue.common.players.QueuePlayerImpl; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class EventHandlerImpl implements EventHandler { + + final QueueMain main; + public EventHandlerImpl(QueueMain main) { + this.main = main; + } + + @Override + public void handleMessage(AdaptedPlayer recievingPlayer, byte[] data) { + IBaseCommand moveCommand = main.getPlatformMethods().getCommands().get(0); + IBaseCommand leaveCommand = main.getPlatformMethods().getCommands().get(1); + DataInputStream in = new DataInputStream(new ByteArrayInputStream(data)); + try { + String subchannel = in.readUTF(); + + if(subchannel.equals("queue")) { + String rawData = in.readUTF(); + String[] args = new String[1]; + args[0] = rawData; + moveCommand.execute(new PlayerSender(recievingPlayer), args); + } + if(subchannel.equals("massqueue")) { + String inData = in.readUTF(); + String[] parts = inData.split(","); + for(String part : parts) { + String[] pparts = part.split(":"); + if(pparts.length < 2) continue; + String pname = pparts[0]; + String pserver = pparts[1]; + AdaptedPlayer p = main.getPlatformMethods().getPlayer(pname); + String[] args = new String[1]; + args[0] = pserver; + moveCommand.execute(new PlayerSender(p), args); + } + } + if(subchannel.equals("queuename")) { + main.getPlatformMethods().sendPluginMessage(recievingPlayer, "queuename", main.getQueueManager().getQueuedName(recievingPlayer)); + } + if(subchannel.equals("position")) { + QueueServer server = main.getQueueManager().getSingleServer(recievingPlayer); + String pos = main.getMessages().getString("placeholders.position.none"); + if(server != null) { + pos = server.getQueue().indexOf(server.findPlayer(recievingPlayer))+1+""; + } + main.getPlatformMethods().sendPluginMessage(recievingPlayer, "position", pos); + } + if(subchannel.equals("positionof")) { + QueueServer server = main.getQueueManager().getSingleServer(recievingPlayer); + String pos = main.getMessages().getString("placeholders.position.none"); + if(server != null) { + pos = server.getQueue().size()+""; + } + main.getPlatformMethods().sendPluginMessage(recievingPlayer, "positionof", pos); + } + if(subchannel.equals("inqueue")) { + QueueServer server = main.getQueueManager().getSingleServer(recievingPlayer); + main.getPlatformMethods().sendPluginMessage(recievingPlayer, "inqueue", (server != null)+""); + } + if(subchannel.equals("queuedfor")) { + String srv = in.readUTF(); + QueueServer server = main.getQueueManager().findServer(srv); + if(server == null) return; + main.getPlatformMethods().sendPluginMessage(recievingPlayer, "queuedfor", srv, server.getQueue().size()+""); + } + if(subchannel.equals("leavequeue")) { + String[] args = new String[1]; + try { + args[0] = in.readUTF(); + } catch(Exception ignored) {} + leaveCommand.execute(new PlayerSender(recievingPlayer), args); + } + + } catch (IOException e1) { + main.getLogger().warning("An error occured while reading data from spigot side:"); + e1.printStackTrace(); + } + } + + @Override + public void onPlayerJoin(AdaptedPlayer player) { + ImmutableList queues = main.getQueueManager().findPlayerInQueues(player); + for(QueuePlayer queuePlayer : queues) { + queuePlayer.setPlayer(player); + } + if(queues.size() > 0) { + main.getQueueManager().sendMessage(main.getQueueManager().getSingleServer(player).findPlayer(player)); + } + } + + @Override + public void onPlayerLeave(AdaptedPlayer player) { + ImmutableList queues = main.getQueueManager().findPlayerInQueues(player); + for(QueuePlayer queuePlayer : queues) { + ((QueuePlayerImpl) queuePlayer).setLeaveTime(System.currentTimeMillis()); + List svs = main.getConfig().getStringList("queue-servers"); + for(String s : svs) { + if(!s.contains(":")) continue; + String[] parts = s.split(":"); + String from = parts[0]; + if(queuePlayer.getQueueServer().getServerNames().contains(from)) { + queuePlayer.getQueueServer().removePlayer(queuePlayer); + } + } + } + main.getQueueManager().clear(player); + } + + @Override + public void onPlayerJoinServer(AdaptedPlayer player) { + ImmutableList alreadyqueued = main.getQueueManager().findPlayerInQueues(player); + for(QueuePlayer queuePlayer : alreadyqueued) { + QueueServer server = queuePlayer.getQueueServer(); + int pos = queuePlayer.getPosition(); + if((pos <= 1 && server.getServerNames().contains(player.getServerName())) || main.getConfig().getBoolean("remove-player-on-server-switch")) { + server.removePlayer(player); + server.setLastSentTime(System.currentTimeMillis()); + } + } + + + String serverName = player.getServerName(); + List svs = main.getConfig().getStringList("queue-servers"); + for(String s : svs) { + if(!s.contains(":")) continue; + 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); + } + } + + } + + @Override + public void onServerKick(AdaptedPlayer player, AdaptedServer from, Component reason, boolean moving) { + + if(!player.isConnected()) return; + + String plainReason = PlainTextComponentSerializer.plainText().serialize(reason); + + if(!moving && main.getConfig().getBoolean("send-fail-debug")) { + main.getLogger().warning("Failed to send "+player.getName()+" to "+from.getName()+". Kicked with reason: "+plainReason); + } + + ImmutableList queuedServers = main.getQueueManager().getPlayerQueues(player); + if(!queuedServers.contains(main.getQueueManager().findServer(from.getName())) && main.getConfig().getBoolean("auto-add-to-queue-on-kick")) { + + List reasons = main.getConfig().getStringList("auto-add-kick-reasons"); + boolean shouldqueue = false; + for(String kickReason : reasons) { + if(plainReason.toLowerCase().contains(kickReason.toLowerCase())) { + shouldqueue = true; + break; + } + } + + if(shouldqueue || reasons.isEmpty()) { + main.getTaskManager().runLater(() -> { + if(!player.isConnected()) return; + + String toName = from.getName(); + player.sendMessage(main.getMessages().getComponent("auto-queued", "SERVER:"+toName)); + main.getQueueManager().addToQueue(player, toName); + }, (long) (main.getConfig().getDouble("auto-add-to-queue-on-kick-delay")*1000), TimeUnit.MILLISECONDS); + return; + } + + } + + + for(QueueServer server : queuedServers) { + if(!(server.getServerNames().contains(from.getName()))) continue; + QueuePlayer queuePlayer = server.findPlayer(player); + if(queuePlayer.getPosition() != 1) continue; + List kickReasons = main.getConfig().getStringList("kick-reasons"); + + for(String kickReason : kickReasons) { + if(plainReason.toLowerCase().contains(kickReason.toLowerCase())) { + server.removePlayer(queuePlayer); + } + } + } + } +} 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..8d27916 --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/common/QueueMain.java @@ -0,0 +1,198 @@ +package us.ajg0702.queue.common; + +import org.spongepowered.configurate.ConfigurateException; +import us.ajg0702.queue.api.*; +import us.ajg0702.queue.api.util.QueueLogger; +import us.ajg0702.queue.common.utils.LogConverter; +import us.ajg0702.queue.logic.LogicGetterImpl; +import us.ajg0702.utils.common.Config; +import us.ajg0702.utils.common.Messages; + +import java.io.File; +import java.util.LinkedHashMap; + +public class QueueMain { + + private static QueueMain instance; + public static QueueMain getInstance() { + return instance; + } + + private double timeBetweenPlayers; + public double getTimeBetweenPlayers() { + return timeBetweenPlayers; + } + public void setTimeBetweenPlayers() { + this.timeBetweenPlayers = config.getDouble("wait-time"); + } + + 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 final PlatformMethods platformMethods; + public PlatformMethods getPlatformMethods() { + return platformMethods; + } + + private final QueueLogger logger; + public QueueLogger getLogger() { + return logger; + } + + private final TaskManager taskManager = new TaskManager(this); + public TaskManager getTaskManager() { + return taskManager; + } + + private final EventHandler eventHandler = new EventHandlerImpl(this); + public EventHandler getEventHandler() { + return eventHandler; + } + + private QueueManager queueManager; + public QueueManager getQueueManager() { + return queueManager; + } + + private final LogicGetter logicGetter; + public LogicGetter getLogicGetter() { + return logicGetter; + } + + public void shutdown() { + taskManager.shutdown(); + } + + + private final File dataFolder; + + + public QueueMain(QueueLogger logger, PlatformMethods platformMethods, File dataFolder) { + + logicGetter = new LogicGetterImpl(); + + if(instance != null) { + try { + throw new Exception("ajQueue QueueMain is being initialized when there is already one! Still initializing it, but this can cause issues."); + } catch(Exception e) { + e.printStackTrace(); + } + } + instance = this; + + + this.logger = logger; + this.platformMethods = platformMethods; + this.dataFolder = dataFolder; + + constructMessages(); + + try { + config = new Config(dataFolder, new LogConverter(logger)); + } catch (ConfigurateException e) { + logger.warning("Unable to load config:"); + e.printStackTrace(); + return; + } + + setTimeBetweenPlayers(); + + queueManager = new QueueManagerImpl(this); + + logic = logicGetter.constructLogic(); + aliasManager = logicGetter.constructAliasManager(config); + + taskManager.rescheduleTasks(); + + } + + private void constructMessages() { + LinkedHashMap d = new LinkedHashMap<>(); + + d.put("status.offline.base", "&c{SERVER} is {STATUS}. &7You are in position &f{POS}&7 of &f{LEN}&7."); + + d.put("status.offline.offline", "offline"); + d.put("status.offline.restarting", "restarting"); + d.put("status.offline.full", "full"); + d.put("status.offline.restricted", "restricted"); + d.put("status.offline.paused", "paused"); + + d.put("status.online.base", "&7You are in position &f{POS}&7 of &f{LEN}&7. Estimated time: {TIME}"); + d.put("status.left-last-queue", "&aYou left the last queue you were in."); + 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("errors.server-not-exist", "&cThe server {SERVER} does not exist!"); + d.put("errors.already-queued", "&cYou are already queued for that server!"); + d.put("errors.player-only", "&cThis command can only be executed as a player!"); + d.put("errors.already-connected", "&cYou are already connected to this server!"); + d.put("errors.cant-join-paused", "&cYou cannot join the queue for {SERVER} because it is paused."); + d.put("errors.deny-joining-from-server", "&cYou are not allowed to join queues from this server!"); + + d.put("commands.leave-queue", "&aYou left the queue for {SERVER}!"); + d.put("commands.reload", "&aConfig and messages reloaded successfully!"); + d.put("commands.joinqueue.usage", "&cUsage: /joinqueue "); + + d.put("noperm", "&cYou do not have permission to do this!"); + + d.put("format.time.mins", "{m}m {s}s"); + d.put("format.time.secs", "{s} seconds"); + + d.put("list.format", "&b{SERVER} &7({COUNT}): {LIST}"); + d.put("list.playerlist", "&9{NAME}&7, "); + d.put("list.total", "&7Total players in queues: &f{TOTAL}"); + d.put("list.none", "&7None"); + + d.put("spigot.actionbar.online", "&7You are queued for &f{SERVER}&7. You are in position &f{POS}&7 of &f{LEN}&7. Estimated time: {TIME}"); + d.put("spigot.actionbar.offline", "&7You are queued for &f{SERVER}&7. &7You are in position &f{POS}&7 of &f{LEN}&7."); + + d.put("send", "&aAdded &f{PLAYER}&a to the queue for &f{SERVER}"); + d.put("remove", "&aRemoved &f{PLAYER} from all queues they were in."); + + d.put("placeholders.queued.none", "None"); + d.put("placeholders.position.none", "None"); + + d.put("commands.leave.more-args", "&cPlease specify which queue you want to leave! &7You are in these queues: {QUEUES}"); + d.put("commands.leave.queues-list-format", "&f{NAME}&7, "); + d.put("commands.leave.not-queued", "&cYou are not queued for that server! &7You are in these queues: {QUEUES}"); + d.put("commands.leave.no-queues", "&cYou are not queued!"); + + d.put("commands.pause.more-args", "&cUsage: /ajqueue pause [on/off]"); + d.put("commands.pause.no-server", "&cThat server does not exist!"); + d.put("commands.pause.success", "&aThe queue for &f{SERVER} &ais now {PAUSED}"); + d.put("commands.pause.paused.true", "&epaused"); + 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.listqueues.header", "&9Queues:"); + d.put("commands.listqueues.format", "{COLOR}{NAME}&7: {COUNT} queued"); + + d.put("max-tries-reached", "&cUnable to connect to {SERVER}. Max retries reached."); + d.put("auto-queued", "&aYou've been auto-queued for {SERVER} because you were kicked."); + + 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 new file mode 100644 index 0000000..d380ad0 --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/common/QueueManagerImpl.java @@ -0,0 +1,530 @@ +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.api.server.AdaptedServer; +import us.ajg0702.queue.common.players.QueuePlayerImpl; +import us.ajg0702.queue.common.queues.QueueServerImpl; +import us.ajg0702.utils.common.Messages; +import us.ajg0702.utils.common.TimeUtils; + +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.TimeUnit; + +public class QueueManagerImpl implements QueueManager { + + private List servers = new CopyOnWriteArrayList<>(); + + private final QueueMain main; + private final Messages msgs; + + public QueueManagerImpl(QueueMain main) { + this.main = main; + this.msgs = main.getMessages(); + + int delay = main.getConfig().getBoolean("wait-to-load-servers") ? main.getConfig().getInt("wait-to-load-servers-delay") : 0; + + main.getTaskManager().runLater(this::reloadServers, delay, TimeUnit.MILLISECONDS); + } + + public List buildServers() { + List result = new ArrayList<>(); + List servers = main.getPlatformMethods().getServers(); + + for(AdaptedServer server : servers) { + QueueServer previousServer = main.getQueueManager().findServer(server.getName()); + List previousPlayers = previousServer == null ? new ArrayList<>() : previousServer.getQueue(); + if(previousPlayers.size() > 0) { + main.getLogger().info("Adding "+previousPlayers.size()+" players back to the queue for "+server.getName()); + } + QueueServer queueServer = new QueueServerImpl(server.getName(), main, server, previousPlayers); + if(previousServer != null) { + queueServer.setPaused(previousServer.isPaused()); + queueServer.setLastSentTime(previousServer.getLastSentTime()); + } + result.add(queueServer); + } + + return result; + } + + @Override + public boolean addToQueue(AdaptedPlayer player, QueueServer server) { + 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; + int maxOfflineTime = player.hasPermission("ajqueue.stayqueued") ? 60 : 0; + queuePlayer = new QueuePlayerImpl(player, server, priority, maxOfflineTime); + 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(player); + 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() + ) + ); + } + + if(!server.isJoinable(player)) { + sendMessage(queuePlayer); + } + main.getPlatformMethods().sendPluginMessage(player, "position", pos+""); + main.getPlatformMethods().sendPluginMessage(player, "positionof", len+""); + main.getPlatformMethods().sendPluginMessage(player, "queuename", server.getAlias()); + main.getPlatformMethods().sendPluginMessage(player, "inqueue", "true"); + main.getPlatformMethods().sendPluginMessage(player, "inqueueevent", "true"); + return true; + } + + @Override + public boolean addToQueue(AdaptedPlayer player, String serverName) { + QueueServer server = findServer(serverName); + if(server == null) { + player.sendMessage(msgs.getComponent("errors.server-not-exist", "SERVER:"+serverName)); + return false; + } + return addToQueue(player, server); + } + + @Override + public ImmutableList getServers() { + 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) { + QueueServer server = getSingleServer(player); + if(server == null) return main.getMessages().getString("placeholders.queued.none"); + return server.getName(); + } + + @Override + public void reloadServers() { + if(main.getConfig() == null) { + main.getLogger().severe("[MAN] Config is null"); + } + + List oldServers = ImmutableList.copyOf(servers); + + servers = buildServers(); + + 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; + } + + List groupServers = new ArrayList<>(); + + for(String serverraw : serversraw) { + QueueServer found = findServer(serverraw); + if(found == null) { + main.getLogger().warning("Could not find server named '"+serverraw+"' in servergroup '"+groupName+"'!"); + continue; + } + if(found.isGroup()) continue; + + groupServers.add(found.getServers().get(0)); + } + + if(servers.size() == 0) { + main.getLogger().warning("Server group '"+groupName+"' has no servers! Ignoring it."); + continue; + } + + + final List previousPlayers = new ArrayList<>(); + oldServers.forEach(queueServer -> { + if(queueServer.getName().equals(groupName)) { + previousPlayers.addAll(queueServer.getQueue()); + } + }); + + this.servers.add(new QueueServerImpl(groupName, main, groupServers, previousPlayers)); + } + } + + @Override + public void sendActionBars() { + if(!main.getConfig().getBoolean("send-actionbar")) return; + + for(QueueServer server : servers) { + String status = server.getStatusString(); + for(QueuePlayer queuePlayer : server.getQueue()) { + + int pos = queuePlayer.getPosition(); + if(pos == 0) { + server.removePlayer(queuePlayer); + continue; + } + + AdaptedPlayer player = queuePlayer.getPlayer(); + if(player == null) continue; + + if(!getSingleServer(player).equals(server)) continue; + + if(!server.isJoinable(player)) { + player.sendActionBar(msgs.getComponent("spigot.actionbar.offline", + "POS:"+pos, + "LEN:"+server.getQueue().size(), + "SERVER:"+server.getAlias(), + "STATUS:"+status + )); + } else { + int time = (int) Math.round(pos * main.getTimeBetweenPlayers()); + player.sendActionBar(msgs.getComponent("spigot.actionbar.online", + "POS:"+pos, + "LEN:"+server.getQueue().size(), + "SERVER:"+server.getAlias(), + "TIME:"+ TimeUtils.timeString(time, msgs.getString("format.time.mins"), msgs.getString("format.time.secs")) + )); + } + } + } + } + + @Override + public void sendQueueEvents() { + List svs = main.getConfig().getStringList("queue-servers"); + for(String s : svs) { + if(!s.contains(":")) continue; + String[] parts = s.split(":"); + String fromName = parts[0]; + String toName = parts[1]; + AdaptedServer from = main.getPlatformMethods().getServer(fromName); + QueueServer to = findServer(toName); + if(from == null || to == null) continue; + from.getPlayers().forEach(player -> { + if(!getPlayerQueues(player).contains(to)) { + addToQueue(player, to); + } + }); + } + for (QueueServer s : servers) { + for (QueuePlayer queuePlayer : s.getQueue()) { + AdaptedPlayer player = queuePlayer.getPlayer(); + if (player == null || !player.isConnected()) continue; + main.getPlatformMethods().sendPluginMessage(player, "inqueueevent", "true"); + } + } + } + + @Override + public void sendMessages() { + try { + for(QueueServer server : servers) { + for(QueuePlayer queuePlayer : server.getQueue()) { + sendMessage(queuePlayer); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void sendMessage(QueuePlayer queuePlayer) { + AdaptedPlayer player = queuePlayer.getPlayer(); + if(player == null || !player.isConnected()) return; + + QueueServer server = queuePlayer.getQueueServer(); + + int pos = queuePlayer.getPosition(); + int len = server.getQueue().size(); + + if(!server.isJoinable(player)) { + String status = server.getStatusString(player); + + if(msgs.getString("status.offline.base").isEmpty()) return; + + player.sendMessage(msgs.getComponent("status.offline.base", + "STATUS:"+status, + "POS:"+pos, + "LEN:"+len, + "SERVER:"+server.getAlias() + )); + } else { + if(msgs.getString("status.online.base").isEmpty()) return; + int time = (int) Math.round(pos * main.getTimeBetweenPlayers()); + player.sendMessage(msgs.getComponent("status.online.base", + "TIME:" + TimeUtils.timeString(time, msgs.getString("format.time.mins"), msgs.getString("format.time.secs")), + "POS:"+pos, + "LEN:"+len, + "SERVER:"+server.getAlias() + )); + } + } + + @Override + public void updateServers() { + try { + for(QueueServer server : servers) { + server.updatePing(); + } + } catch(Exception e) { + e.printStackTrace(); + } + } + + @Override + public QueueServer findServer(String name) { + for(QueueServer server : servers) { + if(server == null) continue; + if(server.getName().equalsIgnoreCase(name)) { + return server; + } + } + return null; + } + + @Override + public void sendPlayers() { + sendPlayers(null); + } + + final HashMap sendingNowAntiSpam = new HashMap<>(); + final HashMap sendingAttempts = new HashMap<>(); + + @Override + public void sendPlayers(QueueServer queueServer) { + List sendingServers; + if(queueServer == null) { + sendingServers = new ArrayList<>(servers); + } else { + sendingServers = Collections.singletonList(queueServer); + } + + for(QueueServer server : sendingServers) { + for(QueuePlayer queuePlayer : server.getQueue()) { + if(queuePlayer.getPlayer() != null) continue; + if(main.getLogic().playerDisconnectedTooLong(queuePlayer)) { + server.removePlayer(queuePlayer); + } + } + if(!server.isOnline()) continue; + if(server.getQueue().size() == 0) continue; + + if(main.getConfig().getBoolean("send-all-when-back-online") && server.justWentOnline() && server.isOnline()) { + for(QueuePlayer p : server.getQueue()) { + AdaptedPlayer player = p.getPlayer(); + if(player == null) continue; + + if(server.isFull() && !p.getPlayer().hasPermission("ajqueue.joinfull")) continue; + + AdaptedServer selected = server.getIdealServer(player); + if(selected == null) { + main.getLogger().severe("Could not find ideal server for server/group '"+server.getName()+"'!"); + continue; + } + + player.sendMessage(msgs.getComponent("status.sending-now", "SERVER:"+server.getAlias())); + player.connect(selected); + } + continue; + } + + QueuePlayer nextQueuePlayer = server.getQueue().get(0); + AdaptedPlayer nextPlayer = nextQueuePlayer.getPlayer(); + + + // 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()) { + if(nextPlayer != null) { // Remove them if they are already in the server + server.removePlayer(nextQueuePlayer); + if(server.getQueue().size() > i) { + nextQueuePlayer = server.getQueue().get(i); + nextPlayer = nextQueuePlayer.getPlayer(); + } else { + nextPlayer = null; + break; + } + } else { + i++; + nextQueuePlayer = server.getQueue().get(i); + nextPlayer = nextQueuePlayer.getPlayer(); + } + } + + if(nextPlayer == null) continue; // None of the players in the queue are online + + if(!server.canAccess(nextPlayer)) continue; + + if(server.isFull() && !nextPlayer.hasPermission("ajqueue.joinfull")) continue; + + if(main.getConfig().getBoolean("enable-bypasspaused-permission")) { + if(server.isPaused() && !nextPlayer.hasPermission("ajqueue.bypasspaused")) continue; + } else if(server.isPaused()) { continue; } + + int tries = sendingAttempts.get(nextQueuePlayer) == null ? 0 : sendingAttempts.get(nextQueuePlayer); + int maxTries = main.getConfig().getInt("max-tries"); + if(tries >= maxTries && maxTries > 0) { + server.removePlayer(nextQueuePlayer); + sendingAttempts.remove(nextQueuePlayer); + nextPlayer.sendMessage(msgs.getComponent("max-tries-reached", "SERVER:"+server.getAlias())); + continue; + } + tries++; + sendingAttempts.put(nextQueuePlayer, tries); + + if(!sendingNowAntiSpam.containsKey(nextPlayer)) { + sendingNowAntiSpam.put(nextPlayer, (long) 0); + } + if(System.currentTimeMillis() - sendingNowAntiSpam.get(nextPlayer) >= 5000) { + nextPlayer.sendMessage(msgs.getComponent("status.sending-now", "SERVER:"+server.getAlias())); + sendingNowAntiSpam.put(nextPlayer, System.currentTimeMillis()); + } + + AdaptedServer selected = server.getIdealServer(nextPlayer); + if(selected == null) { + main.getLogger().severe("Could not find ideal server for server/group '"+server.getName()+"'"); + continue; + } + server.setLastSentTime(System.currentTimeMillis()); + nextPlayer.connect(selected); + } + } + + @Override + public ImmutableList findPlayerInQueues(AdaptedPlayer p) { + List srs = new ArrayList<>(); + for(QueueServer s : servers) { + QueuePlayer player = s.findPlayer(p); + if(player != null) { + srs.add(player); + } + } + return ImmutableList.copyOf(srs); + } + + @Override + public ImmutableList getPlayerQueues(AdaptedPlayer p) { + List srs = new ArrayList<>(); + for(QueueServer s : servers) { + QueuePlayer player = s.findPlayer(p); + if(player != null) { + srs.add(s); + } + } + return ImmutableList.copyOf(srs); + } + + @Override + public void clear(AdaptedPlayer player) { + sendingNowAntiSpam.remove(player); + } +} diff --git a/common/src/main/java/us/ajg0702/queue/common/TaskManager.java b/common/src/main/java/us/ajg0702/queue/common/TaskManager.java new file mode 100644 index 0000000..2db235f --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/common/TaskManager.java @@ -0,0 +1,128 @@ +package us.ajg0702.queue.common; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +public class TaskManager { + + + final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); + final ScheduledExecutorService updateExecutor = Executors.newScheduledThreadPool(1); + + final QueueMain main; + public TaskManager(QueueMain main) { + this.main = main; + } + + public void shutdown() { + executor.shutdown(); + updateExecutor.shutdown(); + } + + public String taskStatus() { + List> tasks = Arrays.asList(sendTask, updateTask, messageTask, actionBarTask, queueEventTask, reloadServerTask); + StringBuilder sb = new StringBuilder(); + for(ScheduledFuture task : tasks) { + sb.append(task == null ? "null" : task.isDone() ? "canceled/done" : "running"); + sb.append("\n"); + } + return sb.toString(); + } + + ScheduledFuture sendTask; + ScheduledFuture updateTask; + ScheduledFuture messageTask; + ScheduledFuture actionBarTask; + ScheduledFuture queueEventTask; + ScheduledFuture reloadServerTask; + public void rescheduleTasks() { + cancelTasks(); + + sendTask = scheduleAtFixedRate( + main.getQueueManager()::sendPlayers, + (long) (main.getConfig().getDouble("wait-time")*1000L), + TimeUnit.MILLISECONDS + ); + + updateTask = scheduleAtFixedRate(updateExecutor, + main.getQueueManager()::updateServers, + 500L, + (long) (Math.max(main.getTimeBetweenPlayers(), 2)*1000L), + TimeUnit.MILLISECONDS + ); + + messageTask = scheduleAtFixedRate( + main.getQueueManager()::sendMessages, + main.getConfig().getInt("message-time"), + TimeUnit.SECONDS + ); + + actionBarTask = scheduleAtFixedRate( + main.getQueueManager()::sendActionBars, + 1500L, + TimeUnit.MILLISECONDS + ); + + queueEventTask = scheduleAtFixedRate( + main.getQueueManager()::sendQueueEvents, + 1500L, + TimeUnit.MILLISECONDS + ); + + if(main.getConfig().getInt("reload-servers-interval") > 0) { + reloadServerTask = scheduleAtFixedRate( + main.getQueueManager()::reloadServers, + main.getConfig().getInt("reload-servers-interval"), + TimeUnit.SECONDS + ); + } + + } + + public void cancelTasks() { + if(sendTask != null && !sendTask.isCancelled()) { + sendTask.cancel(true); + } + if(updateTask != null && !updateTask.isCancelled()) { + updateTask.cancel(true); + } + if(messageTask != null && !messageTask.isCancelled()) { + messageTask.cancel(true); + } + if(actionBarTask != null && !actionBarTask.isCancelled()) { + actionBarTask.cancel(true); + } + if(queueEventTask != null && !queueEventTask.isCancelled()) { + queueEventTask.cancel(true); + } + if(reloadServerTask != null && !reloadServerTask.isCancelled()) { + reloadServerTask.cancel(true); + reloadServerTask = null; + } + } + + private ScheduledFuture scheduleAtFixedRate(Runnable command, long period, TimeUnit unit) { + return scheduleAtFixedRate(executor, command, 0, period, unit); + } + + @SuppressWarnings("UnusedReturnValue") + public ScheduledFuture runLater(Runnable runnable, long delay, TimeUnit unit) { + return executor.schedule(runnable, delay, unit); + } + + + private ScheduledFuture scheduleAtFixedRate(ScheduledExecutorService executor, Runnable command, long initialDelay, long period, TimeUnit unit) { + return executor.scheduleAtFixedRate(() -> { + try { + command.run(); + } catch (Exception e) { + System.out.println("An error ocurred while running an ajQueue task"); + e.printStackTrace(); + } + }, initialDelay, period, unit); + } +} 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..5c1b619 --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/common/players/QueuePlayerImpl.java @@ -0,0 +1,110 @@ +package us.ajg0702.queue.common.players; + +import org.jetbrains.annotations.NotNull; +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; + private final String name; + + private final int maxOfflineTime; + + public QueuePlayerImpl(UUID uuid, String name, QueueServer server, int highestPriority, int maxOfflineTime) { + this(null, name, uuid, server, highestPriority, maxOfflineTime); + } + + public QueuePlayerImpl(AdaptedPlayer player, QueueServer server, int highestPriority, int maxOfflineTime) { + this(player, player.getName(), player.getUniqueId(), server, highestPriority, maxOfflineTime); + } + + private QueuePlayerImpl(@Nullable AdaptedPlayer player, String name, @NotNull UUID uuid, QueueServer server, int highestPriority, int maxOfflineTime) { + this.player = player; + this.server = server; + + this.highestPriority = highestPriority; + + this.uuid = uuid; + this.name = name; + + this.maxOfflineTime = maxOfflineTime; + } + + @Override + public UUID getUniqueId() { + if(uuid == null) throw new IllegalStateException("Why is my UUID null??"); + 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 != null && !player.isConnected()) player = null; + return player; + } + + @Override + public void setPlayer(AdaptedPlayer player) { + if(player != null && !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; + } + + @Override + public String getName() { + return name; + } + + + + @Override + public long getTimeSinceOnline() { + if(player != null && player.isConnected()) { + return 0; + } + return System.currentTimeMillis()-leaveTime; + } + + @Override + public int getMaxOfflineTime() { + return maxOfflineTime; + } + + + private long leaveTime = 0; + public void setLeaveTime(long leaveTime) { + this.leaveTime = 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 new file mode 100644 index 0000000..2238771 --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/common/queues/QueueServerImpl.java @@ -0,0 +1,383 @@ +package us.ajg0702.queue.common.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.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.players.QueuePlayerImpl; +import us.ajg0702.utils.common.GenUtils; +import us.ajg0702.utils.common.Messages; + +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class QueueServerImpl implements QueueServer { + + private final String name; + + public QueueServerImpl(String name, QueueMain main, AdaptedServer server, List previousPlayers) { + this(name, main, Collections.singletonList(server), previousPlayers); + } + + public QueueServerImpl(String name, QueueMain main, List servers, List previousPlayers) { + this.name = name; + this.servers = servers; + this.main = main; + + for(QueuePlayer queuePlayer : previousPlayers) { + if(queuePlayer.getPlayer() == null) { + addPlayer( + new QueuePlayerImpl( + queuePlayer.getUniqueId(), + queuePlayer.getName(), + this, + queuePlayer.getPriority(), + queuePlayer.getMaxOfflineTime() + ) + ); + } else { + addPlayer( + new QueuePlayerImpl( + queuePlayer.getPlayer(), + this, + queuePlayer.getPriority(), + queuePlayer.getMaxOfflineTime() + ) + ); + } + } + } + + private final QueueMain main; + + private final HashMap pings = new HashMap<>(); + + private final List servers; + + private final List queue = new ArrayList<>(); + + + private int playerCount; + private int maxPlayers; + + private boolean online; + + private boolean paused; + + + private long lastUpdate = 0; + + private int offlineTime = 0; + + private long lastSentTime = 0; + + private long lastOffline; + + + boolean whitelisted = false; + List whitelistedUUIDs = new ArrayList<>(); + + + @Override + public ImmutableList getQueue() { + return ImmutableList.copyOf(queue); + } + + @Override + public String getStatusString(AdaptedPlayer p) { + Messages msgs = main.getMessages(); + + if(getOfflineTime() > main.getConfig().getInt("offline-time")) { + return msgs.getString("status.offline.offline"); + } + + if(!isOnline()) { + return msgs.getString("status.offline.restarting"); + } + + if(isPaused()) { + return msgs.getString("status.offline.paused"); + } + + if(isFull()) { + return msgs.getString("status.offline.full"); + } + + if(p != null && !canAccess(p)) { + return msgs.getString("status.offline.restricted"); + } + + + return "online"; + } + + @Override + public String getStatusString() { + return getStatusString(null); + } + + @Override + public void updatePing() { + HashMap> pingsFutures = new HashMap<>(); + for(AdaptedServer server : servers) { + if(main.getConfig().getBoolean("pinger-debug")) { + main.getLogger().info("[pinger] ["+server.getServerInfo().getName()+"] sending ping"); + } + pingsFutures.put(server, server.ping()); + } + + int i = 0; + for(AdaptedServer server : pingsFutures.keySet()) { + CompletableFuture futurePing = pingsFutures.get(server); + AdaptedServerPing ping = null; + try { + ping = futurePing.get(5, TimeUnit.SECONDS); + } catch (InterruptedException | ExecutionException | TimeoutException e) { + if(main.getConfig().getBoolean("pinger-debug")) { + main.getLogger().info("[pinger] ["+server.getServerInfo().getName()+"] offline:"); + e.printStackTrace(); + } + } + if(ping != null && main.getConfig().getBoolean("pinger-debug")) { + main.getLogger().info("[pinger] ["+server.getServerInfo().getName()+"] online. motd: "+ping.getPlainDescription()+" players: "+ping.getPlayerCount()+"/"+ping.getMaxPlayers()); + } + + pings.put(server, ping); + i++; + if(i == servers.size()) { + int onlineCount = 0; + playerCount = 0; + maxPlayers = 0; + for(AdaptedServer pingedServer : pings.keySet()) { + AdaptedServerPing serverPing = pings.get(pingedServer); + if(serverPing == null) { + continue; + } + onlineCount++; + playerCount += serverPing.getPlayerCount(); + maxPlayers += serverPing.getMaxPlayers(); + } + online = onlineCount > 0; + + if(lastUpdate == -1) { + lastUpdate = System.currentTimeMillis(); + offlineTime = 0; + } else { + int timesincelast = (int) Math.round((System.currentTimeMillis() - lastUpdate*1.0)/1000); + lastUpdate = System.currentTimeMillis(); + if(!online) { + offlineTime += timesincelast; + } else { + offlineTime = 0; + } + } + } + } + } + + @Override + public int getOfflineTime() { + return offlineTime; + } + + @Override + public long getLastSentTime() { + return System.currentTimeMillis() - lastSentTime; + } + @Override + public void setLastSentTime(long lastSentTime) { + this.lastSentTime = lastSentTime; + } + + @Override + public boolean isWhitelisted() { + return whitelisted; + } + + @Override + public void setWhitelisted(boolean whitelisted) { + this.whitelisted = whitelisted; + } + + @Override + public ImmutableList getWhitelistedPlayers() { + return ImmutableList.copyOf(whitelistedUUIDs); + } + + @Override + public synchronized void setWhitelistedPlayers(List whitelistedPlayers) { + whitelistedUUIDs = whitelistedPlayers; + } + + @Override + public boolean isJoinable(AdaptedPlayer p) { + return (!whitelisted || whitelistedUUIDs.contains(p.getUniqueId())) && + this.isOnline() && + this.canAccess(p) && + !this.isFull() && + !this.isPaused(); + } + + @Override + public synchronized void setPaused(boolean paused) { + this.paused = paused; + } + + @Override + public boolean isPaused() { + return paused; + } + + @Override + public boolean isOnline() { + if(System.currentTimeMillis()-lastOffline <= (main.getConfig().getInt("wait-after-online")*1000) && online) { + return false; + } + if(!online) { + lastOffline = System.currentTimeMillis(); + } + return online; + } + + @Override + public boolean justWentOnline() { + return System.currentTimeMillis()-lastOffline <= (main.getConfig().getDouble("wait-time")) && online; + } + + @Override + public boolean isFull() { + return playerCount >= maxPlayers; + } + + @Override + public synchronized void removePlayer(QueuePlayer player) { + queue.remove(player); + } + + @Override + public void removePlayer(AdaptedPlayer player) { + QueuePlayer queuePlayer = findPlayer(player); + if(queuePlayer == null) return; + removePlayer(queuePlayer); + } + + @Override + public void addPlayer(QueuePlayer player) { + addPlayer(player, -1); + } + + @Override + public synchronized void addPlayer(QueuePlayer player, int position) { + if(!player.getQueueServer().equals(this) || queue.contains(player)) return; + + if(position >= 0) { + queue.add(position, player); + } else { + queue.add(player); + } + } + + @Override + public void sendPlayer() { + main.getQueueManager().sendPlayers(this); + } + + @Override + public String getName() { + return name; + } + + @Override + public boolean canAccess(AdaptedPlayer ply) { + if(ply == null) return true; + for(AdaptedServer si : servers) { + if(si.canAccess(ply)) { + return true; + } + } + return false; + } + + @Override + public String getAlias() { + return main.getAliasManager().getAlias(getName()); + } + + @Override + public ImmutableList getServers() { + return ImmutableList.copyOf(servers); + } + + @Override + public ImmutableList getServerNames() { + List names = new ArrayList<>(); + for(AdaptedServer server : servers) { + names.add(server.getName()); + } + return ImmutableList.copyOf(names); + } + + @Override + public boolean isGroup() { + return servers.size() > 1; + } + + @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; + } + + @Override + public AdaptedServer getIdealServer(AdaptedPlayer player) { + HashMap serverInfos = pings; + AdaptedServer selected = null; + int selectednum = 0; + if(serverInfos.keySet().size() == 1) { + selected = serverInfos.keySet().iterator().next(); + } else { + for(AdaptedServer si : serverInfos.keySet()) { + AdaptedServerPing sp = serverInfos.get(si); + if(sp == null) continue; + int online = sp.getPlayerCount(); + if(selected == null) { + selected = si; + selectednum = online; + continue; + } + if(selectednum > online && main.getQueueManager().findServer(si.getName()).isJoinable(player)) { + selected = si; + selectednum = online; + } + } + } + if(selected == null && serverInfos.size() > 0) { + selected = serverInfos.keySet().iterator().next(); + } + if(selected == null) { + main.getLogger().warning("Unable to find ideal server, using random server from group."); + int r = GenUtils.randomInt(0, getServers().size()-1); + selected = getServers().get(r); + } + return selected; + } + + @Override + public HashMap getLastPings() { + return new HashMap<>(pings); + } +} diff --git a/common/src/main/java/us/ajg0702/queue/common/utils/LogConverter.java b/common/src/main/java/us/ajg0702/queue/common/utils/LogConverter.java new file mode 100644 index 0000000..3e9449d --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/common/utils/LogConverter.java @@ -0,0 +1,32 @@ +package us.ajg0702.queue.common.utils; + +import org.jetbrains.annotations.NotNull; +import us.ajg0702.queue.api.util.QueueLogger; + +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +public class LogConverter extends Logger { + private final QueueLogger logger; + public LogConverter(QueueLogger logger) { + super("ajqueue-convert", null); + this.logger = logger; + } + + @Override + public void log(@NotNull LogRecord logRecord) { + String message = logRecord.getMessage(); + switch(logRecord.getLevel().getName()) { + case "OFF": + break; + case "SEVERE": + logger.error(message); + case "WARNING": + logger.warn(message); + case "INFO": + logger.info(message); + default: + logger.info(message); + } + } +} diff --git a/common/src/main/java/us/ajg0702/queue/logic/FreeAliasManager.java b/common/src/main/java/us/ajg0702/queue/logic/FreeAliasManager.java new file mode 100644 index 0000000..8c1a812 --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/logic/FreeAliasManager.java @@ -0,0 +1,22 @@ +package us.ajg0702.queue.logic; + +import us.ajg0702.queue.api.AliasManager; +import us.ajg0702.utils.common.Config; + +public class FreeAliasManager implements AliasManager { + @SuppressWarnings("unused") + final Config config; + public FreeAliasManager(Config config) { + this.config = config; + } + + @Override + public String getAlias(String server) { + return server; + } + + @Override + public String getServer(String alias) { + return alias; + } +} diff --git a/common/src/main/java/us/ajg0702/queue/logic/FreeLogic.java b/common/src/main/java/us/ajg0702/queue/logic/FreeLogic.java new file mode 100644 index 0000000..6e26917 --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/logic/FreeLogic.java @@ -0,0 +1,23 @@ +package us.ajg0702.queue.logic; + +import us.ajg0702.queue.api.Logic; +import us.ajg0702.queue.api.players.AdaptedPlayer; +import us.ajg0702.queue.api.players.QueuePlayer; +import us.ajg0702.queue.api.queues.QueueServer; + +public class FreeLogic implements Logic { + @Override + public boolean isPremium() { + return false; + } + + @Override + public QueuePlayer priorityLogic(QueueServer server, AdaptedPlayer player) { + return null; + } + + @Override + public boolean playerDisconnectedTooLong(QueuePlayer player) { + return player.getMaxOfflineTime() < player.getTimeSinceOnline()*1000; + } +} diff --git a/common/src/main/java/us/ajg0702/queue/logic/LogicGetterImpl.java b/common/src/main/java/us/ajg0702/queue/logic/LogicGetterImpl.java new file mode 100644 index 0000000..37598cc --- /dev/null +++ b/common/src/main/java/us/ajg0702/queue/logic/LogicGetterImpl.java @@ -0,0 +1,26 @@ +package us.ajg0702.queue.logic; + +import us.ajg0702.queue.api.AliasManager; +import us.ajg0702.queue.api.Logic; +import us.ajg0702.queue.api.players.AdaptedPlayer; +import us.ajg0702.utils.common.Config; + +import java.util.List; + +public class LogicGetterImpl implements us.ajg0702.queue.api.LogicGetter { + + @Override + public Logic constructLogic() { + return new FreeLogic(); + } + + @Override + public AliasManager constructAliasManager(Config config) { + return new FreeAliasManager(config); + } + + @Override + public List getPermissions(AdaptedPlayer player) { + return null; + } +} diff --git a/src/main/resources/config.yml b/common/src/main/resources/config.yml similarity index 94% rename from src/main/resources/config.yml rename to common/src/main/resources/config.yml index c3cf109..319edb8 100644 --- a/src/main/resources/config.yml +++ b/common/src/main/resources/config.yml @@ -1,5 +1,5 @@ # Dont touch this number please -config-version: 21 +config-version: 22 # The time the server will wait between sending people in the queue # Default: 5 @@ -16,7 +16,7 @@ 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 survivalqueue server, they will auto-join the queue for survival queue-servers: -- 'survivalqueue:survival' + - 'survivalqueue:survival' # 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. @@ -26,8 +26,8 @@ send-actionbar: true # 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' + - 'banned' + - 'blacklisted' # Should we remove a player from the queue if they move servers? @@ -80,7 +80,7 @@ multi-server-queue-pick: last # 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" + - "event-a:Event A" # How long should we wait after a server is online before sending players? @@ -117,7 +117,7 @@ joinfrom-server-permission: false # 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" + - "lobbys:lobby-1,lobby-2,lobby-3" # Should we allow tab-completing in the /queue command? @@ -130,7 +130,7 @@ tab-complete-queues: true # This also works with group # NOTE: Server names are caps sensitive send-instantly: -- "lobbys" + - "lobbys" # Should we log to the bungeecord 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 @@ -170,5 +170,10 @@ auto-add-to-queue-on-kick-delay: 1 # 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. auto-add-kick-reasons: -- "restarting" -- "closed" \ No newline at end of file + - "restarting" + - "closed" + +# 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 +enable-server-command: false \ No newline at end of file diff --git a/free/build.gradle.kts b/free/build.gradle.kts new file mode 100644 index 0000000..289c987 --- /dev/null +++ b/free/build.gradle.kts @@ -0,0 +1,63 @@ +plugins { + `java-library` + id("com.github.johnrengelman.shadow") + `maven-publish` +} + +group = "us.ajg0702.queue" + +repositories { + //mavenLocal() + mavenCentral() + maven { url = uri("https://repo.ajg0702.us") } + maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") } +} + +dependencies { + compileOnly("net.kyori:adventure-api:4.8.1") + compileOnly("com.google.guava:guava:30.1.1-jre") + compileOnly("org.spongepowered:configurate-yaml:4.0.0") + + implementation("us.ajg0702:ajUtils:1.1.7") + + implementation(project(":platforms:velocity")) + implementation(project(":platforms:bungeecord")) + + implementation(project(":spigot")) +} + +tasks.shadowJar { + relocate("us.ajg0702.utils", "us.ajg0702.queue.libs.utils") + relocate("org.bstats", "us.ajg0702.queue.libs.bstats") + //relocate("net.kyori", "us.ajg0702.queue.libs.kyori") + relocate("io.leangen.geantyref", "us.ajg0702.queue.libs.geantyref") + relocate("org.spongepowered", "us.ajg0702.queue.libs.sponge") + relocate("org.yaml", "us.ajg0702.queue.libs.yaml") + archiveBaseName.set("ajQueue") + archiveClassifier.set("") +} + +publishing { + publications { + create("mavenJava") { + artifact(tasks["jar"]) + } + } + + repositories { + + val mavenUrl = "https://repo.ajg0702.us/releases" + + if(!System.getenv("REPO_TOKEN").isNullOrEmpty()) { + maven { + url = uri(mavenUrl) + name = "ajRepo" + + credentials { + username = "plugins" + password = System.getenv("REPO_TOKEN") + } + } + } + } +} \ No newline at end of file diff --git a/platforms/bungeecord/build.gradle.kts b/platforms/bungeecord/build.gradle.kts new file mode 100644 index 0000000..136f1e8 --- /dev/null +++ b/platforms/bungeecord/build.gradle.kts @@ -0,0 +1,71 @@ +plugins { + `java-library` + `maven-publish` +} + +group = "us.ajg0702.queue.platforms.bungeecord" + +repositories { + //mavenLocal() + mavenCentral() + maven { url = uri("https://repo.ajg0702.us") } + maven { url = uri("https://nexus.velocitypowered.com/repository/maven-public/") } +} + +dependencies { + compileOnly("net.kyori:adventure-api:4.8.1") + compileOnly("com.google.guava:guava:30.1.1-jre") + compileOnly("us.ajg0702:ajUtils:1.1.7") + + compileOnly("net.md-5:bungeecord-api:1.16-R0.4") + + compileOnly("net.kyori:adventure-text-minimessage:4.0.0-SNAPSHOT") + + implementation("net.kyori:adventure-platform-bungeecord:4.0.0-SNAPSHOT") + compileOnly("net.kyori:adventure-text-serializer-plain:4.0.0-SNAPSHOT") + + implementation("org.bstats:bstats-bungeecord:2.2.1") + + implementation(project(":common")) + implementation(project(":api")) +} + + +tasks.withType { + from(sourceSets.main.get().java.srcDirs) + filter( + "tokens" to mapOf( + "VERSION" to project.version.toString() + ) + ).into("$buildDir/src") +} + +tasks.jar { + exclude("**/*.java") +} + + +publishing { + publications { + create("mavenJava") { + artifact(tasks["jar"]) + } + } + + repositories { + + val mavenUrl = "https://repo.ajg0702.us/releases" + + if(!System.getenv("REPO_TOKEN").isNullOrEmpty()) { + maven { + url = uri(mavenUrl) + name = "ajRepo" + + credentials { + username = "plugins" + password = System.getenv("REPO_TOKEN") + } + } + } + } +} \ No newline at end of file diff --git a/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/BungeeLogger.java b/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/BungeeLogger.java new file mode 100644 index 0000000..51dc44b --- /dev/null +++ b/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/BungeeLogger.java @@ -0,0 +1,39 @@ +package us.ajg0702.queue.platforms.bungeecord; + +import us.ajg0702.queue.api.util.QueueLogger; + +import java.util.logging.Logger; + +public class BungeeLogger implements QueueLogger { + + private final Logger logger; + + protected BungeeLogger(Logger logger) { + this.logger = logger; + } + + @Override + public void warn(String message) { + logger.warning(message); + } + + @Override + public void warning(String message) { + logger.warning(message); + } + + @Override + public void info(String message) { + logger.info(message); + } + + @Override + public void error(String message) { + logger.severe(message); + } + + @Override + public void severe(String message) { + logger.severe(message); + } +} diff --git a/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/BungeeMethods.java b/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/BungeeMethods.java new file mode 100644 index 0000000..9a6ef6e --- /dev/null +++ b/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/BungeeMethods.java @@ -0,0 +1,122 @@ +package us.ajg0702.queue.platforms.bungeecord; + +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; +import net.md_5.bungee.api.ProxyServer; +import net.md_5.bungee.api.config.ServerInfo; +import net.md_5.bungee.api.connection.ProxiedPlayer; +import us.ajg0702.queue.api.PlatformMethods; +import us.ajg0702.queue.api.commands.IBaseCommand; +import us.ajg0702.queue.api.commands.ICommandSender; +import us.ajg0702.queue.api.players.AdaptedPlayer; +import us.ajg0702.queue.api.server.AdaptedServer; +import us.ajg0702.queue.api.util.QueueLogger; +import us.ajg0702.queue.commands.commands.PlayerSender; +import us.ajg0702.queue.platforms.bungeecord.players.BungeePlayer; +import us.ajg0702.queue.platforms.bungeecord.server.BungeeServer; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Locale; + +public class BungeeMethods implements PlatformMethods { + + final ProxyServer proxyServer; + final QueueLogger logger; + final BungeeQueue plugin; + + public BungeeMethods(BungeeQueue plugin, ProxyServer proxyServer, QueueLogger logger) { + this.proxyServer = proxyServer; + this.logger = logger; + this.plugin = plugin; + } + + @SuppressWarnings("UnstableApiUsage") + @Override + public void sendPluginMessage(AdaptedPlayer player, String channel, String... data) { + Collection networkPlayers = ProxyServer.getInstance().getPlayers(); + if (networkPlayers != null && !networkPlayers.isEmpty()) { + ByteArrayDataOutput out = ByteStreams.newDataOutput(); + out.writeUTF(channel); + out.writeUTF(player.getName()); + int length = data.length; + + for (String s : data) { + out.writeUTF(s); + } + + ((BungeePlayer) player).getHandle().getServer().sendData("ajqueue:tospigot", out.toByteArray()); + } + } + + @Override + public AdaptedPlayer senderToPlayer(ICommandSender sender) { + if(sender instanceof PlayerSender) { + return ((PlayerSender) sender).getHandle(); + } + return new BungeePlayer((ProxiedPlayer) sender.getHandle()); + } + + @Override + public String getPluginVersion() { + return plugin.getDescription().getVersion(); + } + + @Override + public List getOnlinePlayers() { + List players = new ArrayList<>(); + proxyServer.getPlayers().forEach(pp -> players.add(new BungeePlayer(pp))); + return players; + } + + @Override + public List getPlayerNames(boolean lowercase) { + List names = new ArrayList<>(); + proxyServer.getPlayers().forEach(player -> names.add(lowercase ? player.getName().toLowerCase(Locale.ROOT) : player.getName())); + return names; + } + + @Override + public AdaptedPlayer getPlayer(String name) { + ProxiedPlayer player = proxyServer.getPlayer(name); + if(player == null) return null; + return new BungeePlayer(player); + } + + @Override + public List getServerNames() { + return new ArrayList<>(proxyServer.getServers().keySet()); + } + + @Override + public String getImplementationName() { + return "BungeeCord"; + } + + @Override + public List getCommands() { + return plugin.commands; + } + + @Override + public boolean hasPlugin(String pluginName) { + return proxyServer.getPluginManager().getPlugin(pluginName) != null; + } + + @Override + public AdaptedServer getServer(String name) { + ServerInfo server = proxyServer.getServerInfo(name); + if(server == null) return null; + return new BungeeServer(server); + } + + @Override + public List getServers() { + List result = new ArrayList<>(); + + proxyServer.getServers().forEach((s, serverInfo) -> result.add(new BungeeServer(serverInfo))); + + return result; + } +} 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 new file mode 100644 index 0000000..a55b795 --- /dev/null +++ b/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/BungeeQueue.java @@ -0,0 +1,132 @@ +package us.ajg0702.queue.platforms.bungeecord; + +import net.kyori.adventure.platform.bungeecord.BungeeAudiences; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; +import net.md_5.bungee.api.connection.ProxiedPlayer; +import net.md_5.bungee.api.event.*; +import net.md_5.bungee.api.plugin.Listener; +import net.md_5.bungee.api.plugin.Plugin; +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.commands.IBaseCommand; +import us.ajg0702.queue.api.util.QueueLogger; +import us.ajg0702.queue.commands.BaseCommand; +import us.ajg0702.queue.commands.commands.leavequeue.LeaveCommand; +import us.ajg0702.queue.commands.commands.listqueues.ListCommand; +import us.ajg0702.queue.commands.commands.manage.ManageCommand; +import us.ajg0702.queue.commands.commands.queue.QueueCommand; +import us.ajg0702.queue.common.QueueMain; +import us.ajg0702.queue.platforms.bungeecord.commands.BungeeCommand; +import us.ajg0702.queue.platforms.bungeecord.players.BungeePlayer; +import us.ajg0702.queue.platforms.bungeecord.server.BungeeServer; + +import java.io.File; +import java.util.Arrays; +import java.util.List; + +public class BungeeQueue extends Plugin implements Listener { + + private QueueMain main; + + List commands; + + @Override + public void onEnable() { + QueueLogger logger = new BungeeLogger(getLogger()); + File dataFolder = getDataFolder(); + + adventure = BungeeAudiences.create(this); + + main = new QueueMain( + logger, + new BungeeMethods(this, getProxy(), logger), + dataFolder + ); + + getProxy().registerChannel("ajqueue:tospigot"); + getProxy().registerChannel("ajqueue:toproxy"); + + commands = Arrays.asList( + new QueueCommand(main), + new LeaveCommand(main), + new ListCommand(main), + new ManageCommand(main) + ); + + for(IBaseCommand command : commands) { + getProxy().getPluginManager() + .registerCommand(this, new BungeeCommand((BaseCommand) command)); + } + + getProxy().getPluginManager().registerListener(this, this); + + + Metrics metrics = new Metrics(this, 7404); + + metrics.addCustomChart(new SimplePie("premium", () -> String.valueOf(main.getLogic().isPremium()))); + metrics.addCustomChart(new SimplePie("implementation", () -> main.getPlatformMethods().getImplementationName())); + } + + private static BungeeAudiences adventure; + + public static @NonNull BungeeAudiences adventure() { + if(adventure == null) { + throw new IllegalStateException("Cannot retrieve audience provider. Not loaded yet."); + } + return adventure; + } + + @Override + public void onDisable() { + main.shutdown(); + if(adventure != null) { + adventure.close(); + adventure = null; + } + } + + @EventHandler + public void onPluginMessage(PluginMessageEvent e) { + if(e.getTag().equals("ajqueue:tospigot")) { + e.setCancelled(true); + return; + } + if(!e.getTag().equals("ajqueue:toproxy")) return; + e.setCancelled(true); + + if(!(e.getReceiver() instanceof ProxiedPlayer)) return; + + main.getEventHandler().handleMessage(new BungeePlayer((ProxiedPlayer) e.getReceiver()), e.getData()); + } + + @EventHandler + public void onJoin(PostLoginEvent e) { + main.getEventHandler().onPlayerJoin(new BungeePlayer(e.getPlayer())); + } + + @EventHandler + public void onServerSwitch(ServerSwitchEvent e) { + main.getEventHandler().onPlayerJoinServer(new BungeePlayer(e.getPlayer())); + } + + @EventHandler + public void onLeave(PlayerDisconnectEvent e) { + main.getEventHandler().onPlayerLeave(new BungeePlayer(e.getPlayer())); + } + + @EventHandler + public void onKick(ServerKickEvent e) { + if(!e.getPlayer().isConnected()) return; + if(e.getPlayer().getServer() == null) return; // if the player is kicked on initial join, we dont care + Component reason = BungeeComponentSerializer.get().deserialize(e.getKickReasonComponent()); + main.getEventHandler().onServerKick( + new BungeePlayer(e.getPlayer()), + new BungeeServer(e.getCancelServer()), + reason, + false + ); + } +} diff --git a/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/commands/BungeeCommand.java b/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/commands/BungeeCommand.java new file mode 100644 index 0000000..e0d949b --- /dev/null +++ b/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/commands/BungeeCommand.java @@ -0,0 +1,25 @@ +package us.ajg0702.queue.platforms.bungeecord.commands; + + +import net.md_5.bungee.api.CommandSender; +import net.md_5.bungee.api.plugin.Command; +import net.md_5.bungee.api.plugin.TabExecutor; +import us.ajg0702.queue.commands.BaseCommand; + +public class BungeeCommand extends Command implements TabExecutor { + final BaseCommand command; + public BungeeCommand(BaseCommand command) { + super(command.getName(), command.getPermission(), command.getAliases().toArray(new String[0])); + this.command = command; + } + + @Override + public void execute(CommandSender sender, String[] args) { + command.execute(new BungeeSender(sender), args); + } + + @Override + public Iterable onTabComplete(CommandSender sender, String[] args) { + return command.autoComplete(new BungeeSender(sender), args); + } +} diff --git a/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/commands/BungeeSender.java b/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/commands/BungeeSender.java new file mode 100644 index 0000000..dda2f74 --- /dev/null +++ b/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/commands/BungeeSender.java @@ -0,0 +1,39 @@ +package us.ajg0702.queue.platforms.bungeecord.commands; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import net.md_5.bungee.api.CommandSender; +import net.md_5.bungee.api.connection.ProxiedPlayer; +import org.jetbrains.annotations.NotNull; +import us.ajg0702.queue.api.commands.ICommandSender; +import us.ajg0702.queue.platforms.bungeecord.BungeeQueue; + +public class BungeeSender implements ICommandSender { + + final CommandSender handle; + + public BungeeSender(CommandSender handle) { + this.handle = handle; + } + + @Override + public boolean hasPermission(String permission) { + return handle.hasPermission(permission); + } + + @Override + public boolean isPlayer() { + return handle instanceof ProxiedPlayer; + } + + @Override + public void sendMessage(@NotNull Component message) { + if(PlainTextComponentSerializer.plainText().serialize(message).isEmpty()) return; + BungeeQueue.adventure().sender(handle).sendMessage(message); + } + + @Override + public CommandSender getHandle() { + return handle; + } +} diff --git a/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/players/BungeePlayer.java b/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/players/BungeePlayer.java new file mode 100644 index 0000000..c45b73f --- /dev/null +++ b/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/players/BungeePlayer.java @@ -0,0 +1,82 @@ +package us.ajg0702.queue.platforms.bungeecord.players; + +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import net.md_5.bungee.api.connection.ProxiedPlayer; +import org.jetbrains.annotations.NotNull; +import us.ajg0702.queue.api.players.AdaptedPlayer; +import us.ajg0702.queue.api.server.AdaptedServer; +import us.ajg0702.queue.platforms.bungeecord.BungeeQueue; +import us.ajg0702.queue.platforms.bungeecord.server.BungeeServer; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class BungeePlayer implements AdaptedPlayer, Audience { + + final ProxiedPlayer handle; + + public BungeePlayer(ProxiedPlayer player) { + handle = player; + } + + @Override + public boolean isConnected() { + return handle.isConnected(); + } + + @Override + public void sendMessage(@NotNull Component message) { + if(PlainTextComponentSerializer.plainText().serialize(message).isEmpty()) return; + BungeeQueue.adventure().player(handle).sendMessage(message); + } + + @Override + public void sendActionBar(@NotNull Component message) { + if(PlainTextComponentSerializer.plainText().serialize(message).isEmpty()) return; + BungeeQueue.adventure().player(handle).sendActionBar(message); + } + + @Override + public void sendMessage(String message) { + if(message.isEmpty()) return; + BungeeQueue.adventure().player(handle).sendMessage(Component.text(message)); + } + + @Override + public boolean hasPermission(String permission) { + return handle.hasPermission(permission); + } + + @Override + public String getServerName() { + return handle.getServer().getInfo().getName(); + } + + @Override + public UUID getUniqueId() { + return handle.getUniqueId(); + } + + @Override + public void connect(AdaptedServer server) { + handle.connect(((BungeeServer) server).getHandle()); + } + + @Override + public String getName() { + return handle.getName(); + } + + @Override + public List getPermissions() { + return new ArrayList<>(handle.getPermissions()); + } + + @Override + public ProxiedPlayer getHandle() { + return handle; + } +} 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 new file mode 100644 index 0000000..6c8dc38 --- /dev/null +++ b/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/server/BungeeServer.java @@ -0,0 +1,63 @@ +package us.ajg0702.queue.platforms.bungeecord.server; + +import net.md_5.bungee.api.config.ServerInfo; +import net.md_5.bungee.api.connection.ProxiedPlayer; +import us.ajg0702.queue.api.players.AdaptedPlayer; +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.platforms.bungeecord.players.BungeePlayer; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +public class BungeeServer implements AdaptedServer { + + final ServerInfo handle; + final BungeeServerInfo serverInfo; + + public BungeeServer(ServerInfo handle) { + this.handle = handle; + serverInfo = new BungeeServerInfo(handle); + } + + @Override + public AdaptedServerInfo getServerInfo() { + return serverInfo; + } + + @Override + public String getName() { + return serverInfo.getName(); + } + + @Override + public CompletableFuture ping() { + CompletableFuture future = new CompletableFuture<>(); + handle.ping((pp, error) -> { + if(error != null) { + future.complete(null); + } + future.complete(new BungeeServerPing(pp)); + }); + return future; + } + + @Override + public boolean canAccess(AdaptedPlayer player) { + return handle.canAccess((ProxiedPlayer) player.getHandle()); + } + + @Override + public List getPlayers() { + List players = new ArrayList<>(); + handle.getPlayers().forEach(pp -> players.add(new BungeePlayer(pp))); + return players; + } + + @Override + public ServerInfo getHandle() { + return handle; + } +} diff --git a/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/server/BungeeServerInfo.java b/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/server/BungeeServerInfo.java new file mode 100644 index 0000000..98e151d --- /dev/null +++ b/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/server/BungeeServerInfo.java @@ -0,0 +1,22 @@ +package us.ajg0702.queue.platforms.bungeecord.server; + +import net.md_5.bungee.api.config.ServerInfo; +import us.ajg0702.queue.api.server.AdaptedServerInfo; + +public class BungeeServerInfo implements AdaptedServerInfo { + + final ServerInfo handle; + public BungeeServerInfo(ServerInfo handle) { + this.handle = handle; + } + + @Override + public String getName() { + return handle.getName(); + } + + @Override + public ServerInfo getHandle() { + return handle; + } +} diff --git a/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/server/BungeeServerPing.java b/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/server/BungeeServerPing.java new file mode 100644 index 0000000..a4c21c3 --- /dev/null +++ b/platforms/bungeecord/src/main/java/us/ajg0702/queue/platforms/bungeecord/server/BungeeServerPing.java @@ -0,0 +1,43 @@ +package us.ajg0702.queue.platforms.bungeecord.server; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; +import net.md_5.bungee.api.ServerPing; +import net.md_5.bungee.api.chat.BaseComponent; +import us.ajg0702.queue.api.server.AdaptedServerPing; + +public class BungeeServerPing implements AdaptedServerPing { + + final ServerPing handle; + + public BungeeServerPing(ServerPing handle) { + this.handle = handle; + } + + @Override + public Component getDescriptionComponent() { + BaseComponent[] baseComponents = new BaseComponent[1]; + baseComponents[0] = handle.getDescriptionComponent(); + return BungeeComponentSerializer.get().deserialize(baseComponents); + } + + @Override + public String getPlainDescription() { + return handle.getDescriptionComponent().toPlainText(); + } + + @Override + public int getPlayerCount() { + return handle.getPlayers().getOnline(); + } + + @Override + public int getMaxPlayers() { + return handle.getPlayers().getMax(); + } + + @Override + public ServerPing getHandle() { + return handle; + } +} diff --git a/platforms/bungeecord/src/main/resources/bungee.yml b/platforms/bungeecord/src/main/resources/bungee.yml new file mode 100644 index 0000000..a6e82ec --- /dev/null +++ b/platforms/bungeecord/src/main/resources/bungee.yml @@ -0,0 +1,4 @@ +name: ajQueue +version: "@VERSION@" +main: us.ajg0702.queue.platforms.bungeecord.BungeeQueue +author: ajgeiss0702 \ No newline at end of file diff --git a/platforms/velocity/build.gradle.kts b/platforms/velocity/build.gradle.kts new file mode 100644 index 0000000..48d296f --- /dev/null +++ b/platforms/velocity/build.gradle.kts @@ -0,0 +1,72 @@ +plugins { + `java-library` + `maven-publish` +} + +group = "us.ajg0702.queue.platforms.velocity" + +repositories { + //mavenLocal() + mavenCentral() + maven { url = uri("https://repo.ajg0702.us") } + maven { url = uri("https://nexus.velocitypowered.com/repository/maven-public/") } +} + +dependencies { + compileOnly("net.kyori:adventure-api:4.8.1") + compileOnly("com.google.guava:guava:30.1.1-jre") + compileOnly("us.ajg0702:ajUtils:1.1.7") + + compileOnly("com.velocitypowered:velocity-api:3.0.0") + annotationProcessor("com.velocitypowered:velocity-api:3.0.0") + compileOnly("net.kyori:adventure-text-minimessage:4.0.0-SNAPSHOT") + + implementation("org.bstats:bstats-velocity:2.2.1") + + implementation(project(":common")) + implementation(project(":api")) +} + + +tasks.withType { + from(sourceSets.main.get().java.srcDirs) + filter( + "tokens" to mapOf( + "VERSION" to project.version.toString() + ) + ).into("$buildDir/src") +} + +tasks.jar { + exclude("**/*.java") +} + +tasks.compileJava { + source = tasks.getByName("processResources").outputs.files.asFileTree +} + + +publishing { + publications { + create("mavenJava") { + artifact(tasks["jar"]) + } + } + + repositories { + + val mavenUrl = "https://repo.ajg0702.us/releases" + + if(!System.getenv("REPO_TOKEN").isNullOrEmpty()) { + maven { + url = uri(mavenUrl) + name = "ajRepo" + + credentials { + username = "plugins" + password = System.getenv("REPO_TOKEN") + } + } + } + } +} \ No newline at end of file diff --git a/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/VelocityLogger.java b/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/VelocityLogger.java new file mode 100644 index 0000000..ce3706d --- /dev/null +++ b/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/VelocityLogger.java @@ -0,0 +1,39 @@ +package us.ajg0702.queue.platforms.velocity; + + +import org.slf4j.Logger; +import us.ajg0702.queue.api.util.QueueLogger; + +public class VelocityLogger implements QueueLogger { + + private final Logger logger; + + protected VelocityLogger(Logger logger) { + this.logger = logger; + } + + @Override + public void warn(String message) { + logger.warn(message); + } + + @Override + public void warning(String message) { + logger.warn(message); + } + + @Override + public void info(String message) { + logger.info(message); + } + + @Override + public void error(String message) { + logger.error(message); + } + + @Override + public void severe(String message) { + logger.error(message); + } +} diff --git a/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/VelocityMethods.java b/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/VelocityMethods.java new file mode 100644 index 0000000..e899725 --- /dev/null +++ b/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/VelocityMethods.java @@ -0,0 +1,145 @@ +package us.ajg0702.queue.platforms.velocity; + +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; +import com.velocitypowered.api.plugin.PluginContainer; +import com.velocitypowered.api.proxy.Player; +import com.velocitypowered.api.proxy.ProxyServer; +import com.velocitypowered.api.proxy.ServerConnection; +import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier; +import com.velocitypowered.api.proxy.server.RegisteredServer; + +import us.ajg0702.queue.api.PlatformMethods; +import us.ajg0702.queue.api.commands.IBaseCommand; +import us.ajg0702.queue.api.commands.ICommandSender; +import us.ajg0702.queue.api.players.AdaptedPlayer; +import us.ajg0702.queue.api.server.AdaptedServer; +import us.ajg0702.queue.api.util.QueueLogger; +import us.ajg0702.queue.commands.commands.PlayerSender; +import us.ajg0702.queue.platforms.velocity.players.VelocityPlayer; +import us.ajg0702.queue.platforms.velocity.server.VelocityServer; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Optional; + +@SuppressWarnings("OptionalIsPresent") +public class VelocityMethods implements PlatformMethods { + + final ProxyServer proxyServer; + final QueueLogger logger; + final VelocityQueue plugin; + + public VelocityMethods(VelocityQueue plugin, ProxyServer proxyServer, QueueLogger logger) { + this.proxyServer = proxyServer; + this.logger = logger; + this.plugin = plugin; + } + + @Override + public void sendPluginMessage(AdaptedPlayer player, String channel, String... data) { + if(player == null) return; + Player velocityPlayer = ((VelocityPlayer) player).getHandle(); + @SuppressWarnings("UnstableApiUsage") ByteArrayDataOutput out = ByteStreams.newDataOutput(); + out.writeUTF( channel ); + out.writeUTF(player.getName()); + for(String s : data) { + out.writeUTF( s ); + } + Optional server = velocityPlayer.getCurrentServer(); + if(!server.isPresent()) { + throw new IllegalStateException("No server to send data to"); + } + server.get().sendPluginMessage(MinecraftChannelIdentifier.from("ajqueue:tospigot"), out.toByteArray()); + } + + @Override + public AdaptedPlayer senderToPlayer(ICommandSender sender) { + if(sender instanceof PlayerSender) { + return ((PlayerSender) sender).getHandle(); + } + return new VelocityPlayer((Player) sender.getHandle()); + } + + @Override + public String getPluginVersion() { + Optional plugin = proxyServer.getPluginManager().getPlugin("ajqueue"); + if(!plugin.isPresent()) return "?E"; + Optional version = plugin.get().getDescription().getVersion(); + return version.orElse("?V"); + } + + @Override + public List getOnlinePlayers() { + List players = new ArrayList<>(); + for(Player player : proxyServer.getAllPlayers()) { + players.add(new VelocityPlayer(player)); + } + return players; + } + + @Override + public List getPlayerNames(boolean lowercase) { + List players = new ArrayList<>(); + for(Player player : proxyServer.getAllPlayers()) { + if(lowercase) { + players.add(player.getUsername().toLowerCase(Locale.ROOT)); + } else { + players.add(player.getUsername()); + } + } + return players; + } + + @Override + public AdaptedPlayer getPlayer(String name) { + Optional player = proxyServer.getPlayer(name); + if(!player.isPresent()) { + System.out.println("Player "+name+" not found"); + return null; + } + return new VelocityPlayer(player.get()); + } + + @Override + public List getServerNames() { + List names = new ArrayList<>(); + for(RegisteredServer server : proxyServer.getAllServers()) { + names.add(server.getServerInfo().getName()); + } + return names; + } + + @Override + public String getImplementationName() { + return "velocity"; + } + + @Override + public List getCommands() { + return plugin.commands; + } + + @Override + public boolean hasPlugin(String pluginName) { + return proxyServer.getPluginManager().getPlugin(pluginName.toLowerCase(Locale.ROOT)).isPresent(); + } + + @Override + public AdaptedServer getServer(String name) { + Optional server = proxyServer.getServer(name); + if(!server.isPresent()) return null; + return new VelocityServer(server.get()); + } + + + @Override + public List getServers() { + List result = new ArrayList<>(); + + proxyServer.getAllServers().forEach(registeredServer -> result.add(new VelocityServer(registeredServer))); + + return result; + } +} 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 new file mode 100644 index 0000000..b1b1696 --- /dev/null +++ b/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/VelocityQueue.java @@ -0,0 +1,155 @@ +package us.ajg0702.queue.platforms.velocity; + +import com.google.inject.Inject; +import com.velocitypowered.api.command.CommandManager; +import com.velocitypowered.api.event.Subscribe; +import com.velocitypowered.api.event.connection.DisconnectEvent; +import com.velocitypowered.api.event.connection.PluginMessageEvent; +import com.velocitypowered.api.event.player.KickedFromServerEvent; +import com.velocitypowered.api.event.player.ServerPostConnectEvent; +import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; +import com.velocitypowered.api.event.proxy.ProxyShutdownEvent; +import com.velocitypowered.api.plugin.Plugin; +import com.velocitypowered.api.plugin.annotation.DataDirectory; +import com.velocitypowered.api.proxy.Player; +import com.velocitypowered.api.proxy.ProxyServer; +import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier; +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.commands.IBaseCommand; +import us.ajg0702.queue.commands.BaseCommand; +import us.ajg0702.queue.commands.commands.leavequeue.LeaveCommand; +import us.ajg0702.queue.commands.commands.listqueues.ListCommand; +import us.ajg0702.queue.commands.commands.manage.ManageCommand; +import us.ajg0702.queue.commands.commands.queue.QueueCommand; +import us.ajg0702.queue.common.QueueMain; +import us.ajg0702.queue.platforms.velocity.commands.VelocityCommand; +import us.ajg0702.queue.platforms.velocity.players.VelocityPlayer; +import us.ajg0702.queue.platforms.velocity.server.VelocityServer; + +import java.io.File; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +@Plugin( + id = "ajqueue", + name = "ajQueue", + version = "@VERSION@", + url = "https://ajg0702.us", + description = "Queue for servers", + authors = {"ajgeiss0702"} +) + +public class VelocityQueue { + final ProxyServer proxyServer; + final VelocityLogger logger; + + QueueMain main; + + final File dataFolder; + + private final Metrics.Factory metricsFactory; + + @Inject + public VelocityQueue(ProxyServer proxyServer, Logger logger, @DataDirectory Path dataFolder, Metrics.Factory metricsFactory) { + this.proxyServer = proxyServer; + this.logger = new VelocityLogger(logger); + + this.dataFolder = dataFolder.toFile(); + + this.metricsFactory = metricsFactory; + } + + List commands; + + @Subscribe + public void onProxyInit(ProxyInitializeEvent e) { + main = new QueueMain( + logger, + new VelocityMethods(this, proxyServer, logger), + dataFolder + ); + + commands = Arrays.asList( + new QueueCommand(main), + new LeaveCommand(main), + new ListCommand(main), + 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) + ); + } + + + Metrics metrics = metricsFactory.make(this, 7404); + + metrics.addCustomChart(new SimplePie("premium", () -> String.valueOf(main.getLogic().isPremium()))); + metrics.addCustomChart(new SimplePie("implementation", () -> main.getPlatformMethods().getImplementationName())); + } + + @Subscribe + public void onProxyShutdown(ProxyShutdownEvent e) { + main.shutdown(); + } + + @Subscribe + public void onPluginMessage(PluginMessageEvent e) { + + if(e.getIdentifier().getId().equals("ajqueue:tospigot")) { + e.setResult(PluginMessageEvent.ForwardResult.handled()); + return; + } + if(!e.getIdentifier().getId().equals("ajqueue:toproxy")) return; + e.setResult(PluginMessageEvent.ForwardResult.handled()); + + if(!(e.getTarget() instanceof Player)) return; + + main.getEventHandler().handleMessage(new VelocityPlayer((Player) e.getTarget()), e.getData()); + } + + @SuppressWarnings("UnstableApiUsage") + @Subscribe + public void onJoin(ServerPostConnectEvent e) { + if(e.getPreviousServer() == null) { // only run if the player just joined + main.getEventHandler().onPlayerJoin(new VelocityPlayer(e.getPlayer())); + } + main.getEventHandler().onPlayerJoinServer(new VelocityPlayer(e.getPlayer())); + } + + @Subscribe + public void onLeave(DisconnectEvent e) { + 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 + Optional reasonOptional = e.getServerKickReason(); + main.getEventHandler().onServerKick( + new VelocityPlayer(e.getPlayer()), + new VelocityServer(e.getServer()), + reasonOptional.orElseGet(() -> Component.text("Proxy lost connection")), + // According to Tux on discord, velocity doesnt give a reason when the proxy loses connection to the connected server + e.kickedDuringServerConnect() + ); + } + +} diff --git a/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/commands/VelocityCommand.java b/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/commands/VelocityCommand.java new file mode 100644 index 0000000..c95021c --- /dev/null +++ b/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/commands/VelocityCommand.java @@ -0,0 +1,41 @@ +package us.ajg0702.queue.platforms.velocity.commands; + +import com.velocitypowered.api.command.RawCommand; +import us.ajg0702.queue.commands.BaseCommand; +import us.ajg0702.queue.common.QueueMain; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class VelocityCommand implements RawCommand { + + final QueueMain main; + final BaseCommand command; + + public VelocityCommand(QueueMain main, BaseCommand command) { + this.main = main; + this.command = command; + } + + @Override + public void execute(Invocation invocation) { + command.execute(new VelocitySender(invocation.source()), invocation.arguments().split(" ")); + } + + @Override + public List suggest(final Invocation invocation) { + List args = new ArrayList<>(Arrays.asList(invocation.arguments().split(" "))); + if(invocation.arguments().length() > 0 &&invocation.arguments().charAt(invocation.arguments().length()-1) == ' ') { + args.add(" "); + } + return command.autoComplete(new VelocitySender(invocation.source()), args.toArray(new String[0])); + } + + @Override + public boolean hasPermission(final Invocation invocation) { + String permission = command.getPermission(); + if(permission == null) return true; + return invocation.source().hasPermission(permission); + } +} diff --git a/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/commands/VelocitySender.java b/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/commands/VelocitySender.java new file mode 100644 index 0000000..765651e --- /dev/null +++ b/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/commands/VelocitySender.java @@ -0,0 +1,38 @@ +package us.ajg0702.queue.platforms.velocity.commands; + +import com.velocitypowered.api.command.CommandSource; +import com.velocitypowered.api.proxy.ConsoleCommandSource; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import org.jetbrains.annotations.NotNull; +import us.ajg0702.queue.api.commands.ICommandSender; + +public class VelocitySender implements ICommandSender { + + final CommandSource handle; + + public VelocitySender(CommandSource handle) { + this.handle = handle; + } + + @Override + public boolean hasPermission(String permission) { + return handle.hasPermission(permission); + } + + @Override + public boolean isPlayer() { + return !(handle instanceof ConsoleCommandSource); + } + + @Override + public void sendMessage(@NotNull Component message) { + if(PlainTextComponentSerializer.plainText().serialize(message).isEmpty()) return; + handle.sendMessage(message); + } + + @Override + public CommandSource getHandle() { + return handle; + } +} diff --git a/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/players/VelocityPlayer.java b/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/players/VelocityPlayer.java new file mode 100644 index 0000000..350f165 --- /dev/null +++ b/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/players/VelocityPlayer.java @@ -0,0 +1,95 @@ +package us.ajg0702.queue.platforms.velocity.players; + +import com.velocitypowered.api.proxy.Player; +import com.velocitypowered.api.proxy.ServerConnection; +import com.velocitypowered.api.proxy.server.RegisteredServer; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import org.jetbrains.annotations.NotNull; +import us.ajg0702.queue.api.players.AdaptedPlayer; +import us.ajg0702.queue.api.server.AdaptedServer; +import us.ajg0702.queue.common.QueueMain; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +public class VelocityPlayer implements AdaptedPlayer, Audience { + + final Player handle; + + public VelocityPlayer(Player player) { + handle = player; + } + + @Override + public boolean isConnected() { + return handle.isActive(); + } + + @Override + public void sendMessage(@NotNull Component message) { + if(PlainTextComponentSerializer.plainText().serialize(message).isEmpty()) return; + handle.sendMessage(message); + } + + @Override + public void sendActionBar(@NotNull Component message) { + handle.sendActionBar(message); + } + + @Override + public void sendMessage(String message) { + handle.sendMessage(Component.text().content(message)); + } + + @Override + public boolean hasPermission(String permission) { + return handle.hasPermission(permission); + } + + @Override + public String getServerName() { + Optional serverConnection = handle.getCurrentServer(); + if(!serverConnection.isPresent()) return "none"; + ServerConnection connection = serverConnection.get(); + return connection.getServerInfo().getName(); + } + + @Override + public UUID getUniqueId() { + return handle.getUniqueId(); + } + + @Override + public void connect(AdaptedServer server) { + handle.createConnectionRequest((RegisteredServer) server.getHandle()).connect().thenAcceptAsync( + result -> { + if(!result.isSuccessful()) { + QueueMain.getInstance().getEventHandler().onServerKick( + this, + server, + result.getReasonComponent().orElseGet(() -> Component.text("Connection failed")), + false + ); + } + } + ); + } + + @Override + public String getName() { + return handle.getUsername(); + } + + @Override + public List getPermissions() { + throw new IllegalStateException("AdaptedPlayer#getPermissions cannot be used on velocity"); + } + + @Override + public Player 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 new file mode 100644 index 0000000..c43333c --- /dev/null +++ b/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/server/VelocityServer.java @@ -0,0 +1,68 @@ +package us.ajg0702.queue.platforms.velocity.server; + +import com.velocitypowered.api.proxy.Player; +import com.velocitypowered.api.proxy.server.RegisteredServer; +import com.velocitypowered.api.proxy.server.ServerPing; +import us.ajg0702.queue.api.players.AdaptedPlayer; +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.platforms.velocity.players.VelocityPlayer; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +public class VelocityServer implements AdaptedServer { + + private final RegisteredServer handle; + public VelocityServer(RegisteredServer handle) { + this.handle = handle; + } + + @Override + public AdaptedServerInfo getServerInfo() { + return new VelocityServerInfo(handle.getServerInfo()); + } + + @Override + public String getName() { + return handle.getServerInfo().getName(); + } + + @Override + public CompletableFuture ping() { + CompletableFuture future = new CompletableFuture<>(); + CompletableFuture serverPing = handle.ping(); + serverPing.thenRunAsync(() -> { + AdaptedServerPing aPing = null; + try { + aPing = new VelocityServerPing(serverPing.get()); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + future.complete(aPing); + }); + return future; + } + + @Override + public boolean canAccess(AdaptedPlayer player) { + return true; + } + + @Override + public List getPlayers() { + List players = new ArrayList<>(); + for(Player player : handle.getPlayersConnected()) { + players.add(new VelocityPlayer(player)); + } + return players; + } + + @Override + public RegisteredServer getHandle() { + return handle; + } +} diff --git a/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/server/VelocityServerInfo.java b/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/server/VelocityServerInfo.java new file mode 100644 index 0000000..ad43026 --- /dev/null +++ b/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/server/VelocityServerInfo.java @@ -0,0 +1,23 @@ +package us.ajg0702.queue.platforms.velocity.server; + +import com.velocitypowered.api.proxy.server.ServerInfo; +import us.ajg0702.queue.api.server.AdaptedServerInfo; + +public class VelocityServerInfo implements AdaptedServerInfo { + + private final ServerInfo handle; + + public VelocityServerInfo(ServerInfo handle) { + this.handle = handle; + } + + @Override + public String getName() { + return handle.getName(); + } + + @Override + public ServerInfo getHandle() { + return handle; + } +} diff --git a/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/server/VelocityServerPing.java b/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/server/VelocityServerPing.java new file mode 100644 index 0000000..acc57ae --- /dev/null +++ b/platforms/velocity/src/main/java/us/ajg0702/queue/platforms/velocity/server/VelocityServerPing.java @@ -0,0 +1,39 @@ +package us.ajg0702.queue.platforms.velocity.server; + +import com.velocitypowered.api.proxy.server.ServerPing; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import us.ajg0702.queue.api.server.AdaptedServerPing; + +public class VelocityServerPing implements AdaptedServerPing { + + private final ServerPing handle; + public VelocityServerPing(ServerPing handle) { + this.handle = handle; + } + + @Override + public Component getDescriptionComponent() { + return handle.getDescriptionComponent(); + } + + @Override + public String getPlainDescription() { + return PlainTextComponentSerializer.plainText().serialize(handle.getDescriptionComponent()); + } + + @Override + public int getPlayerCount() { + return handle.getPlayers().map(ServerPing.Players::getOnline).orElse(0); + } + + @Override + public int getMaxPlayers() { + return handle.getPlayers().map(ServerPing.Players::getMax).orElse(0); + } + + @Override + public ServerPing getHandle() { + return handle; + } +} diff --git a/premium/build.gradle.kts b/premium/build.gradle.kts new file mode 100644 index 0000000..f6e9ee7 --- /dev/null +++ b/premium/build.gradle.kts @@ -0,0 +1,67 @@ +plugins { + `java-library` + id("com.github.johnrengelman.shadow") + `maven-publish` +} + +group = "us.ajg0702.queue" + +repositories { + //mavenLocal() + mavenCentral() + maven { url = uri("https://repo.ajg0702.us") } + maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") } + +} + +dependencies { + implementation(project(":free")) + + compileOnly(project(":api")) + compileOnly(project(":common")) + + compileOnly("com.google.guava:guava:30.1.1-jre") + + compileOnly("us.ajg0702:ajUtils:1.1.7") + + compileOnly("net.kyori:adventure-api:4.8.1") + + compileOnly(fileTree(mapOf("dir" to "../libs", "include" to listOf("*.jar")))) + + compileOnly("net.luckperms:api:5.0") +} + +tasks.shadowJar { + relocate("us.ajg0702.utils", "us.ajg0702.queue.libs.utils") + relocate("org.bstats", "us.ajg0702.queue.libs.bstats") + relocate("io.leangen.geantyref", "us.ajg0702.queue.libs.geantyref") + relocate("org.spongepowered", "us.ajg0702.queue.libs.sponge") + relocate("org.yaml", "us.ajg0702.queue.libs.yaml") + archiveBaseName.set("ajQueuePlus") + archiveClassifier.set("") +} + +publishing { + publications { + create("mavenJava") { + artifact(tasks["jar"]) + } + } + + repositories { + + val mavenUrl = "https://repo.ajg0702.us/releases" + + if(!System.getenv("REPO_TOKEN").isNullOrEmpty()) { + maven { + url = uri(mavenUrl) + name = "ajRepo" + + credentials { + username = "plugins" + password = System.getenv("REPO_TOKEN") + } + } + } + } +} \ No newline at end of file diff --git a/premium/src/main/java/us/ajg0702/queue/logic/LogicGetterImpl.java b/premium/src/main/java/us/ajg0702/queue/logic/LogicGetterImpl.java new file mode 100644 index 0000000..1613779 --- /dev/null +++ b/premium/src/main/java/us/ajg0702/queue/logic/LogicGetterImpl.java @@ -0,0 +1,34 @@ +package us.ajg0702.queue.logic; + +import us.ajg0702.queue.api.AliasManager; +import us.ajg0702.queue.api.Logic; +import us.ajg0702.queue.api.LogicGetter; +import us.ajg0702.queue.api.players.AdaptedPlayer; +import us.ajg0702.queue.common.QueueMain; +import us.ajg0702.queue.logic.permissions.PermissionGetter; +import us.ajg0702.utils.common.Config; + +import java.util.List; + +public class LogicGetterImpl implements LogicGetter { + PremiumLogic logic; + + @Override + public Logic constructLogic() { + if(logic == null) { + logic = new PremiumLogic(QueueMain.getInstance()); + } + return logic; + } + + @Override + public AliasManager constructAliasManager(Config config) { + return new PremiumAliasManager(config); + } + + @Override + public List getPermissions(AdaptedPlayer player) { + if(logic == null) return null; + return logic.getPermissionGetter().getSelected().getPermissions(player); + } +} diff --git a/premium/src/main/java/us/ajg0702/queue/logic/PremiumAliasManager.java b/premium/src/main/java/us/ajg0702/queue/logic/PremiumAliasManager.java new file mode 100644 index 0000000..324de46 --- /dev/null +++ b/premium/src/main/java/us/ajg0702/queue/logic/PremiumAliasManager.java @@ -0,0 +1,37 @@ +package us.ajg0702.queue.logic; + +import us.ajg0702.queue.api.AliasManager; +import us.ajg0702.utils.common.Config; + +import java.util.List; + +public class PremiumAliasManager implements AliasManager { + + private final Config config; + + protected PremiumAliasManager(Config config) { + this.config = config; + } + + @Override + public String getAlias(String server) { + List aliasesraw = config.getStringList("server-aliases"); + for(String aliasraw : aliasesraw) { + String realname = aliasraw.split(":")[0]; + if(!realname.equalsIgnoreCase(server)) continue; + return aliasraw.split(":")[1]; + } + return server; + } + + @Override + public String getServer(String alias) { + List aliasesraw = config.getStringList("server-aliases"); + for(String aliasraw : aliasesraw) { + String salias = aliasraw.split(":")[1]; + if(!alias.equalsIgnoreCase(salias)) continue; + return aliasraw.split(":")[0]; + } + return alias; + } +} diff --git a/premium/src/main/java/us/ajg0702/queue/logic/PremiumLogic.java b/premium/src/main/java/us/ajg0702/queue/logic/PremiumLogic.java new file mode 100644 index 0000000..7cdd042 --- /dev/null +++ b/premium/src/main/java/us/ajg0702/queue/logic/PremiumLogic.java @@ -0,0 +1,97 @@ +package us.ajg0702.queue.logic; + +import com.google.common.collect.ImmutableList; +import us.ajg0702.queue.api.Logic; +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.util.QueueLogger; +import us.ajg0702.queue.common.QueueMain; +import us.ajg0702.queue.common.players.QueuePlayerImpl; +import us.ajg0702.queue.logic.permissions.PermissionGetter; + +public class PremiumLogic implements Logic { + + public PermissionGetter getPermissionGetter() { + return permissionGetter; + } + + private final PermissionGetter permissionGetter; + public PremiumLogic(QueueMain main) { + permissionGetter = new PermissionGetter(main); + } + + @Override + public boolean isPremium() { + return true; + } + + @Override + public QueuePlayer priorityLogic(QueueServer server, AdaptedPlayer player) { + int maxOfflineTime = permissionGetter.getMaxOfflineTime(player); + + QueueMain main = QueueMain.getInstance(); + + QueueLogger logger = main.getLogger(); + boolean debug = main.getConfig().getBoolean("priority-queue-debug"); + + if(player.hasPermission("ajqueue.bypass") || player.hasPermission("ajqueue.serverbypass."+server.getName())) { + if(debug) { + logger.info("[priority] "+player.getName()+" bypass"); + } + QueuePlayer queuePlayer = new QueuePlayerImpl(player, server, Integer.MAX_VALUE, maxOfflineTime); + server.addPlayer(queuePlayer, 0); + main.getQueueManager().sendPlayers(server); + return queuePlayer; + } + + int priority = permissionGetter.getPriority(player); + int serverPriority = permissionGetter.getServerPriotity(server.getName(), player); + + if(debug) { + logger.info("[priority] Using "+permissionGetter.getSelected().getName()+" for permissions"); + } + + int highestPriority = Math.max(priority, serverPriority); + + QueuePlayer queuePlayer = new QueuePlayerImpl(player, server, highestPriority, maxOfflineTime); + + if(debug) { + logger.info("[priority] "+player.getName()+" highestPriority: "+highestPriority); + logger.info("[priority] "+player.getName()+" priority: "+priority); + logger.info("[priority] "+player.getName()+" serverPriority: "+serverPriority); + } + + if(highestPriority <= 0) { + if(debug) { + logger.info("[priority] "+player.getName()+" No priority" ); + } + server.addPlayer(queuePlayer); + return queuePlayer; + } + + ImmutableList list = server.getQueue(); + + for(int i = 0; i < list.size(); i++) { + QueuePlayer pl = list.get(i); + if(pl.getPriority() < highestPriority) { + if(debug) { + logger.info("[priority] "+player.getName()+" Adding to: "+i); + } + server.addPlayer(queuePlayer, i); + return queuePlayer; + } + } + + if(debug) { + logger.info("[priority] "+player.getName()+" Cant go infront of anyone" ); + } + server.addPlayer(queuePlayer); + return queuePlayer; + } + + @Override + public boolean playerDisconnectedTooLong(QueuePlayer player) { + return player.getTimeSinceOnline() > player.getMaxOfflineTime()*1000L; + } +} diff --git a/premium/src/main/java/us/ajg0702/queue/logic/permissions/PermissionGetter.java b/premium/src/main/java/us/ajg0702/queue/logic/permissions/PermissionGetter.java new file mode 100644 index 0000000..49dfb56 --- /dev/null +++ b/premium/src/main/java/us/ajg0702/queue/logic/permissions/PermissionGetter.java @@ -0,0 +1,77 @@ +package us.ajg0702.queue.logic.permissions; + +import us.ajg0702.queue.api.players.AdaptedPlayer; +import us.ajg0702.queue.common.QueueMain; +import us.ajg0702.queue.logic.permissions.hooks.BuiltIn; +import us.ajg0702.queue.logic.permissions.hooks.LuckPermsHook; +import us.ajg0702.queue.logic.permissions.hooks.UltraPermissionsHook; + +import java.util.*; + +public class PermissionGetter { + + private final List hooks; + + private final QueueMain main; + public PermissionGetter(QueueMain main) { + hooks = Arrays.asList( + new BuiltIn(main), + new LuckPermsHook(main), + new UltraPermissionsHook(main) + ); + this.main = main; + } + + private PermissionHook selected; + 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()) { + selected = hook; + } + } + if(selected == null) { + throw new IllegalStateException("All hooks are unusable!"); + } + main.getLogger().info("Using "+selected.getName()+" for permissions."); + return selected; + } + + public int getMaxOfflineTime(AdaptedPlayer player) { + return getHighestPermission(player, "ajqueue.stayqueued."); + } + + public int getPriority(AdaptedPlayer player) { + return getHighestPermission(player, "ajqueue.priority."); + } + + public int getServerPriotity(String server, AdaptedPlayer player) { + return getHighestPermission(player, "ajqueue.serverpriority."+server+"."); + } + + private int getHighestPermission(AdaptedPlayer player, String prefix) { + if(getSelected() == null) { + return -1; + } + List perms = getSelected().getPermissions(player); + Iterator it = perms.iterator(); + String highestPerm = prefix+"0"; + while(it.hasNext()) { + String perm = it.next(); + if(!perm.startsWith(prefix)) continue; + if(highestPerm.isEmpty()) { + highestPerm = perm; + continue; + } + int level = Integer.parseInt(perm.substring(prefix.length())); + int highestlevel = Integer.parseInt(highestPerm.substring(prefix.length())); + if(level > highestlevel) { + highestPerm = perm; + } + } + return Integer.parseInt(highestPerm.substring(prefix.length())); + } +} diff --git a/premium/src/main/java/us/ajg0702/queue/logic/permissions/PermissionHook.java b/premium/src/main/java/us/ajg0702/queue/logic/permissions/PermissionHook.java new file mode 100644 index 0000000..b9b7e97 --- /dev/null +++ b/premium/src/main/java/us/ajg0702/queue/logic/permissions/PermissionHook.java @@ -0,0 +1,11 @@ +package us.ajg0702.queue.logic.permissions; + +import us.ajg0702.queue.api.players.AdaptedPlayer; + +import java.util.List; + +public interface PermissionHook { + String getName(); + boolean canUse(); + List getPermissions(AdaptedPlayer player); +} diff --git a/premium/src/main/java/us/ajg0702/queue/logic/permissions/hooks/BuiltIn.java b/premium/src/main/java/us/ajg0702/queue/logic/permissions/hooks/BuiltIn.java new file mode 100644 index 0000000..289d046 --- /dev/null +++ b/premium/src/main/java/us/ajg0702/queue/logic/permissions/hooks/BuiltIn.java @@ -0,0 +1,34 @@ +package us.ajg0702.queue.logic.permissions.hooks; + +import us.ajg0702.queue.api.players.AdaptedPlayer; +import us.ajg0702.queue.common.QueueMain; +import us.ajg0702.queue.logic.permissions.PermissionHook; + +import java.util.ArrayList; +import java.util.List; + +public class BuiltIn implements PermissionHook { + + private final QueueMain main; + public BuiltIn(QueueMain main) { + this.main = main; + } + + @Override + public String getName() { + return "Built-In"; + } + + @Override + public boolean canUse() { + return true; + } + + @Override + public List getPermissions(AdaptedPlayer player) { + if(main.getPlatformMethods().getImplementationName().equals("velocity")) { + return new ArrayList<>(); + } + return player.getPermissions(); + } +} 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 new file mode 100644 index 0000000..1b21b79 --- /dev/null +++ b/premium/src/main/java/us/ajg0702/queue/logic/permissions/hooks/LuckPermsHook.java @@ -0,0 +1,51 @@ +package us.ajg0702.queue.logic.permissions.hooks; + +import net.luckperms.api.LuckPerms; +import net.luckperms.api.LuckPermsProvider; +import net.luckperms.api.model.user.User; +import net.luckperms.api.node.Node; +import net.luckperms.api.node.NodeType; +import net.luckperms.api.query.QueryOptions; +import us.ajg0702.queue.api.players.AdaptedPlayer; +import us.ajg0702.queue.common.QueueMain; +import us.ajg0702.queue.logic.permissions.PermissionHook; + +import java.util.*; + +public class LuckPermsHook implements PermissionHook { + + private final QueueMain main; + public LuckPermsHook(QueueMain main) { + this.main = main; + } + + @Override + public String getName() { + return "LuckPerms"; + } + + @Override + public boolean canUse() { + return main.getPlatformMethods().hasPlugin("LuckPerms"); + } + + @Override + public List getPermissions(AdaptedPlayer player) { + LuckPerms api = LuckPermsProvider.get(); + + User user = api.getUserManager().getUser(player.getUniqueId()); + + assert user != null; + SortedSet nodes = user.resolveDistinctInheritedNodes(QueryOptions.nonContextual()); + + List perms = new ArrayList<>(); + + for (Node node : nodes) { + if (!node.getType().equals(NodeType.PERMISSION)) continue; + if (!node.getValue()) continue; + perms.add(node.getKey()); + } + + return perms; + } +} diff --git a/premium/src/main/java/us/ajg0702/queue/logic/permissions/hooks/UltraPermissionsHook.java b/premium/src/main/java/us/ajg0702/queue/logic/permissions/hooks/UltraPermissionsHook.java new file mode 100644 index 0000000..259bfa8 --- /dev/null +++ b/premium/src/main/java/us/ajg0702/queue/logic/permissions/hooks/UltraPermissionsHook.java @@ -0,0 +1,44 @@ +package us.ajg0702.queue.logic.permissions.hooks; + +import me.TechsCode.UltraPermissions.UltraPermissions; +import me.TechsCode.UltraPermissions.UltraPermissionsAPI; +import me.TechsCode.UltraPermissions.storage.objects.User; +import us.ajg0702.queue.api.players.AdaptedPlayer; +import us.ajg0702.queue.common.QueueMain; +import us.ajg0702.queue.logic.permissions.PermissionHook; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +@SuppressWarnings("SimplifyOptionalCallChains") +public class UltraPermissionsHook implements PermissionHook { + + private final QueueMain main; + public UltraPermissionsHook(QueueMain main) { + this.main = main; + } + + @Override + public String getName() { + return "UltraPermissions"; + } + + @Override + public boolean canUse() { + return main.getPlatformMethods().hasPlugin("UltraPermissions"); + } + + @Override + public List getPermissions(AdaptedPlayer player) { + UltraPermissionsAPI ultraPermissionsAPI = UltraPermissions.getAPI(); + + Optional userOptional = ultraPermissionsAPI.getUsers().uuid(player.getUniqueId()); + if(!userOptional.isPresent()) return new ArrayList<>(); + User user = userOptional.get(); + + List permissions = new ArrayList<>(); + user.getPermissions().bungee().forEach(permission -> permissions.add(permission.getName())); + return permissions; + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 874f8e2..ca75773 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1 +1,12 @@ -rootProject.name = "ajQueue" \ No newline at end of file +rootProject.name = "ajQueue" + +include(":api") +include(":common") + +include(":spigot") + +include(":platforms:velocity") +include(":platforms:bungeecord") + +include(":free") +include(":premium") \ No newline at end of file diff --git a/spigot/build.gradle.kts b/spigot/build.gradle.kts new file mode 100644 index 0000000..aec53f1 --- /dev/null +++ b/spigot/build.gradle.kts @@ -0,0 +1,61 @@ +plugins { + `java-library` + `maven-publish` +} + +group = "us.ajg0702.queue.spigot" + +repositories { + //mavenLocal() + mavenCentral() + + maven { url = uri("https://repo.extendedclip.com/content/repositories/placeholderapi/") } + + maven { url = uri("https://repo.codemc.io/repository/nms/") } + + maven { url = uri("https://repo.ajg0702.us") } +} + +dependencies { + implementation("net.kyori:adventure-api:4.8.1") + compileOnly("com.google.guava:guava:30.1.1-jre") + + compileOnly("us.ajg0702:ajUtils:1.1.7") + + compileOnly(group = "org.spigotmc", name = "spigot", version = "1.16.5-R0.1-SNAPSHOT") + compileOnly("me.clip:placeholderapi:2.10.4") +} + +tasks.withType { + include("**/*.yml") + filter( + "tokens" to mapOf( + "VERSION" to project.version.toString() + ) + ) +} + +publishing { + publications { + create("mavenJava") { + artifact(tasks["jar"]) + } + } + + repositories { + + val mavenUrl = "https://repo.ajg0702.us/releases" + + if(!System.getenv("REPO_TOKEN").isNullOrEmpty()) { + maven { + url = uri(mavenUrl) + name = "ajRepo" + + credentials { + username = "plugins" + password = System.getenv("REPO_TOKEN") + } + } + } + } +} \ No newline at end of file diff --git a/src/main/java/us/ajg0702/queue/spigot/Commands.java b/spigot/src/main/java/us/ajg0702/queue/spigot/Commands.java similarity index 85% rename from src/main/java/us/ajg0702/queue/spigot/Commands.java rename to spigot/src/main/java/us/ajg0702/queue/spigot/Commands.java index 356fd41..c4a0368 100644 --- a/src/main/java/us/ajg0702/queue/spigot/Commands.java +++ b/spigot/src/main/java/us/ajg0702/queue/spigot/Commands.java @@ -6,16 +6,17 @@ import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; public class Commands implements CommandExecutor { - Main pl; - public Commands(Main pl) { + final SpigotMain pl; + public Commands(SpigotMain pl) { this.pl = pl; } @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { Player player = null; if(sender instanceof Player) { player = (Player) sender; @@ -51,6 +52,7 @@ public class Commands implements CommandExecutor { if(pl.config.getBoolean("send-queue-commands-in-batches")) { pl.queuebatch.put(player, srvname); } else { + assert player != null; pl.sendMessage(player, "queue", srvname); } diff --git a/src/main/java/us/ajg0702/queue/spigot/Config.java b/spigot/src/main/java/us/ajg0702/queue/spigot/Config.java similarity index 95% rename from src/main/java/us/ajg0702/queue/spigot/Config.java rename to spigot/src/main/java/us/ajg0702/queue/spigot/Config.java index 26281f4..b1eafb6 100644 --- a/src/main/java/us/ajg0702/queue/spigot/Config.java +++ b/spigot/src/main/java/us/ajg0702/queue/spigot/Config.java @@ -1,18 +1,18 @@ package us.ajg0702.queue.spigot; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.plugin.java.JavaPlugin; + import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.nio.file.Files; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.plugin.java.JavaPlugin; - public class Config { - File f; - YamlConfiguration yml; + final File f; + final YamlConfiguration yml; - JavaPlugin pl; + final JavaPlugin pl; public boolean getBoolean(String key) { diff --git a/src/main/java/us/ajg0702/queue/spigot/Placeholders.java b/spigot/src/main/java/us/ajg0702/queue/spigot/Placeholders.java similarity index 80% rename from src/main/java/us/ajg0702/queue/spigot/Placeholders.java rename to spigot/src/main/java/us/ajg0702/queue/spigot/Placeholders.java index 0e7fedc..5945862 100644 --- a/src/main/java/us/ajg0702/queue/spigot/Placeholders.java +++ b/spigot/src/main/java/us/ajg0702/queue/spigot/Placeholders.java @@ -1,12 +1,12 @@ package us.ajg0702.queue.spigot; +import me.clip.placeholderapi.expansion.PlaceholderExpansion; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + import java.util.ConcurrentModificationException; import java.util.HashMap; import java.util.Iterator; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; - -import me.clip.placeholderapi.expansion.PlaceholderExpansion; /** * This class will be registered through the register-method in the @@ -14,7 +14,7 @@ import me.clip.placeholderapi.expansion.PlaceholderExpansion; */ public class Placeholders extends PlaceholderExpansion { - private Main plugin; + private final SpigotMain plugin; /** * Since we register the expansion inside our own plugin, we @@ -24,7 +24,7 @@ public class Placeholders extends PlaceholderExpansion { * @param plugin * The instance of our plugin. */ - public Placeholders(Main plugin){ + public Placeholders(SpigotMain plugin){ this.plugin = plugin; } @@ -89,7 +89,7 @@ public class Placeholders extends PlaceholderExpansion { return plugin.getDescription().getVersion(); } - HashMap> responseCache = new HashMap<>(); + final HashMap> responseCache = new HashMap<>(); public void cleanCache() { Iterator it = responseCache.keySet().iterator(); @@ -118,7 +118,8 @@ public class Placeholders extends PlaceholderExpansion { * * @return possibly-null String of the requested identifier. */ - @Override + @SuppressWarnings("SuspiciousMethodCalls") + @Override public String onPlaceholderRequest(Player player, final String identifier){ //Bukkit.getLogger().info("itentifier: "+identifier); @@ -135,31 +136,25 @@ public class Placeholders extends PlaceholderExpansion { } } - Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() { - public void run() { - HashMap playerCache; - if(responseCache.containsKey(player)) { - playerCache = responseCache.get(player); - } else { - playerCache = new HashMap(); - } - if(playerCache.size() > 75) { - try { - playerCache.remove(playerCache.keySet().toArray()[0]); - } catch(ConcurrentModificationException e) { - Bukkit.getScheduler().runTask(plugin, new Runnable() { - public void run() { - playerCache.remove(playerCache.keySet().toArray()[0]); - } - }); - } - } - String resp = parsePlaceholder(player, identifier); - if(resp == null) return; - playerCache.put(identifier, resp); - responseCache.put(player, playerCache); - } - }); + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + HashMap playerCache; + if(responseCache.containsKey(player)) { + playerCache = responseCache.get(player); + } else { + playerCache = new HashMap<>(); + } + if(playerCache.size() > 75) { + try { + playerCache.remove(playerCache.keySet().toArray()[0]); + } catch(ConcurrentModificationException e) { + Bukkit.getScheduler().runTask(plugin, () -> playerCache.remove(playerCache.keySet().toArray()[0])); + } + } + String resp = parsePlaceholder(player, identifier); + if(resp == null) return; + playerCache.put(identifier, resp); + responseCache.put(player, playerCache); + }); if(responseCache.containsKey(player)) { @@ -186,26 +181,22 @@ public class Placeholders extends PlaceholderExpansion { return null; } - private String parsePlaceholder(Player player, String identifier) { + @SuppressWarnings("SameReturnValue") + private String parsePlaceholder(Player player, String identifier) { if(identifier.equalsIgnoreCase("queued")) { plugin.sendMessage(player, "queuename", ""); - return null; } if(identifier.equalsIgnoreCase("position")) { plugin.sendMessage(player, "position", ""); - return null; } if(identifier.equalsIgnoreCase("of")) { plugin.sendMessage(player, "positionof", ""); - return null; } if(identifier.equalsIgnoreCase("inqueue")) { plugin.sendMessage(player, "inqueue", ""); - return null; } if(identifier.matches("queuedfor_*.*")) { plugin.sendMessage(player, "queuedfor", identifier.split("_")[1]); - return null; } diff --git a/src/main/java/us/ajg0702/queue/spigot/QueueScoreboardActivator.java b/spigot/src/main/java/us/ajg0702/queue/spigot/QueueScoreboardActivator.java similarity index 82% rename from src/main/java/us/ajg0702/queue/spigot/QueueScoreboardActivator.java rename to spigot/src/main/java/us/ajg0702/queue/spigot/QueueScoreboardActivator.java index 9c621b0..46ba47f 100644 --- a/src/main/java/us/ajg0702/queue/spigot/QueueScoreboardActivator.java +++ b/spigot/src/main/java/us/ajg0702/queue/spigot/QueueScoreboardActivator.java @@ -3,11 +3,12 @@ package us.ajg0702.queue.spigot; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; public class QueueScoreboardActivator extends Event { private static final HandlerList HANDLERS = new HandlerList(); - public HandlerList getHandlers() { + public @NotNull HandlerList getHandlers() { return HANDLERS; } @@ -15,7 +16,7 @@ public class QueueScoreboardActivator extends Event { return HANDLERS; } - Player ply; + final Player ply; public QueueScoreboardActivator(Player p) { this.ply = p; diff --git a/src/main/java/us/ajg0702/queue/spigot/Main.java b/spigot/src/main/java/us/ajg0702/queue/spigot/SpigotMain.java similarity index 74% rename from src/main/java/us/ajg0702/queue/spigot/Main.java rename to spigot/src/main/java/us/ajg0702/queue/spigot/SpigotMain.java index cc2cb14..79366b6 100644 --- a/src/main/java/us/ajg0702/queue/spigot/Main.java +++ b/spigot/src/main/java/us/ajg0702/queue/spigot/SpigotMain.java @@ -1,7 +1,8 @@ package us.ajg0702.queue.spigot; -import java.util.HashMap; - +import com.google.common.io.ByteArrayDataInput; +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -9,23 +10,22 @@ import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.messaging.PluginMessageListener; +import org.jetbrains.annotations.NotNull; -import com.google.common.io.ByteArrayDataInput; -import com.google.common.io.ByteArrayDataOutput; -import com.google.common.io.ByteStreams; +import java.util.HashMap; -import us.ajg0702.queue.spigot.utils.VersionSupport; - -public class Main extends JavaPlugin implements PluginMessageListener,Listener { +@SuppressWarnings("UnstableApiUsage") +public class SpigotMain extends JavaPlugin implements PluginMessageListener,Listener { boolean papi = false; Placeholders placeholders; Config config; + @SuppressWarnings("ConstantConditions") public void onEnable() { getServer().getMessenger().registerIncomingPluginChannel(this, "ajqueue:tospigot", this); - getServer().getMessenger().registerOutgoingPluginChannel(this, "ajqueue:tobungee"); + getServer().getMessenger().registerOutgoingPluginChannel(this, "ajqueue:toproxy"); this.getCommand("move").setExecutor(new Commands(this)); this.getCommand("leavequeue").setExecutor(new Commands(this)); @@ -40,20 +40,18 @@ public class Main extends JavaPlugin implements PluginMessageListener,Listener { getLogger().info("Registered PlaceholderAPI placeholders"); } - Bukkit.getScheduler().runTaskTimer(this, new Runnable() { - public void run() { - if(Bukkit.getOnlinePlayers().size() <= 0 || queuebatch.size() <= 0) return; - String msg = ""; - for(Player p : queuebatch.keySet()) { - if(p == null || !p.isOnline()) continue; - msg += p.getName()+":"+queuebatch.get(p)+","; - } - if(msg.length() > 1) { - msg = msg.substring(0, msg.length()-1); - } - queuebatch.clear(); - sendMessage("massqueue", msg); + Bukkit.getScheduler().runTaskTimer(this, () -> { + if(Bukkit.getOnlinePlayers().size() <= 0 || queuebatch.size() <= 0) return; + StringBuilder msg = new StringBuilder(); + for(Player p : queuebatch.keySet()) { + if(p == null || !p.isOnline()) continue; + msg.append(p.getName()).append(":").append(queuebatch.get(p)).append(","); } + if(msg.length() > 1) { + msg = new StringBuilder(msg.substring(0, msg.length() - 1)); + } + queuebatch.clear(); + sendMessage("massqueue", msg.toString()); }, 2*20, 20); config = new Config(this); @@ -61,30 +59,16 @@ public class Main extends JavaPlugin implements PluginMessageListener,Listener { getLogger().info("Spigot side enabled! v"+getDescription().getVersion()); } - HashMap queuebatch = new HashMap<>(); + final HashMap queuebatch = new HashMap<>(); @Override - public void onPluginMessageReceived(String channel, Player player, byte[] message) { + public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, byte[] message) { if (!channel.equals("ajqueue:tospigot")) return; ByteArrayDataInput in = ByteStreams.newDataInput(message); String subchannel = in.readUTF(); - - if(subchannel.equals("actionbar")) { - String playername = in.readUTF(); - Player p = Bukkit.getPlayer(playername); - if(p == null) return; - - String data = in.readUTF(); - final String text = data.split(";time=")[0]; - //getLogger().info("recieved actionbar for "+player.getName()+": "+text); - VersionSupport.sendActionBar(p, text); - - /*QueueActionbarUpdateEvent e = new QueueActionbarUpdateEvent(p); - Bukkit.getPluginManager().callEvent(e);*/ - return; - } + if(subchannel.equals("inqueueevent")) { String playername = in.readUTF(); Player p = Bukkit.getPlayer(playername); @@ -148,7 +132,7 @@ public class Main extends JavaPlugin implements PluginMessageListener,Listener { if(p == null) return; if(!p.isOnline()) return; - int number = Integer.valueOf(in.readUTF()); + int number = Integer.parseInt(in.readUTF()); HashMap phs = placeholders.responseCache.get(p); if(phs == null) phs = new HashMap<>(); phs.put("queuedfor_"+queuename, number+""); @@ -158,12 +142,11 @@ public class Main extends JavaPlugin implements PluginMessageListener,Listener { public void sendMessage(Player player, String subchannel, String data) { - //getLogger().info("Sending message. "+subchannel+" "+data); ByteArrayDataOutput out = ByteStreams.newDataOutput(); out.writeUTF(subchannel); out.writeUTF(data); - player.sendPluginMessage(this, "ajqueue:tobungee", out.toByteArray()); + player.sendPluginMessage(this, "ajqueue:toproxy", out.toByteArray()); } public void sendMessage(String subchannel, String data) { @@ -172,7 +155,7 @@ public class Main extends JavaPlugin implements PluginMessageListener,Listener { out.writeUTF(data); Bukkit.getOnlinePlayers().iterator().next() - .sendPluginMessage(this, "ajqueue:tobungee", out.toByteArray()); + .sendPluginMessage(this, "ajqueue:toproxy", out.toByteArray()); } @EventHandler diff --git a/src/main/java/us/ajg0702/queue/spigot/utils/ActionBar.java b/spigot/src/main/java/us/ajg0702/queue/spigot/utils/ActionBar.java similarity index 91% rename from src/main/java/us/ajg0702/queue/spigot/utils/ActionBar.java rename to spigot/src/main/java/us/ajg0702/queue/spigot/utils/ActionBar.java index 57e8652..acc3c60 100644 --- a/src/main/java/us/ajg0702/queue/spigot/utils/ActionBar.java +++ b/spigot/src/main/java/us/ajg0702/queue/spigot/utils/ActionBar.java @@ -1,29 +1,26 @@ package us.ajg0702.queue.spigot.utils; -import java.lang.reflect.Field; -import java.lang.reflect.Method; - import org.bukkit.Bukkit; import org.bukkit.entity.Player; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + /** * A cross-version actionbar class * @author Based on ActionBarAPI from https://github.com/ConnorLinfoot * */ public class ActionBar { - - private static String version; - private static boolean old; - public static void send(Player player, String message) { + public static void send(Player player, String message) { if(player == null) return; if(!player.isOnline()) return; - - version = Bukkit.getServer().getClass().getPackage().getName(); + + String version = Bukkit.getServer().getClass().getPackage().getName(); version = version.substring(version.lastIndexOf(".") + 1); - old = version.equalsIgnoreCase("v1_8_R1") || version.startsWith("v1_7_"); + boolean old = version.equalsIgnoreCase("v1_8_R1") || version.startsWith("v1_7_"); try { Class craftPlayerClass = Class.forName("org.bukkit.craftbukkit." + version + ".entity.CraftPlayer"); diff --git a/src/main/java/us/ajg0702/queue/spigot/utils/VersionSupport.java b/spigot/src/main/java/us/ajg0702/queue/spigot/utils/VersionSupport.java similarity index 96% rename from src/main/java/us/ajg0702/queue/spigot/utils/VersionSupport.java rename to spigot/src/main/java/us/ajg0702/queue/spigot/utils/VersionSupport.java index ff3c551..7ed2280 100644 --- a/src/main/java/us/ajg0702/queue/spigot/utils/VersionSupport.java +++ b/spigot/src/main/java/us/ajg0702/queue/spigot/utils/VersionSupport.java @@ -1,10 +1,9 @@ package us.ajg0702.queue.spigot.utils; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; - import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; public class VersionSupport { diff --git a/src/main/resources/plugin.yml b/spigot/src/main/resources/plugin.yml similarity index 87% rename from src/main/resources/plugin.yml rename to spigot/src/main/resources/plugin.yml index 81632df..afc875e 100644 --- a/src/main/resources/plugin.yml +++ b/spigot/src/main/resources/plugin.yml @@ -1,4 +1,4 @@ -main: us.ajg0702.queue.spigot.Main +main: us.ajg0702.queue.spigot.SpigotMain version: "@VERSION@" api-version: 1.13 author: ajgeiss0702 diff --git a/src/main/java/us/ajg0702/queue/AliasManager.java b/src/main/java/us/ajg0702/queue/AliasManager.java deleted file mode 100644 index c857153..0000000 --- a/src/main/java/us/ajg0702/queue/AliasManager.java +++ /dev/null @@ -1,11 +0,0 @@ -package us.ajg0702.queue; - -public class AliasManager { - public AliasManager(Main pl) {} - public String getAlias(String server) { - return server; - } - public String getServer(String alias) { - return alias; - } -} diff --git a/src/main/java/us/ajg0702/queue/Logic.java b/src/main/java/us/ajg0702/queue/Logic.java deleted file mode 100644 index 7ff4629..0000000 --- a/src/main/java/us/ajg0702/queue/Logic.java +++ /dev/null @@ -1,13 +0,0 @@ -package us.ajg0702.queue; - -import java.util.List; - -import net.md_5.bungee.api.connection.ProxiedPlayer; - -public class Logic { - - static boolean isp = false; - - public static void priorityLogic(List list, String s, ProxiedPlayer p) {} - -} diff --git a/src/main/java/us/ajg0702/queue/Main.java b/src/main/java/us/ajg0702/queue/Main.java deleted file mode 100644 index d7e4c61..0000000 --- a/src/main/java/us/ajg0702/queue/Main.java +++ /dev/null @@ -1,355 +0,0 @@ -package us.ajg0702.queue; - -import java.io.ByteArrayInputStream; -import java.io.DataInputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import net.md_5.bungee.api.ProxyServer; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.TextComponent; -import net.md_5.bungee.api.connection.ProxiedPlayer; -import net.md_5.bungee.api.event.PlayerDisconnectEvent; -import net.md_5.bungee.api.event.PluginMessageEvent; -import net.md_5.bungee.api.event.ServerKickEvent; -import net.md_5.bungee.api.event.ServerSwitchEvent; -import net.md_5.bungee.api.plugin.Listener; -import net.md_5.bungee.api.plugin.Plugin; -import net.md_5.bungee.event.EventHandler; -import us.ajg0702.queue.commands.LeaveCommand; -import us.ajg0702.queue.commands.ListCommand; -import us.ajg0702.queue.commands.ManageCommand; -import us.ajg0702.queue.commands.MoveCommand; -import us.ajg0702.utils.bungee.*; - -public class Main extends Plugin implements Listener { - - static Main plugin = null; - - public double timeBetweenPlayers = 5.0; - - BungeeStats metrics; - - BungeeMessages msgs; - - BungeeConfig config; - - Manager man; - - boolean isp; - - MoveCommand moveCommand; - - public AliasManager aliases; - - @Override - public void onEnable() { - plugin = this; - - config = new BungeeConfig(this); - checkConfig(); - - LinkedHashMap d = new LinkedHashMap<>(); - - - d.put("status.offline.base", "&c{SERVER} is {STATUS}. &7You are in position &f{POS}&7 of &f{LEN}&7."); - - d.put("status.offline.offline", "offline"); - d.put("status.offline.restarting", "restarting"); - d.put("status.offline.full", "full"); - d.put("status.offline.restricted", "restricted"); - d.put("status.offline.paused", "paused"); - - d.put("status.online.base", "&7You are in position &f{POS}&7 of &f{LEN}&7. Estimated time: {TIME}"); - d.put("status.left-last-queue", "&aYou left the last queue you were in."); - 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("errors.server-not-exist", "&cThe server {SERVER} does not exist!"); - d.put("errors.already-queued", "&cYou are already queued for that server!"); - d.put("errors.player-only", "&cThis command can only be executed as a player!"); - d.put("errors.already-connected", "&cYou are already connected to this server!"); - d.put("errors.cant-join-paused", "&cYou cannot join the queue for {SERVER} because it is paused."); - d.put("errors.deny-joining-from-server", "&cYou are not allowed to join queues from this server!"); - - d.put("commands.leave-queue", "&aYou left the queue for {SERVER}!"); - d.put("commands.reload", "&aConfig and messages reloaded successfully!"); - d.put("commands.joinqueue.usage", "&cUsage: /joinqueue "); - - d.put("noperm", "&cYou do not have permission to do this!"); - - d.put("format.time.mins", "{m}m {s}s"); - d.put("format.time.secs", "{s} seconds"); - - d.put("list.format", "&b{SERVER} &7({COUNT}): {LIST}"); - d.put("list.playerlist", "&9{NAME}&7, "); - d.put("list.total", "&7Total players in queues: &f{TOTAL}"); - d.put("list.none", "&7None"); - - d.put("spigot.actionbar.online", "&7You are queued for &f{SERVER}&7. You are in position &f{POS}&7 of &f{LEN}&7. Estimated time: {TIME}"); - d.put("spigot.actionbar.offline", "&7You are queued for &f{SERVER}&7. &7You are in position &f{POS}&7 of &f{LEN}&7."); - - d.put("send", "&aAdded &f{PLAYER}&a to the queue for &f{SERVER}"); - d.put("remove", "&aRemoved &f{PLAYER} from all queues they were in."); - - d.put("placeholders.queued.none", "None"); - d.put("placeholders.position.none", "None"); - - d.put("commands.leave.more-args", "&cPlease specify which queue you want to leave! &7You are in these queues: {QUEUES}"); - d.put("commands.leave.queues-list-format", "&f{NAME}&7, "); - d.put("commands.leave.not-queued", "&cYou are not queued for that server! &7You are in these queues: {QUEUES}"); - d.put("commands.leave.no-queues", "&cYou are not queued!"); - - d.put("commands.pause.more-args", "&cUsage: /ajqueue pause [on/off]"); - d.put("commands.pause.no-server", "&cThat server does not exist!"); - d.put("commands.pause.success", "&aThe queue for &f{SERVER} &ais now {PAUSED}"); - d.put("commands.pause.paused.true", "&epaused"); - 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.listqueues.header", "&9Queues:"); - d.put("commands.listqueues.format", "{COLOR}{NAME}&7: {COUNT} queued"); - - d.put("max-tries-reached", "&cUnable to connect to {SERVER}. Max retries reached."); - d.put("auto-queued", "&aYou've been auto-queued for {SERVER} because you were kicked."); - - msgs = BungeeMessages.getInstance(this, d); - - aliases = new AliasManager(this); - - moveCommand = new MoveCommand(this); - this.getProxy().getPluginManager().registerCommand(this, moveCommand); - this.getProxy().getPluginManager().registerCommand(this, new ManageCommand(this)); - this.getProxy().getPluginManager().registerCommand(this, new LeaveCommand(this)); - this.getProxy().getPluginManager().registerCommand(this, new ListCommand(this)); - - this.getProxy().getPluginManager().registerListener(this, this); - - getProxy().registerChannel("ajqueue:tospigot"); - getProxy().registerChannel("ajqueue:tobungee"); - - timeBetweenPlayers = config.getDouble("wait-time"); - - isp = Logic.isp; - - man = Manager.getInstance(this); - - - metrics = new BungeeStats(this, 7404); - metrics.addCustomChart(new BungeeStats.SimplePie("premium", () -> isp+"")); - - } - - public boolean isp() { - return isp; - } - - - - public void checkConfig() { - if(config == null) { - getLogger().warning("Config is null!"); - } - List svs = getConfig().getStringList("queue-servers"); - for(String s : svs) { - if(!s.contains(":")) { - getLogger().warning("The queue-servers section in the config has been set up incorrectly! Please read the comment above the setting and make sure you have a queue server and a destination server separated by a colon (:)"); - break; - } - } - } - - public BungeeConfig getConfig() { - return config; - } - - public static BaseComponent[] formatMessage(String text) { - return TextComponent.fromLegacyText(net.md_5.bungee.api.ChatColor.translateAlternateColorCodes('&', text)); - } - - - @EventHandler - public void moveServer(ServerSwitchEvent e) { - ProxiedPlayer p = e.getPlayer(); - List alreadyqueued = man.findPlayerInQueue(p); - for(QueueServer ser : alreadyqueued) { - List queue = ser.getQueue(); - int pos = queue.indexOf(p); - if((pos == 0 && ser.getInfos().contains(p.getServer().getInfo())) || config.getBoolean("remove-player-on-server-switch")) { - queue.remove(p); - ser.setLastSentTime(System.currentTimeMillis()); - Manager.getInstance().sendingAttempts.remove(p); - } - } - - String servername = e.getPlayer().getServer().getInfo().getName(); - List svs = config.getStringList("queue-servers"); - for(String s : svs) { - if(!s.contains(":")) continue; - String[] parts = s.split(":"); - String from = parts[0]; - String to = parts[1]; - if(from.equalsIgnoreCase(servername)) { - man.addToQueue(p, to); - } - } - } - - @EventHandler - public void onLeave(PlayerDisconnectEvent e) { - ProxiedPlayer p = e.getPlayer(); - //if(p.hasPermission("ajqueue.stay-queued-on-leave")) return; - List servers = man.findPlayerInQueue(p); - for(QueueServer server : servers) { - server.getQueue().remove(p); - } - man.sendingNowAntiSpam.remove(p); - } - - @EventHandler - public void onFailedMove(ServerKickEvent e) { - final ProxiedPlayer p = e.getPlayer(); - List queuedServers = man.findPlayerInQueue(p); - - - if(!queuedServers.contains(man.getServer(e.getKickedFrom().getName())) && config.getBoolean("auto-add-to-queue-on-kick")) { - - StringBuilder plainReason = new StringBuilder(); - for(BaseComponent b : e.getKickReasonComponent()) { - plainReason.append(b.toPlainText()); - } - - List reasons = config.getStringList("auto-add-kick-reasons"); - boolean shouldqueue = false; - for(String reason : reasons) { - if(plainReason.toString().toLowerCase().contains(reason.toLowerCase())) { - shouldqueue = true; - break; - } - } - if(shouldqueue || reasons.isEmpty()) { - plugin.getProxy().getScheduler().schedule(this, () -> { - if(!p.isConnected()) return; - - String toName = e.getKickedFrom().getName(); - p.sendMessage(msgs.getBC("auto-queued", "SERVER:"+toName)); - man.addToQueue(p, toName); - }, (long) (config.getDouble("auto-add-to-queue-on-kick-delay")*1000), TimeUnit.MILLISECONDS); - return; - } - - } - - - for(QueueServer server : queuedServers) { - if(!(server.getInfos().contains(e.getKickedFrom()))) continue; - if(server.getQueue().indexOf(p) != 0) continue; - List kickreasons = config.getStringList("kick-reasons"); - //getLogger().info(e.getKickReasonComponent()); - StringBuilder plainReason = new StringBuilder(); - for(BaseComponent b : e.getKickReasonComponent()) { - plainReason.append(b.toPlainText()); - } - for(String reason : kickreasons) { - if(plainReason.toString().toLowerCase().contains(reason.toLowerCase())) { - server.getQueue().remove(p); - } - } - if(config.getBoolean("send-fail-debug")) { - StringBuilder r = new StringBuilder(); - for(BaseComponent b : e.getKickReasonComponent()) { - r.append(b.toPlainText()); - } - getLogger().warning("Failed to send "+p.getName()+" to "+e.getKickedFrom().getName()+" because "+r); - } - } - } - - - @EventHandler - public void onMessage(PluginMessageEvent e) { - //getLogger().info("Recieved message of "+e.getTag()); - if(e.getTag().equals("ajqueue:tospigot")) { - e.setCancelled(true); - return; - } - if(!e.getTag().equals("ajqueue:tobungee")) return; - if(!(e.getReceiver() instanceof ProxiedPlayer)) return; - e.setCancelled(true); - DataInputStream in = new DataInputStream(new ByteArrayInputStream(e.getData())); - try { - String subchannel = in.readUTF(); - ProxiedPlayer player = (ProxiedPlayer) e.getReceiver(); - - - if(subchannel.equals("queue")) { - String data = in.readUTF(); - String[] args = new String[1]; - args[0] = data; - moveCommand.execute(player, args); - //man.addToQueue(player, data); - - } - if(subchannel.equals("massqueue")) { - String data = in.readUTF(); - String[] parts = data.split(","); - for(String part : parts) { - String[] pparts = part.split(":"); - if(pparts.length < 2) continue; - String pname = pparts[0]; - String pserver = pparts[1]; - ProxiedPlayer p = ProxyServer.getInstance().getPlayer(pname); - String[] args = new String[1]; - args[0] = pserver; - moveCommand.execute(p, args); - } - } - if(subchannel.equals("queuename")) { - BungeeUtils.sendCustomData(player, "queuename", aliases.getAlias(man.getQueuedName(player))); - } - if(subchannel.equals("position")) { - QueueServer server = man.getSingleServer(player); - String pos = msgs.getString("placeholders.position.none"); - if(server != null) { - pos = server.getQueue().indexOf(player)+1+""; - } - BungeeUtils.sendCustomData(player, "position", pos); - } - if(subchannel.equals("positionof")) { - QueueServer server = man.getSingleServer(player); - String pos = msgs.getString("placeholders.position.none"); - if(server != null) { - pos = server.getQueue().size()+""; - } - BungeeUtils.sendCustomData(player, "positionof", pos); - } - if(subchannel.equals("inqueue")) { - QueueServer server = man.getSingleServer(player); - BungeeUtils.sendCustomData(player, "inqueue", (server != null)+""); - } - if(subchannel.equals("queuedfor")) { - String srv = in.readUTF(); - QueueServer server = man.findServer(srv); - if(server == null) return; - BungeeUtils.sendCustomData(player, "queuedfor", srv, server.getQueue().size()+""); - } - if(subchannel.equals("leavequeue")) { - String arg = ""; - try { - arg = in.readUTF(); - } catch(Exception ignored) {} - getProxy().getPluginManager().dispatchCommand(player, "leavequeue"+arg); - } - - } catch (IOException e1) { - getLogger().warning("An error occured while reading data from spigot side:"); - e1.printStackTrace(); - } - } - -} diff --git a/src/main/java/us/ajg0702/queue/Manager.java b/src/main/java/us/ajg0702/queue/Manager.java deleted file mode 100644 index 1014659..0000000 --- a/src/main/java/us/ajg0702/queue/Manager.java +++ /dev/null @@ -1,648 +0,0 @@ -package us.ajg0702.queue; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import net.md_5.bungee.api.ChatMessageType; -import net.md_5.bungee.api.ProxyServer; -import net.md_5.bungee.api.ServerPing; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.TextComponent; -import net.md_5.bungee.api.config.ServerInfo; -import net.md_5.bungee.api.connection.ProxiedPlayer; -import us.ajg0702.utils.GenUtils; -import us.ajg0702.utils.bungee.BungeeMessages; -import us.ajg0702.utils.bungee.BungeeUtils; - -public class Manager { - - static Manager INSTANCE = null; - public static Manager getInstance(Main pl) { - if(INSTANCE == null) { - INSTANCE = new Manager(pl); - } - return INSTANCE; - } - public static Manager getInstance() { - return INSTANCE; - } - - BungeeMessages msgs; - - - Main pl; - private Manager(Main pl) { - this.pl = pl; - msgs = BungeeMessages.getInstance(); - reloadIntervals(); - if(!pl.config.getBoolean("wait-to-load-servers")) { - pl.getProxy().getScheduler().schedule(pl, this::reloadServers, 0, TimeUnit.MILLISECONDS); - } else { - pl.getProxy().getScheduler().schedule(pl, this::reloadServers, pl.config.getInt("wait-to-load-servers-delay"), TimeUnit.MILLISECONDS); - } - } - - /* - * Returns all servers - */ - public List getServers() { - return servers; - } - - /** - * Returns the name of all servers and groups - * @return The names of all servers and groups - */ - public List getServerNames() { - List names = new ArrayList<>(); - for(QueueServer s : servers) { - names.add(s.getName()); - } - return names; - } - - - - int sendId = -1; - int updateId = -1; - int messagerId = -1; - int actionbarId = -1; - int srvRefId = -1; - int queueEventId = -1; - /** - * Clears all intervals and re-makes them - */ - public void reloadIntervals() { - if(sendId != -1) { - try { - pl.getProxy().getScheduler().cancel(sendId); - } catch(IllegalArgumentException ignored) {} - sendId = -1; - } - if(updateId != -1) { - try { - pl.getProxy().getScheduler().cancel(updateId); - } catch(IllegalArgumentException ignored) {} - updateId = -1; - } - if(messagerId != -1) { - try { - pl.getProxy().getScheduler().cancel(messagerId); - } catch(IllegalArgumentException ignored) {} - messagerId = -1; - } - if(actionbarId != -1) { - try { - pl.getProxy().getScheduler().cancel(actionbarId); - } catch(IllegalArgumentException ignored) {} - actionbarId = -1; - } - if(srvRefId != -1) { - try { - pl.getProxy().getScheduler().cancel(srvRefId); - } catch(IllegalArgumentException ignored) {} - srvRefId = -1; - } - if(queueEventId != -1) { - try { - pl.getProxy().getScheduler().cancel(queueEventId); - } catch(IllegalArgumentException ignored) {} - queueEventId = -1; - } - - queueEventId = pl.getProxy().getScheduler().schedule(pl, this::sendQueueEvents, 2, 2, TimeUnit.SECONDS).getId(); - - sendId = pl.getProxy().getScheduler().schedule(pl, this::sendPlayers, 2, Math.round(pl.timeBetweenPlayers*1000), TimeUnit.MILLISECONDS).getId(); - - updateId = pl.getProxy().getScheduler().schedule(pl, this::updateServers, 0, Math.max(Math.round(pl.timeBetweenPlayers), 2), TimeUnit.SECONDS).getId(); - //pl.getLogger().info("Time: "+pl.timeBetweenPlayers); - - messagerId = pl.getProxy().getScheduler().schedule(pl, this::sendMessages, 0, pl.getConfig().getInt("message-time"), TimeUnit.SECONDS).getId(); - actionbarId = pl.getProxy().getScheduler().schedule(pl, this::sendActionBars, 0, 2, TimeUnit.SECONDS).getId(); - - if(pl.config.getInt("reload-servers-interval") > 0) { - srvRefId = pl.getProxy().getScheduler().schedule(pl, this::updateServers, pl.config.getInt("reload-servers-interval"), pl.config.getInt("reload-servers-interval"), TimeUnit.SECONDS).getId(); - } - } - - /** - * Get the name of the server the player is queued for. - * If multiple servers are queued for, it will use the multi-server-queue-pick option in the config - * @param p The player - * @return The name of the server, the placeholder none message if not queued - */ - public String getQueuedName(ProxiedPlayer p) { - List queued = findPlayerInQueue(p); - if(queued.size() <= 0) { - return msgs.getString("placeholders.queued.none"); - } - QueueServer selected = queued.get(0); - - if(pl.config.getString("multi-server-queue-pick").equalsIgnoreCase("last")) { - selected = queued.get(queued.size()-1); - } - - return selected.getName(); - } - - /** - * Get a single server the player is queued for. Depends on the multi-server-queue-pick option in the config - * @param p The player - * @return The server that was chosen that the player is queued for. - */ - public QueueServer getSingleServer(ProxiedPlayer p) { - List queued = findPlayerInQueue(p); - if(queued.size() <= 0) { - return null; - } - QueueServer selected = queued.get(0); - - if(pl.config.getString("multi-server-queue-pick").equalsIgnoreCase("last")) { - selected = queued.get(queued.size()-1); - } - return selected; - } - - - - - List servers = new ArrayList<>(); - /** - * Checks servers that are in bungeecord and adds any it doesnt - * know about. - * - * Also creates/edits server groups - */ - public synchronized void reloadServers() { - if(pl.config == null) { - pl.getLogger().warning("[MAN] Config is null"); - } - Map svs = ProxyServer.getInstance().getServers(); - for(String name : svs.keySet()) { - if(findServer(name) != null) continue; - ServerInfo info = svs.get(name); - //pl.getLogger().info("Adding server "+name); - servers.add(new QueueServer(name, info)); - } - - List groupsraw = pl.config.getStringList("server-groups"); - for(String groupraw : groupsraw) { - if(groupraw.isEmpty()) { - pl.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(getServer(groupname) != null) { - pl.getLogger().warning("The name of a group ('"+groupname+"') cannot be the same as the name of a server!"); - continue; - } - - List servers = new ArrayList<>(); - - 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)); - } - } - - /** - * Sends actionbar updates to all players in all queues with their - * position in the queue and time remaining - */ - public synchronized void sendActionBars() { - if(!pl.getConfig().getBoolean("send-actionbar")) return; - - for(ProxiedPlayer p : ProxyServer.getInstance().getPlayers()) { - QueueServer s = this.getSingleServer(p); - - if(s == null) continue; - List plys = s.getQueue(); - int pos = plys.indexOf(p)+1; - if(pos == 0) { - plys.remove(p); - continue; - } - - int len = plys.size(); - if(!s.isJoinable(p)) { - - String status = s.getStatusString(p); - - - p.sendMessage(ChatMessageType.ACTION_BAR, msgs.getBC("spigot.actionbar.offline", - "POS:"+pos, - "LEN:"+len, - "SERVER:"+pl.aliases.getAlias(s.getName()), - "STATUS:"+status)); - } else { - int time = (int) Math.round(pos*pl.timeBetweenPlayers); - int min = (int) Math.floor((time) / (60.0)); - int sec = (int) Math.floor((time % (60.0))); - String timeStr; - if(min <= 0) { - timeStr = msgs.getString("format.time.secs") - .replaceAll("\\{m}", "0") - .replaceAll("\\{s}", sec+""); - } else { - timeStr = msgs.getString("format.time.mins") - .replaceAll("\\{m}", min+"") - .replaceAll("\\{s}", sec+""); - } - p.sendMessage(ChatMessageType.ACTION_BAR, msgs.getBC("spigot.actionbar.online", - "POS:"+pos, - "LEN:"+len, - "SERVER:"+pl.aliases.getAlias(s.getName()), - "TIME:"+timeStr)); - } - } - - } - - - public synchronized void sendQueueEvents() { - for (QueueServer s : servers) { - for (ProxiedPlayer player : s.getQueue()) { - if (player == null) continue; - if (!player.isConnected()) continue; - BungeeUtils.sendCustomData(player, "inqueueevent", "true"); - } - } - } - - /** - * Sends the message to the player updating them on their position in the queue - * along with their time remaining - */ - public synchronized void sendMessages() { - for(QueueServer s : servers) { - List plys = s.getQueue(); - Iterator it = plys.iterator(); - while(it.hasNext()) { - ProxiedPlayer ply = it.next(); - int pos = plys.indexOf(ply)+1; - if(pos == 0) { - it.remove(); - continue; - } - sendMessage(ply, s); - } - } - } - /** - * Sends a status message to a player - * @param ply The player to send the message to - * @param s The QueueServer the message should be about - */ - public synchronized void sendMessage(ProxiedPlayer ply, QueueServer s) { - List plys = s.getQueue(); - int pos = plys.indexOf(ply)+1; - if(pos == 0) return; - int len = plys.size(); - if(!s.isJoinable(ply)) { - - String status = s.getStatusString(ply); - - if(status.isEmpty()) return; - - ply.sendMessage(msgs.getBC("status.offline.base", - "STATUS:"+status, - "POS:"+pos, - "LEN:"+len, - "SERVER:"+pl.aliases.getAlias(s.getName()) - )); - } else { - if(msgs.getString("spigot.actionbar.offline").isEmpty()) return; - int time = (int) Math.round(pos*pl.timeBetweenPlayers); - int min = (int) Math.floor((time) / (60.0)); - int sec = (int) Math.floor((time % (60.0))); - String timeStr; - if(min <= 0) { - timeStr = msgs.getString("format.time.secs") - .replaceAll("\\{m}", "0") - .replaceAll("\\{s}", sec+""); - } else { - timeStr = msgs.getString("format.time.mins") - .replaceAll("\\{m}", min+"") - .replaceAll("\\{s}", sec+""); - } - ply.sendMessage(msgs.getBC("status.online.base", - "TIME:"+timeStr, - "POS:"+pos, - "LEN:"+len, - "SERVER:"+pl.aliases.getAlias(s.getName()) - )); - } - } - - /** - * Find a server by name - * @param name Name of the server - * @return The server if it exists (otherwise null) - */ - public QueueServer findServer(String name) { - for(QueueServer server : servers) { - if(server == null) continue; - if(server.getName().equalsIgnoreCase(name)) { - return server; - } - } - return null; - } - - /** - * Updates info about servers. - */ - public synchronized void updateServers() { - for (QueueServer server : servers) { - server.update(); - } - } - - /** - * Gets the ideal server in a server group. - * @param s The group to check - * @param p The player to check - * @return the ideal server - */ - public ServerInfo getIdealServer(QueueServer s, ProxiedPlayer p) { - HashMap serverInfos = s.getLastPings(); - ServerInfo selected = null; - int selectednum = 0; - if(serverInfos.keySet().size() == 1) { - selected = serverInfos.keySet().iterator().next(); - } else { - for(ServerInfo si : serverInfos.keySet()) { - ServerPing sp = serverInfos.get(si); - if(sp == null) continue; - if(sp.getPlayers() == null) continue; - int online = sp.getPlayers().getOnline(); - if(selected == null) { - selected = si; - selectednum = online; - continue; - } - if(selectednum > online && findServer(si.getName()).isJoinable(p)) { - selected = si; - selectednum = online; - } - } - } - if(selected == null && serverInfos.size() > 0) { - selected = serverInfos.keySet().iterator().next(); - } - if(selected == null) { - pl.getLogger().warning("Unable to find ideal server, using random server from group."); - int r = GenUtils.randomInt(0, s.getInfos().size()-1); - selected = s.getInfos().get(r); - } - return selected; - } - - /** - * Attempts to send the first player in all queues - */ - public void sendPlayers() { - sendPlayers(null); - } - - HashMap sendingNowAntiSpam = new HashMap<>(); - HashMap sendingAttempts = new HashMap<>(); - - /** - * Attempts to send the first player in this queue - * @param server The server to send the first player in the queue. null for all servers. - */ - public void sendPlayers(String server) { - for(QueueServer s : servers) { - String name = s.getName(); - if(server != null && !server.equals(name)) continue; - if(!s.isOnline()) continue; - if(s.getQueue().size() <= 0) continue; - - if(pl.config.getBoolean("send-all-when-back-online") && s.justWentOnline() && s.isOnline()) { - - - for(ProxiedPlayer p : s.getQueue()) { - - if(s.isFull() && !p.hasPermission("ajqueue.joinfull")) continue; - - ServerInfo selected = getIdealServer(s, p); - if(selected == null) { - pl.getLogger().severe("Could not find ideal server for server/group '"+s.getName()+"'!"); - continue; - } - - p.sendMessage(msgs.getBC("status.sending-now", "SERVER:"+pl.aliases.getAlias(name))); - p.connect(selected); - } - return; - } - - ProxiedPlayer nextplayer = s.getQueue().get(0); - if(nextplayer == null) { - if(s.getQueue().size() > 0) { - s.getQueue().remove(0); - } - continue; - } - - if(!s.canAccess(nextplayer)) continue; - - - if(s.getQueue().size() <= 0) continue; - while(!nextplayer.isConnected()) { - s.getQueue().remove(nextplayer); - if(s.getQueue().size() <= 0) break; - nextplayer = s.getQueue().get(0); - } - while(nextplayer.getServer().getInfo().getName().equals(s.getName())) { - s.getQueue().remove(nextplayer); - if(s.getQueue().size() <= 0) break; - nextplayer = s.getQueue().get(0); - } - if(s.getQueue().size() <= 0) continue; - if(s.isFull() && !nextplayer.hasPermission("ajqueue.joinfull")) continue; - - if(pl.config.getBoolean("enable-bypasspaused-permission")) { - if(s.isPaused() && !nextplayer.hasPermission("ajqueue.bypasspaused")) continue; - } else if(s.isPaused()) { continue; } - - - int tries = sendingAttempts.get(nextplayer) == null ? 0 : sendingAttempts.get(nextplayer); - int maxTries = pl.config.getInt("max-tries"); - if(tries >= maxTries && maxTries > 0) { - s.getQueue().remove(nextplayer); - sendingAttempts.remove(nextplayer); - nextplayer.sendMessage(msgs.getBC("max-tries-reached", "SERVER:"+pl.aliases.getAlias(s.getName()))); - continue; - } - tries++; - sendingAttempts.put(nextplayer, tries); - - if(!sendingNowAntiSpam.containsKey(nextplayer)) { - sendingNowAntiSpam.put(nextplayer, (long) 0); - } - if(System.currentTimeMillis() - sendingNowAntiSpam.get(nextplayer) >= 5000) { - nextplayer.sendMessage(msgs.getBC("status.sending-now", "SERVER:"+pl.aliases.getAlias(s.getName()))); - sendingNowAntiSpam.put(nextplayer, System.currentTimeMillis()); - } - - - - ServerInfo selected = getIdealServer(s, nextplayer); - if(selected == null) { - pl.getLogger().severe("Could not find ideal server for server/group '"+s.getName()+"'!"); - continue; - } - nextplayer.connect(selected); - } - } - - /** - * Add a player to the queue for a server - * @param p The player - * @param s The name of the server - */ - public synchronized void addToQueue(ProxiedPlayer p, String s) { - if(p == null || s == null) return; - QueueServer server = findServer(s); - if(server == null) { - p.sendMessage(msgs.getBC("errors.server-not-exist")); - return; - } - if(!p.isConnected()) return; - - if(pl.config.getBoolean("joinfrom-server-permission") && !p.hasPermission("ajqueue.joinfrom."+p.getServer().getInfo().getName())) { - p.sendMessage(msgs.getBC("errors.deny-joining-from-server")); - return; - } - - if(server.isPaused() && pl.config.getBoolean("prevent-joining-paused")) { - p.sendMessage(msgs.getBC("errors.cant-join-paused", "SERVER:"+pl.aliases.getAlias(server.getName()))); - return; - } - - if(p.getServer().getInfo().getName().equals(s)) { - p.sendMessage(msgs.getBC("errors.already-connected", "SERVER:"+pl.aliases.getAlias(server.getName()))); - return; - } - - List beforeQueues = findPlayerInQueue(p); - if(beforeQueues.size() > 0) { - if(beforeQueues.contains(server)) { - p.sendMessage(msgs.getBC("errors.already-queued")); - return; - } - if(!pl.config.getBoolean("allow-multiple-queues")) { - p.sendMessage(msgs.getBC("status.left-last-queue", "SERVER:"+pl.aliases.getAlias(server.getName()))); - for(QueueServer ser : beforeQueues) { - ser.getQueue().remove(p); - } - } - } - - List list = server.getQueue(); - if(list.contains(p)) { - int pos = list.indexOf(p)+1; - int len = list.size(); - p.sendMessage(msgs.getBC("errors.already-queued", - "POS:"+pos, - "LEN:"+len - )); - return; - } - if(pl.isp) { - Logic.priorityLogic(server.getQueue(), s, p); - } else { - if((p.hasPermission("ajqueue.priority") || p.hasPermission("ajqueue.serverpriority."+s)) && list.size() > 0) { - //p.sendMessage(Main.formatMessage("in priority")); - int i = 0; - for(ProxiedPlayer ply : list) { - if(!(ply.hasPermission("ajqueue.priority") || ply.hasPermission("ajqueue.serverpriority."+s))) { - //p.sendMessage(Main.formatMessage("Adding beind: "+i)); - list.add(i, p); - break; - } - i++; - } - //p.sendMessage(Main.formatMessage("after loop")); - if(list.size() == 0) { - list.add(p); - } else if(!list.contains(p)) { - list.add(p); - } - } else { - //p.sendMessage(Main.formatMessage("normal add")); - list.add(p); - } - } - int pos = list.indexOf(p)+1; - int len = list.size(); - - - boolean sendInstant = pl.config.getStringList("send-instantly").contains(server.getName()) || server.isJoinable(p); - boolean sendInstantp = list.size() <= 1 && server.canAccess(p); - boolean timeGood = !pl.config.getBoolean("check-last-player-sent-time") || System.currentTimeMillis() - server.getLastSentTime() > Math.floor(pl.getConfig().getDouble("wait-time") * 1000); - - if((sendInstant && (sendInstantp && timeGood))) { - sendPlayers(s); - //p.sendMessage(Main.formatMessage("sending instant")); - BaseComponent[] m = msgs.getBC("status.now-in-empty-queue", "POS:"+pos, "LEN:"+len, "SERVER:"+pl.aliases.getAlias(s)); - if(TextComponent.toPlainText(m).length() > 0) { - p.sendMessage(m); - } - } else { - p.sendMessage(msgs.getBC("status.now-in-queue", - "POS:"+pos, - "LEN:"+len, - "SERVER:"+pl.aliases.getAlias(server.getName()), - "SERVERNAME:"+server.getName() - )); - } - //p.sendMessage(Main.formatMessage(sendInstant+" && ("+sendInstantp+" && " + timeGood+")")); - - 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"); - } - - /** - * Finds which servers the player is queued for - * @param p The player to search for - * @return The servers the player is queued for. - */ - public List findPlayerInQueue(ProxiedPlayer p) { - List srs = new ArrayList<>(); - for(QueueServer s : servers) { - if(s.getQueue().contains(p)) { - srs.add(s); - } - } - return srs; - } - - public QueueServer getServer(String name) { - return findServer(name); - } -} diff --git a/src/main/java/us/ajg0702/queue/QueueServer.java b/src/main/java/us/ajg0702/queue/QueueServer.java deleted file mode 100644 index 6e51bc0..0000000 --- a/src/main/java/us/ajg0702/queue/QueueServer.java +++ /dev/null @@ -1,248 +0,0 @@ -package us.ajg0702.queue; - -import java.util.*; - -import net.md_5.bungee.api.Callback; -import net.md_5.bungee.api.ProxyServer; -import net.md_5.bungee.api.ServerPing; -import net.md_5.bungee.api.config.ServerInfo; -import net.md_5.bungee.api.connection.ProxiedPlayer; -import us.ajg0702.utils.bungee.BungeeConfig; -import us.ajg0702.utils.bungee.BungeeMessages; - -public class QueueServer { - - String name; - List servers; - - public QueueServer(String name, ServerInfo info) { - init(name, Collections.singletonList(info)); - } - public QueueServer(String name, List infos) { - init(name, infos); - } - private void init(String name, List infos) { - if(Manager.getInstance() == null || Main.plugin.getConfig() == null) { - ProxyServer.getInstance().getLogger() - .warning("[ajQueue] Something is loading a QueueServer too early! The plugin hasnt fully loaded yet!"); - } - this.name = name; - this.servers = infos; - update(); - } - - public void setInfos(List infos) { - servers = infos; - } - - public String getName() { - return name; - } - public List getInfos() { - return servers; - } - - int offlineTime = 0; - boolean online = false; - int playercount = 0; - int maxplayers = 0; - long lastUpdate = -1; - HashMap pings = new HashMap<>(); - public void update() { - pings = new HashMap<>(); - for(final ServerInfo info : getInfos()) { - if(Main.plugin.getConfig().getBoolean("pinger-debug")) { - Main.plugin.getLogger().info("[pinger] ["+info.getName()+"] sending ping"); - } - info.ping((result, error) -> { - if(Manager.getInstance() == null || Main.plugin.getConfig() == null) { - ProxyServer.getInstance().getLogger() - .warning("[ajQueue] Something used update() too early! The plugin hasnt fully loaded yet!"); - return; - } - boolean online = error == null; - BungeeConfig config = Main.plugin.getConfig(); - - if(config.getBoolean("pinger-debug")) { - if(error != null) { - ProxyServer.getInstance().getLogger().info("[ajQueue] [pinger] ["+name+"] Status: offline. Error: "); - error.printStackTrace(); - } else { - ProxyServer.getInstance().getLogger().info("[ajQueue] [pinger] ["+name+"] Status: online. motd: " - +result.getDescriptionComponent()+" players:"+result.getPlayers()); - } - } - - - pings.put(info, online ? result : null); - if(pings.size() == servers.size()) allDonePing(); - }); - } - } - - public String getStatusString(ProxiedPlayer p) { - BungeeMessages msgs = Main.plugin.msgs; - - if(getOfflineTime() > Main.plugin.getConfig().getInt("offline-time")) { - return msgs.getString("status.offline.offline"); - } - - if(!isOnline()) { - return msgs.getString("status.offline.restarting"); - } - - if(isPaused()) { - return msgs.getString("status.offline.paused"); - } - - if(isFull()) { - return msgs.getString("status.offline.full"); - } - - if(p != null && !canAccess(p)) { - return msgs.getString("status.offline.restricted"); - } - - - return "Online"; - } - - public HashMap getLastPings() { - return pings; - } - - private void allDonePing() { - int onlineCount = 0; - playercount = 0; - maxplayers = 0; - for(ServerInfo info : pings.keySet()) { - ServerPing ping = pings.get(info); - if(ping == null) { - continue; - } - onlineCount++; - playercount += ping.getPlayers().getOnline(); - maxplayers += ping.getPlayers().getMax(); - } - online = onlineCount > 0; - - if(lastUpdate == -1) { - lastUpdate = System.currentTimeMillis(); - offlineTime = 0; - } else { - int timesincelast = (int) Math.round((System.currentTimeMillis() - lastUpdate*1.0)/1000); - lastUpdate = System.currentTimeMillis(); - if(!online) { - offlineTime += timesincelast; - } else { - offlineTime = 0; - } - } - } - - public int getOfflineTime() { - return offlineTime; - } - long lastOffline = 0; - public boolean isOnline() { - BungeeConfig config = Main.plugin.getConfig(); - if(System.currentTimeMillis()-lastOffline <= (config.getInt("wait-after-online")*1000) && online) { - return false; - } - if(!online) { - lastOffline = System.currentTimeMillis(); - } - return online; - } - - public boolean justWentOnline() { - BungeeConfig config = Main.plugin.getConfig(); - return System.currentTimeMillis()-lastOffline <= (config.getDouble("wait-time")) && online; - } - - public boolean isFull() { - return playercount >= maxplayers; - } - - - List queue = new ArrayList<>(); - public synchronized List getQueue() { - return queue; - } - - /** - * If the player can access the server. (Bungeecord's restricted servers) - * @param ply The player - * @return if the player can join based on bungeecord's restricted servers system - */ - public boolean canAccess(ProxiedPlayer ply) { - if(ply == null) return true; - boolean ca = false; - for(ServerInfo si : servers) { - if(si.canAccess(ply)) { - ca = true; - break; - } - } - return ca; - } - - - long lastSent = 0; - public long getLastSentTime() { - return lastSent; - } - public void setLastSentTime(long newLastSent) { - lastSent = newLastSent; - } - - - boolean whitelisted = false; - List whitelistedplayers = new ArrayList<>(); - public void setWhitelisted(boolean b) { - whitelisted = b; - } - public void setWhitelistedPlayers(List plys) { - whitelistedplayers = plys; - } - public boolean getWhitelisted() { - return whitelisted; - } - public boolean isWhitelisted() { - return whitelisted; - } - public List getWhitelistedPlayers() { - return whitelistedplayers; - } - - /** - * If the server is joinable as a player - * @param p The player - * @return If the player can join the server - */ - public boolean isJoinable(ProxiedPlayer p) { - return (!whitelisted || whitelistedplayers.contains(p.getName())) && - this.isOnline() && - this.canAccess(p) && - !this.isFull() && - !this.isPaused(); - - } - public String getJoinableDebug(ProxiedPlayer p) { - return "whitelist: "+(!whitelisted || whitelistedplayers.contains(p.getName())) + "\n" + - "online: "+this.isOnline() +"\n"+ - "canaccess: "+this.canAccess(p) +"\n"+ - "full: "+ !this.isFull() +"\n"+ - "paused: "+!this.isPaused()+"\n"+ - "- joinable: "+isJoinable(p); - } - - - boolean paused = false; - public boolean isPaused() { - return paused; - } - public void setPaused(boolean to) { - paused = to; - } -} diff --git a/src/main/java/us/ajg0702/queue/commands/LeaveCommand.java b/src/main/java/us/ajg0702/queue/commands/LeaveCommand.java deleted file mode 100644 index 87e9521..0000000 --- a/src/main/java/us/ajg0702/queue/commands/LeaveCommand.java +++ /dev/null @@ -1,75 +0,0 @@ -package us.ajg0702.queue.commands; - -import java.util.List; - -import net.md_5.bungee.api.CommandSender; -import net.md_5.bungee.api.connection.ProxiedPlayer; -import net.md_5.bungee.api.plugin.Command; -import us.ajg0702.queue.Main; -import us.ajg0702.queue.Manager; -import us.ajg0702.queue.QueueServer; -import us.ajg0702.utils.bungee.BungeeMessages; - -public class LeaveCommand extends Command { - Main plugin; - BungeeMessages msgs; - public LeaveCommand(Main pl) { - super("leavequeue", null, "leaveq"); - this.plugin = pl; - msgs = BungeeMessages.getInstance(); - - } - @Override - public void execute(CommandSender sender, String[] args) { - if(!(sender instanceof ProxiedPlayer)) { - sender.sendMessage(msgs.getBC("errors.player-only")); - return; - } - Manager man = Manager.getInstance(); - ProxiedPlayer p = (ProxiedPlayer) sender; - List servers = man.findPlayerInQueue(p); - - if(servers.size() == 0) { - p.sendMessage(msgs.getBC("commands.leave.no-queues")); - return; - } - - if(servers.size() == 1) { - servers.get(0).getQueue().remove(p); - p.sendMessage(msgs.getBC("commands.leave-queue", "SERVER:"+plugin.aliases.getAlias(servers.get(0).getName()))); - return; - } - - - if(args.length <= 0) { - p.sendMessage(msgs.getBC("commands.leave.more-args", "QUEUES:"+getQueueList(servers))); - return; - } - - String leaving = args[0]; - QueueServer leavingsrv = man.getServer(leaving); - if(leavingsrv == null) { - p.sendMessage(msgs.getBC("commands.leave.not-queued", "QUEUES:"+getQueueList(servers))); - return; - } - if(leavingsrv.getQueue().indexOf(p) == -1) { - p.sendMessage(msgs.getBC("commands.leave.not-queued", "QUEUES:"+getQueueList(servers))); - return; - } - - leavingsrv.getQueue().remove(p); - p.sendMessage(msgs.getBC("commands.leave-queue", "SERVER:"+plugin.aliases.getAlias(leavingsrv.getName()))); - - } - - private String getQueueList(List servers) { - StringBuilder queueList = new StringBuilder(); - for(QueueServer server : servers) { - queueList.append(msgs.getString("commands.leave.queues-list-format").replaceAll("\\{NAME\\}", server.getName())); - } - if(queueList.length() > 2) { - queueList = new StringBuilder(queueList.substring(0, queueList.length() - 2)); - } - return queueList.toString(); - } -} diff --git a/src/main/java/us/ajg0702/queue/commands/ListCommand.java b/src/main/java/us/ajg0702/queue/commands/ListCommand.java deleted file mode 100644 index 1d53230..0000000 --- a/src/main/java/us/ajg0702/queue/commands/ListCommand.java +++ /dev/null @@ -1,59 +0,0 @@ -package us.ajg0702.queue.commands; - -import net.md_5.bungee.api.CommandSender; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.TextComponent; -import net.md_5.bungee.api.connection.ProxiedPlayer; -import net.md_5.bungee.api.plugin.Command; -import us.ajg0702.queue.Main; -import us.ajg0702.queue.Manager; -import us.ajg0702.queue.QueueServer; -import us.ajg0702.utils.bungee.BungeeMessages; - -import java.util.ArrayList; -import java.util.Arrays; - -public class ListCommand extends Command { - Main pl; - BungeeMessages msgs; - - public ListCommand(Main pl) { - super("listqueues", null, "listq"); - this.pl = pl; - msgs = BungeeMessages.getInstance(); - } - - @Override - public void execute(CommandSender sender, String[] args) { - if(!sender.hasPermission("ajqueue.listqueues")) { - sender.sendMessage(msgs.getBC("noperm")); - return; - } - - ProxiedPlayer spp = null; - if(sender instanceof ProxiedPlayer) { - spp = (ProxiedPlayer) sender; - } - - ArrayList m = new ArrayList<>(Arrays.asList(msgs.getBC("commands.listqueues.header"))); - for(QueueServer s : Manager.getInstance().getServers()) { - String color = "&a"; - if(!s.isOnline()) { - color = "&c"; - } else if(!s.isJoinable(spp)) { - color = "&e"; - } - - m.addAll(Arrays.asList(TextComponent.fromLegacyText("\n"))); - m.addAll(Arrays.asList(msgs.getBC("commands.listqueues.format", - "COLOR:" + msgs.color(color), - "NAME:" + s.getName(), - "COUNT:" + s.getQueue().size(), - "STATUS:" + s.getStatusString(spp) - ))); - } - - sender.sendMessage(m.toArray(new BaseComponent[m.size()-1])); - - } -} diff --git a/src/main/java/us/ajg0702/queue/commands/ManageCommand.java b/src/main/java/us/ajg0702/queue/commands/ManageCommand.java deleted file mode 100644 index 5262a4b..0000000 --- a/src/main/java/us/ajg0702/queue/commands/ManageCommand.java +++ /dev/null @@ -1,267 +0,0 @@ -package us.ajg0702.queue.commands; - -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.PatternReplacementResult; -import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; -import net.md_5.bungee.api.CommandSender; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.TextComponent; -import net.md_5.bungee.api.config.ServerInfo; -import net.md_5.bungee.api.connection.ProxiedPlayer; -import net.md_5.bungee.api.plugin.Command; -import net.md_5.bungee.api.plugin.TabExecutor; -import us.ajg0702.queue.Main; -import us.ajg0702.queue.Manager; -import us.ajg0702.queue.QueueServer; -import us.ajg0702.utils.bungee.BungeeMessages; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.regex.Pattern; - -public class ManageCommand extends Command implements TabExecutor { - - Main pl; - BungeeMessages msgs; - - public ManageCommand(Main pl) { - super("ajqueue", null, "ajq"); - this.pl = pl; - msgs = BungeeMessages.getInstance(); - } - - - - @Override - public void execute(CommandSender sender, String[] args) { - if(args.length == 1) { - if(args[0].equalsIgnoreCase("reload")) { - if(!sender.hasPermission("ajqueue.reload")) { - sender.sendMessage(msgs.getBC("noperm")); - return; - } - msgs.reload(); - pl.getConfig().reload(); - pl.timeBetweenPlayers = pl.getConfig().getDouble("wait-time"); - Manager.getInstance().reloadIntervals(); - Manager.getInstance().reloadServers(); - pl.checkConfig(); - sender.sendMessage(msgs.getBC("commands.reload")); - return; - - } - if(args[0].equalsIgnoreCase("list")) { - if(!sender.hasPermission("ajqueue.list")) { - sender.sendMessage(msgs.getBC("noperm")); - return; - } - int total = 0; - for(QueueServer server : Manager.getInstance().getServers()) { - - Component msg = msgs.getComponent("list.format", - "SERVER:"+server.getName() - ); - Component playerList = Component.empty(); - List players = server.getQueue(); - boolean none = true; - for(ProxiedPlayer p : players) { - playerList = playerList.append(msgs.getComponent("list.playerlist", - "NAME:" + p.getDisplayName() - )); - none = false; - } - if(none) { - playerList = playerList.append(msgs.getComponent("list.none")); - playerList = playerList.append(Component.text(", ")); - } - Component finalPlayerList = playerList; - msg = msg.replaceText(b -> b.match(Pattern.compile("\\{LIST}")).replacement(finalPlayerList)); - char[] commaCountString = PlainTextComponentSerializer.plainText().serialize(msg).toCharArray(); - int commas = 0; - for(Character fChar : commaCountString) { - if(fChar == ',') commas++; - } - - int finalCommas = commas; - msg = msg.replaceText(b -> b.match(",(?!.*,)").replacement("").condition((r, c, re) -> { - if(c == finalCommas) { - return PatternReplacementResult.REPLACE; - } - return PatternReplacementResult.CONTINUE; - })); - total += players.size(); - msg = msg.replaceText(b -> b.match(Pattern.compile("\\{COUNT}")).replacement(players.size()+"")); - sender.sendMessage(msgs.getBC(msg)); - } - sender.sendMessage(msgs.getBC("list.total", "TOTAL:"+total)); - return; - } - if(args[0].equalsIgnoreCase("p")) { - sender.sendMessage(Main.formatMessage(pl.isp()+"")); - return; - } - if(args[0].equalsIgnoreCase("statusdebug")) { - QueueServer s = Manager.getInstance().getSingleServer((ProxiedPlayer) sender); - if(s == null) return; - sender.sendMessage(Main.formatMessage(s.getJoinableDebug((ProxiedPlayer) sender))); - } - if(args[0].equalsIgnoreCase("send")) { - if(!sender.hasPermission("ajqueue.send")) { - sender.sendMessage(msgs.getBC("noperm")); - return; - } - sender.sendMessage(Main.formatMessage("/ajQueue send ")); - return; - } - if(args[0].equalsIgnoreCase("version")) { - sender.sendMessage(Main.formatMessage(pl.getDescription().getVersion())); - return; - } - if(args[0].equalsIgnoreCase("pause")) { - if(!sender.hasPermission("ajqueue.pause")) { - sender.sendMessage(msgs.getBC("noperm")); - return; - } - sender.sendMessage(msgs.getBC("commands.pause.more-args")); - return; - } - } - if(args.length == 2) { - if(args[0].equalsIgnoreCase("pause")) { - if(!sender.hasPermission("ajqueue.pause")) { - sender.sendMessage(msgs.getBC("noperm")); - return; - } - if(!Manager.getInstance().getServerNames().contains(args[1])) { - sender.sendMessage(msgs.getBC("errors.server-not-exist", "SERVER:"+args[1])); - return; - } - QueueServer srv = Manager.getInstance().findServer(args[1]); - if(srv == null) { - sender.sendMessage(msgs.getBC("commands.pause.no-server", "SERVER:"+args[1])); - return; - } - srv.setPaused(!srv.isPaused()); - sender.sendMessage(msgs.getBC("commands.pause.success", - "SERVER:"+srv.getName(), - "PAUSED:"+msgs.getString("commands.pause.paused."+srv.isPaused()) - )); - return; - } - if(args[0].equalsIgnoreCase("send")) { - if(!sender.hasPermission("ajqueue.send")) { - sender.sendMessage(msgs.getBC("noperm")); - return; - } - sender.sendMessage(Main.formatMessage("/ajQueue send ")); - return; - } - } - if(args.length == 3) { - if(args[0].equalsIgnoreCase("pause")) { - if(!sender.hasPermission("ajqueue.pause")) { - sender.sendMessage(msgs.getBC("noperm")); - return; - } - if(!Manager.getInstance().getServerNames().contains(args[1])) { - sender.sendMessage(msgs.getBC("commands.pause.no-server", "SERVER:"+args[1])); - return; - } - QueueServer srv = Manager.getInstance().findServer(args[1]); - if(srv == null) { - sender.sendMessage(msgs.getBC("commands.pause.no-server", "SERVER:"+args[1])); - return; - } - srv.setPaused(args[2].equalsIgnoreCase("on") || args[2].equalsIgnoreCase("true")); - sender.sendMessage(msgs.getBC("commands.pause.success", - "SERVER:"+srv.getName(), - "PAUSED:"+msgs.getString("commands.pause.paused."+srv.isPaused()) - )); - return; - } - if(args[0].equalsIgnoreCase("send")) { - if(!sender.hasPermission("ajqueue.send")) { - sender.sendMessage(msgs.getBC("noperm")); - return; - } - - if(Manager.getInstance().getServer(args[2]) == null) { - sender.sendMessage(msgs.getBC("errors.server-not-exist", "SERVER:"+args[2])); - return; - } - - List playerNames = getNameList(true); - if(playerNames.contains(args[1].toLowerCase())) { - - ProxiedPlayer ply = pl.getProxy().getPlayer(args[1]); - Manager.getInstance().addToQueue(ply, args[2]); - sender.sendMessage(msgs.getBC("send", - "PLAYER:"+ply.getDisplayName(), - "SERVER:"+args[2]) - ); - return; - } else if(pl.getProxy().getServers().containsKey(args[1])) { - - ServerInfo from = pl.getProxy().getServerInfo(args[1]); - if(from == null) { - sender.sendMessage(msgs.getBC("errors.server-not-exist", "SERVER:"+args[1])); - return; - } - List players = new ArrayList<>(from.getPlayers()); - for(ProxiedPlayer ply : players) { - Manager.getInstance().addToQueue(ply, args[2]); - } - - sender.sendMessage(msgs.getBC("send", "PLAYER:"+args[1], "SERVER:"+args[2])); - return; - - } else { - sender.sendMessage(msgs.getBC("commands.send.player-not-found")); - return; - } - } - } - - sender.sendMessage(Main.formatMessage("/ajqueue ")); - } - - private List getNameList(boolean lowercase) { - List playerNames = new ArrayList<>(); - for(ProxiedPlayer ply : pl.getProxy().getPlayers()) { - if(ply == null || !ply.isConnected()) continue; - if(lowercase) { - playerNames.add(ply.getName().toLowerCase()); - } else { - playerNames.add(ply.getName()); - } - } - return playerNames; - } - - @Override - public Iterable onTabComplete(CommandSender sender, String[] args) { - if(args.length == 1) { - return Arrays.asList("reload", "list", "send", "pause"); - } - if(args.length == 2) { - if(args[0].equalsIgnoreCase("send")) { - List options = new ArrayList<>(pl.getProxy().getServers().keySet()); - options.addAll(getNameList(false)); - return options; - } - if(args[0].equalsIgnoreCase("pause")) { - return Manager.getInstance().getServerNames(); - } - } - if(args.length == 3) { - if(args[0].equalsIgnoreCase("send")) { - return Manager.getInstance().getServerNames(); - } - if(args[0].equalsIgnoreCase("pause")) { - return Arrays.asList("on", "off", "true", "false"); - } - } - return new ArrayList<>(); - } -} diff --git a/src/main/java/us/ajg0702/queue/commands/MoveCommand.java b/src/main/java/us/ajg0702/queue/commands/MoveCommand.java deleted file mode 100644 index c8a3873..0000000 --- a/src/main/java/us/ajg0702/queue/commands/MoveCommand.java +++ /dev/null @@ -1,51 +0,0 @@ -package us.ajg0702.queue.commands; - -import java.util.ArrayList; - -import net.md_5.bungee.api.CommandSender; -import net.md_5.bungee.api.connection.ProxiedPlayer; -import net.md_5.bungee.api.plugin.Command; -import net.md_5.bungee.api.plugin.TabExecutor; -import us.ajg0702.queue.Main; -import us.ajg0702.queue.Manager; -import us.ajg0702.utils.bungee.BungeeMessages; - -public class MoveCommand extends Command implements TabExecutor { - Main plugin; - BungeeMessages msgs; - public MoveCommand(Main pl) { - super("move", null, "queue", "server", "joinqueue", "joinq"); - this.plugin = pl; - msgs = BungeeMessages.getInstance(); - } - - @Override - public void execute(CommandSender sender, String[] args) { - if(!(sender instanceof ProxiedPlayer)) { - sender.sendMessage(msgs.getBC("errors.player-only")); - return; - } - ProxiedPlayer p = (ProxiedPlayer) sender; - - if(args.length > 0) { - if(plugin.getConfig().getBoolean("require-permission") && !p.hasPermission("ajqueue.queue."+args[0])) { - sender.sendMessage(msgs.getBC("noperm")); - return; - } - Manager.getInstance().addToQueue(p, args[0]); - } else { - sender.sendMessage(msgs.getBC("commands.joinqueue.usage")); - } - } - - @Override - public Iterable onTabComplete(CommandSender sender, String[] args) { - if(!plugin.getConfig().getBoolean("tab-complete-queues")) { - return new ArrayList<>(); - } - if(args.length == 1) { - return Manager.getInstance().getServerNames(); - } - return new ArrayList<>(); - } -} diff --git a/src/main/resources/bungee.yml b/src/main/resources/bungee.yml deleted file mode 100644 index 0c8d560..0000000 --- a/src/main/resources/bungee.yml +++ /dev/null @@ -1,4 +0,0 @@ -name: ajQueue -version: "@VERSION@" -main: us.ajg0702.queue.Main -author: ajgeiss0702 \ No newline at end of file diff --git a/src/test/java/RegexTest.java b/src/test/java/RegexTest.java deleted file mode 100644 index 674bccf..0000000 --- a/src/test/java/RegexTest.java +++ /dev/null @@ -1,49 +0,0 @@ -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.PatternReplacementResult; -import net.kyori.adventure.text.TextReplacementConfig; -import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer; -import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; -import org.junit.Test; - -import java.util.Arrays; -import java.util.List; -import java.util.regex.Pattern; - -public class RegexTest { - @Test - public void regex() throws Exception { - Component msg = Component.text("&b{SERVER} &7({COUNT}): {LIST}"); - Component playerList = Component.empty(); - List players = Arrays.asList("bot01", "bot02", "bot03", "bot04", "bot05", "bot06"); - for(String p : players) { - playerList = playerList.append(Component.text("&9"+p+"&7, ")); - } - Component finalPlayerList = playerList; - msg = msg.replaceText(b -> b.match(Pattern.compile("\\{LIST}")).replacement(finalPlayerList)); - char[] commaCountString = PlainTextComponentSerializer.plainText().serialize(msg).toCharArray(); - int commas = 0; - for(Character fChar : commaCountString) { - if(fChar == ',') commas++; - } - - int finalCommas = commas; - msg = msg.replaceText(b -> b.match(",(?!.*,)").replacement("").condition((r, c, re) -> { - if(c == finalCommas) { - return PatternReplacementResult.REPLACE; - } - return PatternReplacementResult.CONTINUE; - })); - msg = msg.replaceText(b -> b.match(Pattern.compile("\\{COUNT}")).replacement(players.size()+"")); - - - String f = PlainTextComponentSerializer.plainText().serialize(msg); - System.out.println(f); - int c = 0; - for(Character fChar : f.toCharArray()) { - if(fChar == ',') c++; - } - if(c != 5) { - throw new Exception("Wrong comma count! Had "+c+" when expected 5"); - } - } -}