From 91f25612a724c0fc7bf9f6f36f537a3c0c451331 Mon Sep 17 00:00:00 2001 From: disclearing Date: Mon, 21 Jan 2019 21:56:47 +0000 Subject: [PATCH] dd dd --- .gitignore | 66 ++++++ .../me/joeleoli/portal/bukkit/Portal.java | 93 +++++++++ .../portal/bukkit/command/BaseCommand.java | 24 +++ .../command/commands/DataDumpCommand.java | 71 +++++++ .../command/commands/ForceSendCommand.java | 41 ++++ .../command/commands/JoinQueueCommand.java | 85 ++++++++ .../command/commands/LeaveQueueCommand.java | 44 ++++ .../command/commands/QueueClearCommand.java | 50 +++++ .../command/commands/QueueToggleCommand.java | 50 +++++ .../portal/bukkit/config/FileConfig.java | 47 +++++ .../portal/bukkit/config/Language.java | 82 ++++++++ .../jedis/PortalSubscriptionHandler.java | 177 ++++++++++++++++ .../bukkit/listener/PlayerListener.java | 21 ++ .../bukkit/priority/PriorityProvider.java | 10 + .../impl/DefaultPriorityProvider.java | 59 ++++++ .../joeleoli/portal/bukkit/server/Server.java | 24 +++ .../portal/bukkit/thread/ReminderThread.java | 31 +++ .../portal/bukkit/thread/UpdateThread.java | 23 +++ .../portal/bukkit/util/BungeeUtil.java | 29 +++ .../joeleoli/portal/bukkit/util/MapUtil.java | 23 +++ Bukkit/src/main/resources/config.yml | 27 +++ Bukkit/src/main/resources/plugin.yml | 20 ++ Independent/config.properties | 5 + .../joeleoli/portal/independent/Portal.java | 65 ++++++ .../portal/independent/file/Config.java | 66 ++++++ .../jedis/PortalSubscriptionHandler.java | 189 ++++++++++++++++++ .../portal/independent/log/Logger.java | 15 ++ .../independent/thread/BroadcastThread.java | 60 ++++++ .../independent/thread/QueueThread.java | 60 ++++++ README.md | 26 ++- .../portal/shared/jedis/JedisAction.java | 17 ++ .../portal/shared/jedis/JedisChannel.java | 8 + .../portal/shared/jedis/JedisPublisher.java | 60 ++++++ .../portal/shared/jedis/JedisQueue.java | 16 ++ .../portal/shared/jedis/JedisSettings.java | 27 +++ .../portal/shared/jedis/JedisSubscriber.java | 58 ++++++ .../jedis/JedisSubscriptionHandler.java | 9 + .../joeleoli/portal/shared/queue/Queue.java | 88 ++++++++ .../portal/shared/queue/QueuePlayer.java | 40 ++++ .../shared/queue/QueuePlayerComparator.java | 12 ++ .../portal/shared/queue/QueueRank.java | 28 +++ .../portal/shared/server/ServerData.java | 46 +++++ 42 files changed, 1991 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 Bukkit/src/main/java/me/joeleoli/portal/bukkit/Portal.java create mode 100644 Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/BaseCommand.java create mode 100644 Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/commands/DataDumpCommand.java create mode 100644 Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/commands/ForceSendCommand.java create mode 100644 Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/commands/JoinQueueCommand.java create mode 100644 Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/commands/LeaveQueueCommand.java create mode 100644 Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/commands/QueueClearCommand.java create mode 100644 Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/commands/QueueToggleCommand.java create mode 100644 Bukkit/src/main/java/me/joeleoli/portal/bukkit/config/FileConfig.java create mode 100644 Bukkit/src/main/java/me/joeleoli/portal/bukkit/config/Language.java create mode 100644 Bukkit/src/main/java/me/joeleoli/portal/bukkit/jedis/PortalSubscriptionHandler.java create mode 100644 Bukkit/src/main/java/me/joeleoli/portal/bukkit/listener/PlayerListener.java create mode 100644 Bukkit/src/main/java/me/joeleoli/portal/bukkit/priority/PriorityProvider.java create mode 100644 Bukkit/src/main/java/me/joeleoli/portal/bukkit/priority/impl/DefaultPriorityProvider.java create mode 100644 Bukkit/src/main/java/me/joeleoli/portal/bukkit/server/Server.java create mode 100644 Bukkit/src/main/java/me/joeleoli/portal/bukkit/thread/ReminderThread.java create mode 100644 Bukkit/src/main/java/me/joeleoli/portal/bukkit/thread/UpdateThread.java create mode 100644 Bukkit/src/main/java/me/joeleoli/portal/bukkit/util/BungeeUtil.java create mode 100644 Bukkit/src/main/java/me/joeleoli/portal/bukkit/util/MapUtil.java create mode 100644 Bukkit/src/main/resources/config.yml create mode 100644 Bukkit/src/main/resources/plugin.yml create mode 100644 Independent/config.properties create mode 100644 Independent/src/main/java/me/joeleoli/portal/independent/Portal.java create mode 100644 Independent/src/main/java/me/joeleoli/portal/independent/file/Config.java create mode 100644 Independent/src/main/java/me/joeleoli/portal/independent/jedis/PortalSubscriptionHandler.java create mode 100644 Independent/src/main/java/me/joeleoli/portal/independent/log/Logger.java create mode 100644 Independent/src/main/java/me/joeleoli/portal/independent/thread/BroadcastThread.java create mode 100644 Independent/src/main/java/me/joeleoli/portal/independent/thread/QueueThread.java create mode 100644 Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisAction.java create mode 100644 Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisChannel.java create mode 100644 Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisPublisher.java create mode 100644 Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisQueue.java create mode 100644 Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisSettings.java create mode 100644 Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisSubscriber.java create mode 100644 Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisSubscriptionHandler.java create mode 100644 Shared/src/main/java/me/joeleoli/portal/shared/queue/Queue.java create mode 100644 Shared/src/main/java/me/joeleoli/portal/shared/queue/QueuePlayer.java create mode 100644 Shared/src/main/java/me/joeleoli/portal/shared/queue/QueuePlayerComparator.java create mode 100644 Shared/src/main/java/me/joeleoli/portal/shared/queue/QueueRank.java create mode 100644 Shared/src/main/java/me/joeleoli/portal/shared/server/ServerData.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a0c1630 --- /dev/null +++ b/.gitignore @@ -0,0 +1,66 @@ +<<<<<<< HEAD +# Eclipse stuff +.classpath +.project +.settings/ + +# netbeans +nbproject/ +nbactions.xml + +# we use maven! +build.xml + +# maven +target/ +dependency-reduced-pom.xml + +# vim +.*.sw[a-p] + +# various other potential build files +build/ +bin/ +dist/ +manifest.mf + +# Mac filesystem dust +.DS_Store/ +.DS_Store + +# intellij +*.iml +*.ipr +*.iws +.idea/ +.idea +.idea\ + +working-dir/ +*.xml +.idea/workspace.xml +======= +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +>>>>>>> 6e4ff37e03486bd27d4884d80f78a2263cdf60ea diff --git a/Bukkit/src/main/java/me/joeleoli/portal/bukkit/Portal.java b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/Portal.java new file mode 100644 index 0000000..d17e3a7 --- /dev/null +++ b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/Portal.java @@ -0,0 +1,93 @@ +package me.joeleoli.portal.bukkit; + +import me.joeleoli.portal.bukkit.command.commands.*; +import me.joeleoli.portal.bukkit.config.FileConfig; +import me.joeleoli.portal.bukkit.config.Language; +import me.joeleoli.portal.bukkit.jedis.PortalSubscriptionHandler; +import me.joeleoli.portal.bukkit.listener.PlayerListener; +import me.joeleoli.portal.bukkit.priority.PriorityProvider; +import me.joeleoli.portal.bukkit.priority.impl.DefaultPriorityProvider; +import me.joeleoli.portal.bukkit.server.Server; +import me.joeleoli.portal.bukkit.thread.ReminderThread; +import me.joeleoli.portal.bukkit.thread.UpdateThread; +import me.joeleoli.portal.shared.jedis.JedisChannel; +import me.joeleoli.portal.shared.jedis.JedisPublisher; +import me.joeleoli.portal.shared.jedis.JedisSettings; +import me.joeleoli.portal.shared.jedis.JedisSubscriber; + +import lombok.Getter; +import lombok.Setter; + +import org.bukkit.plugin.java.JavaPlugin; + +@Getter +public class Portal extends JavaPlugin { + + @Getter + private static Portal instance; + + private FileConfig mainConfig; + private Language language; + + private JedisSettings settings; + private JedisPublisher publisher; + private JedisSubscriber subscriber; + + private Server portalServer; + + @Setter + private PriorityProvider priorityProvider; + + @Override + public void onEnable() { + instance = this; + + this.mainConfig = new FileConfig(this, "config.yml"); + + this.language = new Language(); + this.language.load(); + + this.portalServer = new Server( + this.mainConfig.getConfig().getString("server.id"), + this.mainConfig.getConfig().getBoolean("server.hub") + ); + + this.settings = new JedisSettings( + this.mainConfig.getConfig().getString("redis.host"), + this.mainConfig.getConfig().getInt("redis.port"), + !this.mainConfig.getConfig().contains("redis.password") ? null : this.mainConfig.getConfig().getString("redis.password") + ); + + this.subscriber = new JedisSubscriber(JedisChannel.BUKKIT, this.settings, new PortalSubscriptionHandler()); + this.publisher = new JedisPublisher(this.settings); + this.publisher.start(); + + this.priorityProvider = new DefaultPriorityProvider(); + + // Start threads + new UpdateThread().start(); + new ReminderThread().start(); + + // Register commands + new JoinQueueCommand(); + new LeaveQueueCommand(); + new ForceSendCommand(); + new DataDumpCommand(); + new QueueToggleCommand(); + new QueueClearCommand(); + + // Register listeners + this.getServer().getPluginManager().registerEvents(new PlayerListener(), this); + + // Register plugin message channels + this.getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord"); + } + + @Override + public void onDisable() { + if (this.settings.getJedisPool() != null && !this.settings.getJedisPool().isClosed()) { + this.settings.getJedisPool().close(); + } + } + +} diff --git a/Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/BaseCommand.java b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/BaseCommand.java new file mode 100644 index 0000000..a6232da --- /dev/null +++ b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/BaseCommand.java @@ -0,0 +1,24 @@ +package me.joeleoli.portal.bukkit.command; + +import me.joeleoli.portal.bukkit.Portal; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; + +public abstract class BaseCommand implements CommandExecutor { + + protected static final String NO_PERMISSION = ChatColor.RED + "No permission."; + protected static final String CONSOLE_SENDER = ChatColor.RED + "This command can only be peformed in-game."; + + public BaseCommand(String name) { + Portal.getInstance().getCommand(name).setExecutor(this); + } + + @Override + public boolean onCommand(CommandSender commandSender, Command command, String s, String[] strings) { + commandSender.sendMessage("Command not handled"); + return true; + } + +} \ No newline at end of file diff --git a/Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/commands/DataDumpCommand.java b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/commands/DataDumpCommand.java new file mode 100644 index 0000000..221f9b8 --- /dev/null +++ b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/commands/DataDumpCommand.java @@ -0,0 +1,71 @@ +package me.joeleoli.portal.bukkit.command.commands; + +import me.joeleoli.portal.bukkit.command.BaseCommand; +import me.joeleoli.portal.shared.queue.Queue; +import me.joeleoli.portal.shared.server.ServerData; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; + +public class DataDumpCommand extends BaseCommand { + + public DataDumpCommand() { + super("datadump"); + } + + @Override + public boolean onCommand(CommandSender commandSender, Command command, String s, String[] args) { + if (!commandSender.hasPermission("portal.datadump") && !commandSender.isOp()) { + commandSender.sendMessage(NO_PERMISSION); + return true; + } + + commandSender.sendMessage("Servers:"); + + for (ServerData serverData : ServerData.getServers()) { + StringBuilder builder = new StringBuilder("- ") + .append(serverData.getName()) + .append(" (") + .append(serverData.isOnline()) + .append(") (") + .append(serverData.getOnlinePlayers()) + .append("/") + .append(serverData.getMaximumPlayers()) + .append(")"); + + commandSender.sendMessage(builder.toString()); + } + + commandSender.sendMessage("Queues:"); + + for (Queue queue : Queue.getQueues()) { + StringBuilder builder = new StringBuilder("- ") + .append(queue.getName()) + .append(" (") + .append(queue.getPlayers().size()) + .append(" in queue)"); + + ServerData serverData = queue.getServerData(); + + if (serverData == null) { + builder + .append(" (offline)"); + } else { + builder + .append(" (") + .append(serverData.isOnline()) + .append(") (") + .append(serverData.isWhitelisted()) + .append(") (") + .append(serverData.getOnlinePlayers()) + .append("/") + .append(serverData.getMaximumPlayers()) + .append(")"); + } + + commandSender.sendMessage(builder.toString()); + } + + return true; + } + +} diff --git a/Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/commands/ForceSendCommand.java b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/commands/ForceSendCommand.java new file mode 100644 index 0000000..24c69e9 --- /dev/null +++ b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/commands/ForceSendCommand.java @@ -0,0 +1,41 @@ +package me.joeleoli.portal.bukkit.command.commands; + +import com.google.gson.JsonObject; +import me.joeleoli.portal.bukkit.Portal; +import me.joeleoli.portal.bukkit.command.BaseCommand; +import me.joeleoli.portal.shared.jedis.JedisAction; +import me.joeleoli.portal.shared.jedis.JedisChannel; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; + +public class ForceSendCommand extends BaseCommand { + + public ForceSendCommand() { + super("forcesend"); + } + + @Override + public boolean onCommand(CommandSender commandSender, Command command, String s, String[] args) { + if (!commandSender.hasPermission("portal.forcesend") && !commandSender.isOp()) { + commandSender.sendMessage(NO_PERMISSION); + return true; + } + + if (args.length < 2) { + commandSender.sendMessage(ChatColor.RED + "Usage: /forcesend "); + return true; + } + + JsonObject json = new JsonObject(); + json.addProperty("username", args[0]); + json.addProperty("server", args[1]); + + Portal.getInstance().getPublisher().write(JedisChannel.BUKKIT, JedisAction.SEND_PLAYER_SERVER, json); + + commandSender.sendMessage(ChatColor.GREEN + "If a player with that username is online, they will be sent to `" + args[1] + "`."); + + return true; + } + +} diff --git a/Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/commands/JoinQueueCommand.java b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/commands/JoinQueueCommand.java new file mode 100644 index 0000000..e14968e --- /dev/null +++ b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/commands/JoinQueueCommand.java @@ -0,0 +1,85 @@ +package me.joeleoli.portal.bukkit.command.commands; + +import com.google.gson.JsonObject; + +import me.joeleoli.portal.bukkit.Portal; +import me.joeleoli.portal.bukkit.command.BaseCommand; +import me.joeleoli.portal.shared.jedis.JedisAction; +import me.joeleoli.portal.shared.jedis.JedisChannel; +import me.joeleoli.portal.shared.queue.Queue; +import me.joeleoli.portal.shared.queue.QueueRank; + +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class JoinQueueCommand extends BaseCommand { + + public JoinQueueCommand() { + super("joinqueue"); + } + + @Override + public boolean onCommand(CommandSender commandSender, Command command, String s, String[] args) { + if (!(commandSender instanceof Player)) { + commandSender.sendMessage(CONSOLE_SENDER); + return true; + } + + if (args.length == 0) { + commandSender.sendMessage(ChatColor.RED + "Usage: /joinqueue "); + return true; + } + + Player bukkitPlayer = (Player) commandSender; + + Queue queue = Queue.getByPlayer(bukkitPlayer.getUniqueId()); + + if (queue != null) { + bukkitPlayer.sendMessage(ChatColor.RED + "You are already in a queue."); + return true; + } + + queue = Queue.getByName(args[0]); + + if (queue == null) { + bukkitPlayer.sendMessage(ChatColor.RED + "That queue does not exist or is offline."); + return true; + } + + if (queue.getServerData() == null || !queue.getServerData().isOnline()) { + bukkitPlayer.sendMessage(ChatColor.RED + "That queue is offline."); + return true; + } + + if (bukkitPlayer.hasPermission("portal.bypass")) { + JsonObject data = new JsonObject(); + data.addProperty("uuid", bukkitPlayer.getUniqueId().toString()); + data.addProperty("server", queue.getName()); + + Portal.getInstance().getPublisher().write(JedisChannel.BUKKIT, JedisAction.SEND_PLAYER_SERVER, data); + + return true; + } + + QueueRank queueRank = Portal.getInstance().getPriorityProvider().getPriority(bukkitPlayer); + + JsonObject rank = new JsonObject(); + rank.addProperty("name", queueRank.getName()); + rank.addProperty("priority", queueRank.getPriority()); + + JsonObject player = new JsonObject(); + player.addProperty("uuid", bukkitPlayer.getUniqueId().toString()); + player.add("rank", rank); + + JsonObject data = new JsonObject(); + data.addProperty("queue", queue.getName()); + data.add("player", player); + + Portal.getInstance().getPublisher().write(JedisChannel.INDEPENDENT, JedisAction.ADD_PLAYER, data); + + return true; + } + +} diff --git a/Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/commands/LeaveQueueCommand.java b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/commands/LeaveQueueCommand.java new file mode 100644 index 0000000..d0fd400 --- /dev/null +++ b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/commands/LeaveQueueCommand.java @@ -0,0 +1,44 @@ +package me.joeleoli.portal.bukkit.command.commands; + +import com.google.gson.JsonObject; +import me.joeleoli.portal.bukkit.Portal; +import me.joeleoli.portal.bukkit.command.BaseCommand; +import me.joeleoli.portal.shared.jedis.JedisAction; +import me.joeleoli.portal.shared.jedis.JedisChannel; +import me.joeleoli.portal.shared.queue.Queue; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class LeaveQueueCommand extends BaseCommand { + + public LeaveQueueCommand() { + super("leavequeue"); + } + + @Override + public boolean onCommand(CommandSender commandSender, Command command, String s, String[] strings) { + if (!(commandSender instanceof Player)) { + commandSender.sendMessage(CONSOLE_SENDER); + return true; + } + + Player player = (Player) commandSender; + + Queue queue = Queue.getByPlayer(player.getUniqueId()); + + if (queue == null) { + player.sendMessage(ChatColor.RED + "You are not in a queue."); + return true; + } + + JsonObject data = new JsonObject(); + data.addProperty("uuid", player.getUniqueId().toString()); + + Portal.getInstance().getPublisher().write(JedisChannel.INDEPENDENT, JedisAction.REMOVE_PLAYER, data); + + return true; + } + +} diff --git a/Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/commands/QueueClearCommand.java b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/commands/QueueClearCommand.java new file mode 100644 index 0000000..526eefa --- /dev/null +++ b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/commands/QueueClearCommand.java @@ -0,0 +1,50 @@ +package me.joeleoli.portal.bukkit.command.commands; + +import com.google.gson.JsonObject; +import me.joeleoli.portal.bukkit.Portal; +import me.joeleoli.portal.bukkit.command.BaseCommand; +import me.joeleoli.portal.shared.jedis.JedisAction; +import me.joeleoli.portal.shared.jedis.JedisChannel; +import me.joeleoli.portal.shared.queue.Queue; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; + +public class QueueClearCommand extends BaseCommand { + + public QueueClearCommand() { + super("queueclear"); + } + + @Override + public boolean onCommand(CommandSender commandSender, Command command, String s, String[] args) { + if (!commandSender.hasPermission("portal.clear") && !commandSender.isOp()) { + commandSender.sendMessage(NO_PERMISSION); + return true; + } + + if (args.length == 0) { + commandSender.sendMessage(ChatColor.RED + "Usage: /queueclear "); + return true; + } + + Queue queue = Queue.getByName(args[0]); + + if (queue == null) { + commandSender.sendMessage(ChatColor.RED + "That queue does not exist."); + return true; + } + + queue.getPlayers().clear(); + + JsonObject json = new JsonObject(); + json.addProperty("queue", queue.getName()); + + Portal.getInstance().getPublisher().write(JedisChannel.INDEPENDENT, JedisAction.CLEAR_PLAYERS, json); + + commandSender.sendMessage(ChatColor.GREEN + "Cleared list of " + queue.getName()); + + return true; + } + +} diff --git a/Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/commands/QueueToggleCommand.java b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/commands/QueueToggleCommand.java new file mode 100644 index 0000000..6beff09 --- /dev/null +++ b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/command/commands/QueueToggleCommand.java @@ -0,0 +1,50 @@ +package me.joeleoli.portal.bukkit.command.commands; + +import com.google.gson.JsonObject; +import me.joeleoli.portal.bukkit.Portal; +import me.joeleoli.portal.bukkit.command.BaseCommand; +import me.joeleoli.portal.shared.jedis.JedisAction; +import me.joeleoli.portal.shared.jedis.JedisChannel; +import me.joeleoli.portal.shared.queue.Queue; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; + +public class QueueToggleCommand extends BaseCommand { + + public QueueToggleCommand() { + super("queuetoggle"); + } + + @Override + public boolean onCommand(CommandSender commandSender, Command command, String s, String[] args) { + if (!commandSender.hasPermission("portal.toggle") && !commandSender.isOp()) { + commandSender.sendMessage(NO_PERMISSION); + return true; + } + + if (args.length == 0) { + commandSender.sendMessage(ChatColor.RED + "Usage: /queuetoggle "); + return true; + } + + Queue queue = Queue.getByName(args[0]); + + if (queue == null) { + commandSender.sendMessage(ChatColor.RED + "That queue does not exist."); + return true; + } + + queue.setEnabled(!queue.isEnabled()); + + JsonObject json = new JsonObject(); + json.addProperty("queue", queue.getName()); + + Portal.getInstance().getPublisher().write(JedisChannel.INDEPENDENT, JedisAction.TOGGLE, json); + + commandSender.sendMessage(ChatColor.GREEN + "Changed status of `" + queue.getName() + "` to " + queue.isEnabled()); + + return true; + } + +} diff --git a/Bukkit/src/main/java/me/joeleoli/portal/bukkit/config/FileConfig.java b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/config/FileConfig.java new file mode 100644 index 0000000..250a953 --- /dev/null +++ b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/config/FileConfig.java @@ -0,0 +1,47 @@ +package me.joeleoli.portal.bukkit.config; + +import lombok.Getter; +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.File; +import java.io.IOException; + +@Getter +public class FileConfig { + + private File file; + private FileConfiguration config; + + public FileConfig(JavaPlugin plugin, String fileName) { + this.file = new File(plugin.getDataFolder(), fileName); + + if (!this.file.exists()) { + this.file.getParentFile().mkdirs(); + + if (plugin.getResource(fileName) == null) { + try { + this.file.createNewFile(); + } catch (IOException e) { + plugin.getLogger().severe("Failed to create new file " + fileName); + } + } else { + plugin.saveResource(fileName, false); + } + } + + this.config = YamlConfiguration.loadConfiguration(this.file); + } + + public void save() { + try { + this.config.save(this.file); + } catch (IOException e) { + Bukkit.getLogger().severe("Could not save config file " + this.file.toString()); + e.printStackTrace(); + } + } + +} \ No newline at end of file diff --git a/Bukkit/src/main/java/me/joeleoli/portal/bukkit/config/Language.java b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/config/Language.java new file mode 100644 index 0000000..e3debac --- /dev/null +++ b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/config/Language.java @@ -0,0 +1,82 @@ +package me.joeleoli.portal.bukkit.config; + +import me.joeleoli.portal.bukkit.Portal; +import me.joeleoli.portal.shared.queue.Queue; +import org.bukkit.ChatColor; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class Language { + + private List reminder = Arrays.asList( + "&eYou are position &d#{position} &eof &d{total} &ein the &a{queue} &equeue.", + "&7Purchase a rank at www.server.net to get a higher queue priority." + ); + private List added = Arrays.asList( + "&aYou have joined the {queue} queue." + ); + private List removed = Arrays.asList( + "&cYou have been removed from the {queue} queue." + ); + + public void load() { + FileConfiguration config = Portal.getInstance().getMainConfig().getConfig(); + + if (config.contains("language.reminder")) { + this.reminder = config.getStringList("language.reminder"); + } + + if (config.contains("language.added")) { + this.added = config.getStringList("language.added"); + } + + if (config.contains("language.removed")) { + this.removed = config.getStringList("language.removed"); + } + } + + public List getReminder(Player player, Queue queue) { + List translated = new ArrayList<>(); + + for (String line : this.reminder) { + translated.add(ChatColor.translateAlternateColorCodes('&', line + .replace("{position}", queue.getPosition(player.getUniqueId()) + "") + .replace("{total}", queue.getPlayers().size() + "") + .replace("{queue}", queue.getName())) + ); + } + + return translated; + } + + public List getAdded(Player player, Queue queue) { + List translated = new ArrayList<>(); + + for (String line : this.added) { + translated.add(ChatColor.translateAlternateColorCodes('&', line + .replace("{position}", queue.getPosition(player.getUniqueId()) + "") + .replace("{total}", queue.getPlayers().size() + "") + .replace("{queue}", queue.getName())) + ); + } + + return translated; + } + + public List getRemoved(Queue queue) { + List translated = new ArrayList<>(); + + for (String line : this.removed) { + translated.add(ChatColor.translateAlternateColorCodes('&', line + .replace("{queue}", queue.getName())) + ); + } + + return translated; + } + +} diff --git a/Bukkit/src/main/java/me/joeleoli/portal/bukkit/jedis/PortalSubscriptionHandler.java b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/jedis/PortalSubscriptionHandler.java new file mode 100644 index 0000000..e717e2d --- /dev/null +++ b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/jedis/PortalSubscriptionHandler.java @@ -0,0 +1,177 @@ +package me.joeleoli.portal.bukkit.jedis; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import me.joeleoli.portal.bukkit.Portal; +import me.joeleoli.portal.bukkit.util.BungeeUtil; +import me.joeleoli.portal.shared.jedis.JedisSubscriptionHandler; +import me.joeleoli.portal.shared.jedis.JedisAction; +import me.joeleoli.portal.shared.queue.Queue; +import me.joeleoli.portal.shared.queue.QueuePlayer; +import me.joeleoli.portal.shared.queue.QueuePlayerComparator; +import me.joeleoli.portal.shared.queue.QueueRank; +import me.joeleoli.portal.shared.server.ServerData; + +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +import java.util.PriorityQueue; +import java.util.UUID; + +public class PortalSubscriptionHandler implements JedisSubscriptionHandler { + + @Override + public void handleMessage(JsonObject json) { + JedisAction action = JedisAction.valueOf(json.get("action").getAsString()); + JsonObject data = json.get("data").isJsonNull() ? null : json.get("data").getAsJsonObject(); + + if (data == null) { + return; + } + + switch (action) { + case UPDATE: { + final String name = data.get("name").getAsString(); + + if (!Portal.getInstance().getPortalServer().isHub()) { + return; + } + + ServerData serverData = ServerData.getByName(name); + + if (serverData == null) { + serverData = new ServerData(name); + } + + serverData.setOnlinePlayers(data.get("online-players").getAsInt()); + serverData.setMaximumPlayers(data.get("maximum-players").getAsInt()); + serverData.setWhitelisted(data.get("whitelisted").getAsBoolean()); + serverData.setLastUpdate(System.currentTimeMillis()); + } + break; + case LIST: { + if (!Portal.getInstance().getPortalServer().isHub()) { + return; + } + + for (JsonElement e : data.get("queues").getAsJsonArray()) { + final JsonObject queueJson = e.getAsJsonObject(); + final String name = queueJson.get("name").getAsString(); + + Queue queue = Queue.getByName(name); + + if (queue == null) { + queue = new Queue(name); + } + + PriorityQueue players = new PriorityQueue<>(new QueuePlayerComparator()); + + for (JsonElement pe : queueJson.get("players").getAsJsonArray()) { + JsonObject player = pe.getAsJsonObject(); + JsonObject rank = player.get("rank").getAsJsonObject(); + + QueueRank queueRank = new QueueRank(); + + queueRank.setName(rank.get("name").getAsString()); + queueRank.setPriority(rank.get("priority").getAsInt()); + + QueuePlayer queuePlayer = new QueuePlayer(); + + queuePlayer.setUuid(UUID.fromString(player.get("uuid").getAsString())); + queuePlayer.setRank(queueRank); + queuePlayer.setInserted(player.get("inserted").getAsLong()); + + players.add(queuePlayer); + } + + queue.setPlayers(players); + queue.setEnabled(queueJson.get("status").getAsBoolean()); + } + } + break; + case ADDED_PLAYER: { + Queue queue = Queue.getByName(data.get("queue").getAsString()); + + if (queue == null) { + return; + } + + JsonObject player = data.get("player").getAsJsonObject(); + JsonObject rank = player.get("rank").getAsJsonObject(); + + QueueRank queueRank = new QueueRank(); + queueRank.setName(rank.get("name").getAsString()); + queueRank.setPriority(rank.get("priority").getAsInt()); + + QueuePlayer queuePlayer = new QueuePlayer(); + queuePlayer.setUuid(UUID.fromString(player.get("uuid").getAsString())); + queuePlayer.setRank(queueRank); + queuePlayer.setInserted(player.get("inserted").getAsLong()); + + queue.getPlayers().add(queuePlayer); + + Player bukkitPlayer = Portal.getInstance().getServer().getPlayer(queuePlayer.getUuid()); + + if (bukkitPlayer != null) { + for (String message : Portal.getInstance().getLanguage().getAdded(bukkitPlayer, queue)) { + bukkitPlayer.sendMessage(message); + } + } + } + break; + case REMOVED_PLAYER: { + Queue queue = Queue.getByName(data.get("queue").getAsString()); + + if (queue == null) { + return; + } + + UUID uuid = UUID.fromString(data.get("player").getAsJsonObject().get("uuid").getAsString()); + + queue.getPlayers().removeIf(queuePlayer -> queuePlayer.getUuid().equals(uuid)); + + Player bukkitPlayer = Portal.getInstance().getServer().getPlayer(uuid); + + if (bukkitPlayer != null) { + for (String message : Portal.getInstance().getLanguage().getRemoved(queue)) { + bukkitPlayer.sendMessage(message); + } + } + } + break; + case SEND_PLAYER_SERVER: { + String server = data.get("server").getAsString(); + + Player player; + + // Send player by username or uuid + if (data.has("username")) { + player = Portal.getInstance().getServer().getPlayer(data.get("username").getAsString()); + } else { + player = Portal.getInstance().getServer().getPlayer(UUID.fromString(data.get("uuid").getAsString())); + } + + if (player == null) { + return; + } + + player.sendMessage(ChatColor.GREEN + "Sending you to " + server); + + BungeeUtil.sendToServer(player, server); + } + break; + case MESSAGE_PLAYER: { + Player player = Portal.getInstance().getServer().getPlayer(data.get("uuid").getAsString()); + + if (player == null) { + return; + } + + player.sendMessage(ChatColor.translateAlternateColorCodes('&', data.get("message").getAsString())); + } + break; + } + } + +} diff --git a/Bukkit/src/main/java/me/joeleoli/portal/bukkit/listener/PlayerListener.java b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/listener/PlayerListener.java new file mode 100644 index 0000000..1c5fe44 --- /dev/null +++ b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/listener/PlayerListener.java @@ -0,0 +1,21 @@ +package me.joeleoli.portal.bukkit.listener; + +import com.google.gson.JsonObject; +import me.joeleoli.portal.bukkit.Portal; +import me.joeleoli.portal.shared.jedis.JedisAction; +import me.joeleoli.portal.shared.jedis.JedisChannel; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerQuitEvent; + +public class PlayerListener implements Listener { + + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + JsonObject data = new JsonObject(); + data.addProperty("uuid", event.getPlayer().getUniqueId().toString()); + + Portal.getInstance().getPublisher().write(JedisChannel.INDEPENDENT, JedisAction.REMOVE_PLAYER, data); + } + +} diff --git a/Bukkit/src/main/java/me/joeleoli/portal/bukkit/priority/PriorityProvider.java b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/priority/PriorityProvider.java new file mode 100644 index 0000000..7a96e32 --- /dev/null +++ b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/priority/PriorityProvider.java @@ -0,0 +1,10 @@ +package me.joeleoli.portal.bukkit.priority; + +import me.joeleoli.portal.shared.queue.QueueRank; +import org.bukkit.entity.Player; + +public interface PriorityProvider { + + QueueRank getPriority(Player player); + +} diff --git a/Bukkit/src/main/java/me/joeleoli/portal/bukkit/priority/impl/DefaultPriorityProvider.java b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/priority/impl/DefaultPriorityProvider.java new file mode 100644 index 0000000..57c9d2e --- /dev/null +++ b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/priority/impl/DefaultPriorityProvider.java @@ -0,0 +1,59 @@ +package me.joeleoli.portal.bukkit.priority.impl; + +import me.joeleoli.portal.bukkit.Portal; +import me.joeleoli.portal.bukkit.priority.PriorityProvider; +import me.joeleoli.portal.bukkit.util.MapUtil; +import me.joeleoli.portal.shared.queue.QueueRank; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.Player; + +import java.util.HashMap; +import java.util.Map; + +public class DefaultPriorityProvider implements PriorityProvider { + + private static final Portal plugin = Portal.getInstance(); + + private QueueRank defaultPriority; + private Map priorities = new HashMap<>(); + + public DefaultPriorityProvider() { + FileConfiguration config = plugin.getMainConfig().getConfig(); + + try { + this.defaultPriority = new QueueRank("Default", 1); + + if (config.contains("priority.default")) { + this.defaultPriority.setPriority(config.getInt("priority.default")); + } + + if (config.contains("priority.ranks") && config.isConfigurationSection("priority.ranks")) { + for (String rank : config.getConfigurationSection("priority.ranks").getKeys(false)) { + String path = "priority.ranks." + rank; + + if (config.contains(path + ".priority") && config.contains(path + ".permission")) { + this.priorities.put(config.getString(path + ".permission"), new QueueRank(rank, config.getInt + (path + ".priority"))); + } + } + } + + this.priorities = MapUtil.sortByValue(this.priorities); + } catch (Exception e) { + plugin.getLogger().severe("Failed to configure default priority provider."); + e.printStackTrace(); + } + } + + @Override + public QueueRank getPriority(Player player) { + for (Map.Entry entry : this.priorities.entrySet()) { + if (player.hasPermission(entry.getKey())) { + return entry.getValue(); + } + } + + return this.defaultPriority; + } + +} diff --git a/Bukkit/src/main/java/me/joeleoli/portal/bukkit/server/Server.java b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/server/Server.java new file mode 100644 index 0000000..239556b --- /dev/null +++ b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/server/Server.java @@ -0,0 +1,24 @@ +package me.joeleoli.portal.bukkit.server; + +import com.google.gson.JsonObject; +import me.joeleoli.portal.bukkit.Portal; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class Server { + + private String name; + private boolean hub; + + public JsonObject getServerData() { + JsonObject object = new JsonObject(); + object.addProperty("name", this.name); + object.addProperty("online-players", Portal.getInstance().getServer().getOnlinePlayers().size()); + object.addProperty("maximum-players", Portal.getInstance().getServer().getMaxPlayers()); + object.addProperty("whitelisted", Portal.getInstance().getServer().hasWhitelist()); + return object; + } + +} diff --git a/Bukkit/src/main/java/me/joeleoli/portal/bukkit/thread/ReminderThread.java b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/thread/ReminderThread.java new file mode 100644 index 0000000..0aabe64 --- /dev/null +++ b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/thread/ReminderThread.java @@ -0,0 +1,31 @@ +package me.joeleoli.portal.bukkit.thread; + +import me.joeleoli.portal.bukkit.Portal; +import me.joeleoli.portal.shared.queue.Queue; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +public class ReminderThread extends Thread { + + @Override + public void run() { + while (true) { + for (Player player : Portal.getInstance().getServer().getOnlinePlayers()) { + Queue queue = Queue.getByPlayer(player.getUniqueId()); + + if (queue != null) { + for (String message : Portal.getInstance().getLanguage().getReminder(player, queue)) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', message)); + } + } + } + + try { + Thread.sleep(10000L); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + +} diff --git a/Bukkit/src/main/java/me/joeleoli/portal/bukkit/thread/UpdateThread.java b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/thread/UpdateThread.java new file mode 100644 index 0000000..a5eeb33 --- /dev/null +++ b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/thread/UpdateThread.java @@ -0,0 +1,23 @@ +package me.joeleoli.portal.bukkit.thread; + +import me.joeleoli.portal.bukkit.Portal; +import me.joeleoli.portal.shared.jedis.JedisAction; +import me.joeleoli.portal.shared.jedis.JedisChannel; + +public class UpdateThread extends Thread { + + @Override + public void run() { + while (true) { + Portal.getInstance().getPublisher().write(JedisChannel.INDEPENDENT, JedisAction.UPDATE, Portal.getInstance().getPortalServer().getServerData()); + Portal.getInstance().getPublisher().write(JedisChannel.BUKKIT, JedisAction.UPDATE, Portal.getInstance().getPortalServer().getServerData()); + + try { + Thread.sleep(2500L); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + +} diff --git a/Bukkit/src/main/java/me/joeleoli/portal/bukkit/util/BungeeUtil.java b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/util/BungeeUtil.java new file mode 100644 index 0000000..46f53f1 --- /dev/null +++ b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/util/BungeeUtil.java @@ -0,0 +1,29 @@ +package me.joeleoli.portal.bukkit.util; + +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; +import me.joeleoli.portal.bukkit.Portal; +import org.apache.commons.lang3.Validate; +import org.bukkit.entity.Player; + +public final class BungeeUtil { + + private BungeeUtil() { + throw new RuntimeException("Cannot instantiate a utility class."); + } + + public static void sendToServer(Player player, String server) { + Validate.notNull(player, server, "Input values cannot be null!"); + + try { + ByteArrayDataOutput out = ByteStreams.newDataOutput(); + out.writeUTF("Connect"); + out.writeUTF(server); + + player.sendPluginMessage(Portal.getInstance(), "BungeeCord", out.toByteArray()); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/Bukkit/src/main/java/me/joeleoli/portal/bukkit/util/MapUtil.java b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/util/MapUtil.java new file mode 100644 index 0000000..effca7e --- /dev/null +++ b/Bukkit/src/main/java/me/joeleoli/portal/bukkit/util/MapUtil.java @@ -0,0 +1,23 @@ +package me.joeleoli.portal.bukkit.util; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public class MapUtil { + + public static > Map sortByValue(Map map) { + List> list = new ArrayList<>(map.entrySet()); + list.sort(Map.Entry.comparingByValue()); + + Map result = new LinkedHashMap<>(); + + for (Map.Entry entry : list) { + result.put(entry.getKey(), entry.getValue()); + } + + return result; + } + +} \ No newline at end of file diff --git a/Bukkit/src/main/resources/config.yml b/Bukkit/src/main/resources/config.yml new file mode 100644 index 0000000..47de10f --- /dev/null +++ b/Bukkit/src/main/resources/config.yml @@ -0,0 +1,27 @@ +server: + id: hub-01 + hub: false +redis: + host: "127.0.0.1" + port: 6379 + password: "" +priority: + default: 1 + ranks: + Default: + priority: 1 + permission: "ranks.default" + VIP: + priority: 2 + permission: "ranks.vip" + MVP: + priority: 3 + permission: "ranks.mvp" +language: + reminder: + - "&eYou are position &d#{position} &eof &d{total} &ein the &a{queue} &equeue." + - "&7Purchase a rank at www.server.net to get a higher queue priority." + added: + - "&aYou have joined the {queue} queue." + removed: + - "&cYou have been removed from the {queue} queue." \ No newline at end of file diff --git a/Bukkit/src/main/resources/plugin.yml b/Bukkit/src/main/resources/plugin.yml new file mode 100644 index 0000000..d370c48 --- /dev/null +++ b/Bukkit/src/main/resources/plugin.yml @@ -0,0 +1,20 @@ +main: me.joeleoli.portal.bukkit.Portal +name: Portal +version: ${project.version} +author: joeleoli +description: ${project.description} +commands: + joinqueue: + description: Join a queue + leavequeue: + description: Leave a queue + forcesend: + description: Send a player to a server + datadump: + description: Dump data + queuetoggle: + description: Toggle a queue + queueclear: + description: Clear a queue + hub: + description: Get sent to a hub \ No newline at end of file diff --git a/Independent/config.properties b/Independent/config.properties new file mode 100644 index 0000000..c87ad3a --- /dev/null +++ b/Independent/config.properties @@ -0,0 +1,5 @@ +hubs=hub-01,hub-02 +queues=test1,test2,test3 +redis-host=127.0.0.1 +redis-port=6379 +redis-password=dev diff --git a/Independent/src/main/java/me/joeleoli/portal/independent/Portal.java b/Independent/src/main/java/me/joeleoli/portal/independent/Portal.java new file mode 100644 index 0000000..2676fa2 --- /dev/null +++ b/Independent/src/main/java/me/joeleoli/portal/independent/Portal.java @@ -0,0 +1,65 @@ +package me.joeleoli.portal.independent; + +import me.joeleoli.portal.independent.file.Config; +import me.joeleoli.portal.independent.jedis.PortalSubscriptionHandler; +import me.joeleoli.portal.independent.log.Logger; +import me.joeleoli.portal.independent.thread.BroadcastThread; +import me.joeleoli.portal.independent.thread.QueueThread; +import me.joeleoli.portal.shared.jedis.JedisChannel; +import me.joeleoli.portal.shared.jedis.JedisPublisher; +import me.joeleoli.portal.shared.jedis.JedisSettings; +import me.joeleoli.portal.shared.jedis.JedisSubscriber; +import me.joeleoli.portal.shared.queue.Queue; + +import lombok.Getter; + +@Getter +public class Portal { + + @Getter + private static Portal instance; + + private Config config; + + private JedisSubscriber subscriber; + private JedisPublisher publisher; + + private Portal() { + this.config = new Config(); + + for (String name : this.config.getQueues()) { + Queue.getQueues().add(new Queue(name)); + + Logger.print("Loaded queue `" + name + "` from config"); + } + + JedisSettings settings = new JedisSettings( + this.config.getRedisHost(), + this.config.getRedisPort(), + this.config.getRedisPassword().equals("") ? null : this.config.getRedisPassword() + ); + + this.subscriber = new JedisSubscriber(JedisChannel.INDEPENDENT, settings, new PortalSubscriptionHandler()); + this.publisher = new JedisPublisher(settings); + this.publisher.start(); + + new QueueThread().start(); + new BroadcastThread().start(); + + Logger.print("Portal is now running..."); + + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + if (!settings.getJedisPool().isClosed()) { + settings.getJedisPool().close(); + } + } + }); + } + + public static void main(String[] args) { + instance = new Portal(); + } + +} diff --git a/Independent/src/main/java/me/joeleoli/portal/independent/file/Config.java b/Independent/src/main/java/me/joeleoli/portal/independent/file/Config.java new file mode 100644 index 0000000..e0abe6b --- /dev/null +++ b/Independent/src/main/java/me/joeleoli/portal/independent/file/Config.java @@ -0,0 +1,66 @@ +package me.joeleoli.portal.independent.file; + +import lombok.Getter; + +import java.io.*; +import java.util.Properties; + +@Getter +public class Config { + + private String[] hubs; + private String[] queues; + private String redisHost; + private int redisPort; + private String redisPassword; + + public Config() { + File file = new File("config.properties"); + + if (!file.exists()) { + try { + file.createNewFile(); + + FileOutputStream output = new FileOutputStream(file); + output.write("hubs=hub-01\n".getBytes()); + output.write("queues=test1,test2,test3\n".getBytes()); + output.write("redis-host=127.0.0.1\n".getBytes()); + output.write("redis-port=6379\n".getBytes()); + output.write("redis-password=dev\n".getBytes()); + output.flush(); + output.close(); + } catch (IOException io) { + io.printStackTrace(); + } + } + + Properties prop = new Properties(); + InputStream input = null; + + try { + input = new FileInputStream("config.properties"); + + prop.load(input); + + this.hubs = ((String) prop.getOrDefault("hubs", "")).split(","); + this.queues = ((String) prop.getOrDefault("queues", "")).split(","); + this.redisHost = ((String) prop.getOrDefault("redis-host", "127.0.0.1")); + this.redisPort = Integer.valueOf((String) prop.getOrDefault("redis-port", "6379")); + this.redisPassword = ((String) prop.getOrDefault("redis-password", "")); + } + catch (IOException io) { + io.printStackTrace(); + } + finally { + if (input != null) { + try { + input.close(); + } + catch (IOException e) { + e.printStackTrace(); + } + } + } + } + +} diff --git a/Independent/src/main/java/me/joeleoli/portal/independent/jedis/PortalSubscriptionHandler.java b/Independent/src/main/java/me/joeleoli/portal/independent/jedis/PortalSubscriptionHandler.java new file mode 100644 index 0000000..91823c1 --- /dev/null +++ b/Independent/src/main/java/me/joeleoli/portal/independent/jedis/PortalSubscriptionHandler.java @@ -0,0 +1,189 @@ +package me.joeleoli.portal.independent.jedis; + +import com.google.gson.JsonObject; + +import me.joeleoli.portal.independent.Portal; +import me.joeleoli.portal.independent.log.Logger; +import me.joeleoli.portal.shared.jedis.JedisAction; +import me.joeleoli.portal.shared.jedis.JedisChannel; +import me.joeleoli.portal.shared.jedis.JedisSubscriptionHandler; +import me.joeleoli.portal.shared.queue.Queue; +import me.joeleoli.portal.shared.queue.QueuePlayer; +import me.joeleoli.portal.shared.queue.QueueRank; +import me.joeleoli.portal.shared.server.ServerData; + +import java.util.Iterator; +import java.util.UUID; + +public class PortalSubscriptionHandler implements JedisSubscriptionHandler { + + public void handleMessage(JsonObject json) { + JedisAction action = JedisAction.valueOf(json.get("action").getAsString()); + JsonObject data = json.get("data").isJsonNull() ? null : json.get("data").getAsJsonObject(); + + if (data == null) { + return; + } + + Logger.print("Received " + action.name()); + + switch (action) { + case UPDATE: { + String name = data.get("name").getAsString(); + ServerData serverData = ServerData.getByName(name); + Queue queue = Queue.getByName(name); + + if (serverData == null) { + // Enable queue for the first time + if (queue != null) { + queue.setEnabled(true); + + Logger.print("Initiated queue `" + name + "`"); + } + + // Instantiate server data (which gets stored) + serverData = new ServerData(name); + + Logger.print("Initiated server data `" + name + "`"); + } + + serverData.setOnlinePlayers(data.get("online-players").getAsInt()); + serverData.setMaximumPlayers(data.get("maximum-players").getAsInt()); + serverData.setWhitelisted(data.get("whitelisted").getAsBoolean()); + serverData.setLastUpdate(System.currentTimeMillis()); + + Logger.print("Updated data of `" + name + "`"); + } + break; + case CLEAR_PLAYERS: { + Queue queue = Queue.getByName(data.get("queue").getAsString()); + + if (queue == null) { + return; + } + + queue.getPlayers().clear(); + + Logger.print("Cleared players of `" + queue.getName() + "`"); + } + break; + case TOGGLE: { + Queue queue = Queue.getByName(data.get("queue").getAsString()); + + if (queue == null) { + return; + } + + queue.setEnabled(!queue.isEnabled()); + + Logger.print("Changed status of `" + queue.getName() + "` to " + queue.isEnabled()); + } + break; + case ADD_PLAYER: { + Queue queue = Queue.getByName(data.get("queue").getAsString()); + + if (queue == null) { + return; + } + + JsonObject player = data.get("player").getAsJsonObject(); + JsonObject rank = player.get("rank").getAsJsonObject(); + + QueueRank queueRank = new QueueRank(); + queueRank.setName(rank.get("name").getAsString()); + queueRank.setPriority(rank.get("priority").getAsInt()); + + QueuePlayer queuePlayer = new QueuePlayer(); + queuePlayer.setUuid(UUID.fromString(player.get("uuid").getAsString())); + queuePlayer.setRank(queueRank); + queuePlayer.setInserted(System.currentTimeMillis()); + + queue.getPlayers().add(queuePlayer); + + player.addProperty("inserted", queuePlayer.getInserted()); + + data.add("player", player); + + Portal.getInstance().getPublisher().write(JedisChannel.BUKKIT, JedisAction.ADDED_PLAYER, data); + } + break; + case REMOVE_PLAYER: { + UUID uuid = UUID.fromString(data.get("uuid").getAsString()); + + Queue queue = Queue.getByPlayer(uuid); + + if (queue == null) { + return; + } + + QueuePlayer queuePlayer = null; + + Iterator iterator = queue.getPlayers().iterator(); + + while (iterator.hasNext()) { + QueuePlayer other = iterator.next(); + + if (other.getUuid().equals(uuid)) { + queuePlayer = other; + + iterator.remove(); + } + } + + if (queuePlayer == null) { + return; + } + + JsonObject rank = new JsonObject(); + rank.addProperty("name", queuePlayer.getRank().getName()); + rank.addProperty("priority", queuePlayer.getRank().getPriority()); + + JsonObject player = new JsonObject(); + player.addProperty("uuid", queuePlayer.getUuid().toString()); + player.addProperty("inserted", queuePlayer.getInserted()); + player.add("rank", rank); + + JsonObject responseData = new JsonObject(); + responseData.addProperty("queue", queue.getName()); + responseData.add("player", player); + + Portal.getInstance().getPublisher().write(JedisChannel.BUKKIT, JedisAction.REMOVED_PLAYER, + responseData); + } + break; + case SEND_PLAYER_HUB: { + String uuid = data.get("uuid").getAsString(); + + ServerData hub = null; + + for (String loopHub : Portal.getInstance().getConfig().getHubs()) { + ServerData serverData = ServerData.getByName(loopHub); + + if (serverData != null) { + if (hub == null || serverData.getOnlinePlayers() < hub.getOnlinePlayers()) { + hub = serverData; + } + } + } + + if (hub == null) { + JsonObject responseData = new JsonObject(); + responseData.addProperty("uuid", uuid); + responseData.addProperty("message", "&cThere are no hubs to send you to."); + + Portal.getInstance().getPublisher().write(JedisChannel.BUKKIT, JedisAction.MESSAGE_PLAYER, + responseData); + } else { + JsonObject responseData = new JsonObject(); + responseData.addProperty("uuid", uuid); + responseData.addProperty("server", hub.getName()); + + Portal.getInstance().getPublisher().write(JedisChannel.BUKKIT, JedisAction.SEND_PLAYER_SERVER, + responseData); + } + } + break; + } + } + +} diff --git a/Independent/src/main/java/me/joeleoli/portal/independent/log/Logger.java b/Independent/src/main/java/me/joeleoli/portal/independent/log/Logger.java new file mode 100644 index 0000000..5a70f55 --- /dev/null +++ b/Independent/src/main/java/me/joeleoli/portal/independent/log/Logger.java @@ -0,0 +1,15 @@ +package me.joeleoli.portal.independent.log; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Calendar; + +public class Logger { + + private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); + + public static void print(String message) { + System.out.println("[" + DATE_FORMAT.format(Calendar.getInstance().getTime()) + "] [Portal] " + message); + } + +} diff --git a/Independent/src/main/java/me/joeleoli/portal/independent/thread/BroadcastThread.java b/Independent/src/main/java/me/joeleoli/portal/independent/thread/BroadcastThread.java new file mode 100644 index 0000000..c14dcca --- /dev/null +++ b/Independent/src/main/java/me/joeleoli/portal/independent/thread/BroadcastThread.java @@ -0,0 +1,60 @@ +package me.joeleoli.portal.independent.thread; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import me.joeleoli.portal.independent.Portal; +import me.joeleoli.portal.independent.log.Logger; +import me.joeleoli.portal.shared.jedis.JedisAction; +import me.joeleoli.portal.shared.jedis.JedisChannel; +import me.joeleoli.portal.shared.queue.Queue; +import me.joeleoli.portal.shared.queue.QueuePlayer; +import me.joeleoli.portal.shared.server.ServerData; + +public class BroadcastThread extends Thread { + + @Override + public void run() { + while (true) { + JsonArray queues = new JsonArray(); + + for (Queue queue : Queue.getQueues()) { + JsonArray players = new JsonArray(); + + for (QueuePlayer player : queue.getPlayers()) { + JsonObject rank = new JsonObject(); + rank.addProperty("name", player.getRank().getName()); + rank.addProperty("priority", player.getRank().getPriority()); + + JsonObject json = new JsonObject(); + json.addProperty("uuid", player.getUuid().toString()); + json.addProperty("inserted", player.getInserted()); + json.add("rank", rank); + + players.add(json); + } + + JsonObject json = new JsonObject(); + json.addProperty("name", queue.getName()); + json.addProperty("status", queue.isEnabled()); + json.add("players", players); + + queues.add(json); + } + + JsonObject json = new JsonObject(); + + json.add("queues", queues); + + Portal.getInstance().getPublisher().write(JedisChannel.BUKKIT, JedisAction.LIST, json); + + Logger.print("Broadcasted server and queue list"); + + try { + Thread.sleep(5000L); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + +} diff --git a/Independent/src/main/java/me/joeleoli/portal/independent/thread/QueueThread.java b/Independent/src/main/java/me/joeleoli/portal/independent/thread/QueueThread.java new file mode 100644 index 0000000..60aae43 --- /dev/null +++ b/Independent/src/main/java/me/joeleoli/portal/independent/thread/QueueThread.java @@ -0,0 +1,60 @@ +package me.joeleoli.portal.independent.thread; + +import com.google.gson.JsonObject; +import me.joeleoli.portal.independent.Portal; +import me.joeleoli.portal.shared.jedis.JedisChannel; +import me.joeleoli.portal.shared.queue.Queue; +import me.joeleoli.portal.shared.queue.QueuePlayer; +import me.joeleoli.portal.shared.jedis.JedisAction; +import me.joeleoli.portal.shared.server.ServerData; + +public class QueueThread extends Thread { + + private static final Long SEND_DELAY = 500L; + + @Override + public void run() { + while (true) { + for (Queue queue : Queue.getQueues()) { + ServerData serverData = queue.getServerData(); + + if (serverData == null) { + continue; + } + + if (!queue.isEnabled()) { + continue; + } + + if (!serverData.isOnline()) { + continue; + } + + if (serverData.isWhitelisted()) { + continue; + } + + if (serverData.getOnlinePlayers() >= serverData.getMaximumPlayers()) { + continue; + } + + QueuePlayer next = queue.getPlayers().poll(); + + if (next != null) { + JsonObject data = new JsonObject(); + data.addProperty("server", queue.getName()); + data.addProperty("uuid", next.getUuid().toString()); + + Portal.getInstance().getPublisher().write(JedisChannel.BUKKIT, JedisAction.SEND_PLAYER_SERVER, data); + } + } + + try { + Thread.sleep(SEND_DELAY); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + +} diff --git a/README.md b/README.md index d0b467c..0435bbe 100644 --- a/README.md +++ b/README.md @@ -1 +1,25 @@ -# portal \ No newline at end of file +# Portal + +A multi-proxy player queue. + +## How It Works +* Player joins a queue through a hub. +* Hub sends a message to the Independent module to add that player to that queue. +* Independent module constantly checks if a queue can send a player. If a player can be sent, a message is broadcasted to all Bukkit instances that the next player in the queue (based on rank priority) should be sent to the server. +* Any Bukkit instance that contains the player will use plugin messages to send the player. + +## Commands +| Command syntax | Description | Permission | +| ---------------------------- | ----------------------------------- | ---------------- | +| /queueclear \ | Clear the list of a queue | portal.clear | +| /queuetoggle \ | Toggle (pause) a queue | portal.toggle | +| /forcesend \ \ | Force sends a player to a server | portal.forcesend | +| /datadump | Displays all server data and queues | portal.datadump | + +## Priority +Queue priority can be assigned through permissions (config.yml) or by using your own implementation. + +To implement your own priority system, extend `PriorityProvider` and set the instance provider using `Portal.getInstance().setPriorityProvider(provider)`. + +## Bypass +Players that have the `portal.bypass` permission will immediately be sent to a server instead of joining a queue. \ No newline at end of file diff --git a/Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisAction.java b/Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisAction.java new file mode 100644 index 0000000..3c59576 --- /dev/null +++ b/Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisAction.java @@ -0,0 +1,17 @@ +package me.joeleoli.portal.shared.jedis; + +public enum JedisAction { + + LIST, + UPDATE, + TOGGLE, + CLEAR_PLAYERS, + ADD_PLAYER, + ADDED_PLAYER, + REMOVE_PLAYER, + REMOVED_PLAYER, + SEND_PLAYER_SERVER, + SEND_PLAYER_HUB, + MESSAGE_PLAYER + +} diff --git a/Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisChannel.java b/Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisChannel.java new file mode 100644 index 0000000..15908b5 --- /dev/null +++ b/Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisChannel.java @@ -0,0 +1,8 @@ +package me.joeleoli.portal.shared.jedis; + +public class JedisChannel { + + public static final String BUKKIT = "portal-bukkit"; + public static final String INDEPENDENT = "portal-independent"; + +} diff --git a/Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisPublisher.java b/Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisPublisher.java new file mode 100644 index 0000000..6d06f0f --- /dev/null +++ b/Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisPublisher.java @@ -0,0 +1,60 @@ +package me.joeleoli.portal.shared.jedis; + +import com.google.gson.JsonObject; + +import lombok.RequiredArgsConstructor; + +import redis.clients.jedis.Jedis; + +import java.util.LinkedList; +import java.util.Queue; + +@RequiredArgsConstructor +public class JedisPublisher extends Thread { + + private final JedisSettings jedisSettings; + private Queue queue = new LinkedList<>(); + + @Override + public void run() { + while (true) { + if (!this.queue.isEmpty()) { + Jedis jedis = null; + + try { + jedis = this.jedisSettings.getJedisPool().getResource(); + + if (this.jedisSettings.hasPassword()) { + jedis.auth(this.jedisSettings.getPassword()); + } + + while (!this.queue.isEmpty()) { + JedisQueue queue = this.queue.poll(); + + JsonObject json = new JsonObject(); + json.addProperty("action", queue.getAction().name()); + json.add("data", queue.getData()); + + jedis.publish(queue.getChannel(), json.toString()); + } + } + finally { + if (jedis != null) { + jedis.close(); + } + } + } + + try { + Thread.sleep(50L); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + public void write(String channel, JedisAction action, JsonObject data) { + this.queue.add(new JedisQueue(channel, action, data)); + } + +} diff --git a/Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisQueue.java b/Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisQueue.java new file mode 100644 index 0000000..8c2e084 --- /dev/null +++ b/Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisQueue.java @@ -0,0 +1,16 @@ +package me.joeleoli.portal.shared.jedis; + +import com.google.gson.JsonObject; +import lombok.Data; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +@Data +@RequiredArgsConstructor +class JedisQueue { + + @NonNull private String channel; + @NonNull private JedisAction action; + @NonNull private JsonObject data; + +} diff --git a/Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisSettings.java b/Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisSettings.java new file mode 100644 index 0000000..9d96835 --- /dev/null +++ b/Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisSettings.java @@ -0,0 +1,27 @@ +package me.joeleoli.portal.shared.jedis; + +import lombok.Getter; + +import redis.clients.jedis.JedisPool; + +@Getter +public class JedisSettings { + + private final String address; + private final int port; + private final String password; + private final JedisPool jedisPool; + + public JedisSettings(String address, int port, String password) { + this.address = address; + this.port = port; + this.password = password; + + this.jedisPool = new JedisPool(this.address, this.port); + } + + public boolean hasPassword() { + return this.password != null && !this.password.equals(""); + } + +} diff --git a/Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisSubscriber.java b/Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisSubscriber.java new file mode 100644 index 0000000..954b22c --- /dev/null +++ b/Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisSubscriber.java @@ -0,0 +1,58 @@ +package me.joeleoli.portal.shared.jedis; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonParser; +import lombok.Getter; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPubSub; + +@Getter +public class JedisSubscriber { + + private static final JsonParser JSON_PARSER = new JsonParser(); + + private final String channel; + private final JedisSettings settings; + private final Jedis jedis; + private JedisPubSub pubSub; + private JedisSubscriptionHandler subscriptionHandler; + + public JedisSubscriber(String channel, JedisSettings settings, JedisSubscriptionHandler subscriptionHandler) { + this.channel = channel; + this.settings = settings; + this.subscriptionHandler = subscriptionHandler; + + this.pubSub = new JedisPubSub() { + @Override + public void onMessage(String channel, String message) { + try { + JsonObject object = JSON_PARSER.parse(message).getAsJsonObject(); + + JedisSubscriber.this.subscriptionHandler.handleMessage(object); + } catch (JsonParseException e) { + System.out.println("Received message that could not be parsed"); + } + } + }; + + this.jedis = new Jedis(this.settings.getAddress(), this.settings.getPort()); + + if (this.settings.hasPassword()) { + this.jedis.auth(this.settings.getPassword()); + } + + new Thread(() -> this.jedis.subscribe(this.pubSub, this.channel)).start(); + } + + public void close() { + if (this.pubSub != null) { + this.pubSub.unsubscribe(); + } + + if (this.jedis != null) { + this.jedis.close(); + } + } + +} diff --git a/Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisSubscriptionHandler.java b/Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisSubscriptionHandler.java new file mode 100644 index 0000000..982f179 --- /dev/null +++ b/Shared/src/main/java/me/joeleoli/portal/shared/jedis/JedisSubscriptionHandler.java @@ -0,0 +1,9 @@ +package me.joeleoli.portal.shared.jedis; + +import com.google.gson.JsonObject; + +public interface JedisSubscriptionHandler { + + void handleMessage(JsonObject json); + +} diff --git a/Shared/src/main/java/me/joeleoli/portal/shared/queue/Queue.java b/Shared/src/main/java/me/joeleoli/portal/shared/queue/Queue.java new file mode 100644 index 0000000..d7a88a6 --- /dev/null +++ b/Shared/src/main/java/me/joeleoli/portal/shared/queue/Queue.java @@ -0,0 +1,88 @@ +package me.joeleoli.portal.shared.queue; + +import me.joeleoli.portal.shared.server.ServerData; +import lombok.Getter; +import lombok.Setter; + +import java.util.*; + +@Getter +public class Queue { + + @Getter + private static List queues = new ArrayList<>(); + + private String name; + @Setter private PriorityQueue players = new PriorityQueue<>(new QueuePlayerComparator()); + @Setter private boolean enabled; + + public Queue(String name) { + this.name = name; + + queues.add(this); + } + + public ServerData getServerData() { + return ServerData.getByName(this.name); + } + + public boolean containsPlayer(UUID uuid) { + for (QueuePlayer player : this.players) { + if (player.getUuid().equals(uuid)) { + return true; + } + } + + return false; + } + + public int getPosition(UUID uuid) { + if (!this.containsPlayer(uuid)) { + return 0; + } + + PriorityQueue queue = new PriorityQueue<>(this.players); + + int position = 0; + + while (!queue.isEmpty()) { + QueuePlayer player = queue.poll(); + + if (player.getUuid().equals(uuid)) { + break; + } + + position++; + } + + return position + 1; + } + + @Override + public String toString() { + return ""; + } + + public static Queue getByName(String name) { + for (Queue queue : Queue.getQueues()) { + if (queue.getName().equalsIgnoreCase(name)) { + return queue; + } + } + + return null; + } + + public static Queue getByPlayer(UUID uuid) { + for (Queue queue : Queue.getQueues()) { + for (QueuePlayer queuePlayer : queue.getPlayers()) { + if (queuePlayer.getUuid().equals(uuid)) { + return queue; + } + } + } + + return null; + } + +} diff --git a/Shared/src/main/java/me/joeleoli/portal/shared/queue/QueuePlayer.java b/Shared/src/main/java/me/joeleoli/portal/shared/queue/QueuePlayer.java new file mode 100644 index 0000000..57bb46a --- /dev/null +++ b/Shared/src/main/java/me/joeleoli/portal/shared/queue/QueuePlayer.java @@ -0,0 +1,40 @@ +package me.joeleoli.portal.shared.queue; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.UUID; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class QueuePlayer implements Comparable { + + private UUID uuid; + private QueueRank rank; + private long inserted; + + @Override + public int compareTo(Object object) { + int result = 0; + + if (object instanceof QueuePlayer) { + QueuePlayer otherPlayer = (QueuePlayer) object; + result = this.rank.getPriority() - otherPlayer.getRank().getPriority(); + + if (result == 0) { + if (this.inserted < otherPlayer.getInserted()) { + return -1; + } else { + return 1; + } + } + } + + return result; + } + +} diff --git a/Shared/src/main/java/me/joeleoli/portal/shared/queue/QueuePlayerComparator.java b/Shared/src/main/java/me/joeleoli/portal/shared/queue/QueuePlayerComparator.java new file mode 100644 index 0000000..b588d7a --- /dev/null +++ b/Shared/src/main/java/me/joeleoli/portal/shared/queue/QueuePlayerComparator.java @@ -0,0 +1,12 @@ +package me.joeleoli.portal.shared.queue; + +import java.util.Comparator; + +public class QueuePlayerComparator implements Comparator { + + @Override + public int compare(QueuePlayer firstPlayer, QueuePlayer secondPlayer) { + return firstPlayer.compareTo(secondPlayer); + } + +} \ No newline at end of file diff --git a/Shared/src/main/java/me/joeleoli/portal/shared/queue/QueueRank.java b/Shared/src/main/java/me/joeleoli/portal/shared/queue/QueueRank.java new file mode 100644 index 0000000..65c9c5a --- /dev/null +++ b/Shared/src/main/java/me/joeleoli/portal/shared/queue/QueueRank.java @@ -0,0 +1,28 @@ +package me.joeleoli.portal.shared.queue; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class QueueRank implements Comparable { + + private String name; + private int priority; + + @Override + public int compareTo(Object o) { + int result = 0; + + if (o instanceof QueueRank) { + result = this.priority - ((QueueRank) o).priority; + } + + return result; + } + +} diff --git a/Shared/src/main/java/me/joeleoli/portal/shared/server/ServerData.java b/Shared/src/main/java/me/joeleoli/portal/shared/server/ServerData.java new file mode 100644 index 0000000..8aec406 --- /dev/null +++ b/Shared/src/main/java/me/joeleoli/portal/shared/server/ServerData.java @@ -0,0 +1,46 @@ +package me.joeleoli.portal.shared.server; + +import lombok.Data; +import lombok.Getter; + +import java.util.HashSet; +import java.util.Set; + +@Data +public class ServerData { + + @Getter + private static Set servers = new HashSet<>(); + + private String name; + private int onlinePlayers; + private int maximumPlayers; + private boolean whitelisted; + private long lastUpdate; + + public ServerData(String name) { + this.name = name; + + servers.add(this); + } + + public boolean isOnline() { + return System.currentTimeMillis() - this.lastUpdate < 15000L; + } + + @Override + public String toString() { + return ""; + } + + public static ServerData getByName(String name) { + for (ServerData server : servers) { + if (server.getName().equalsIgnoreCase(name)) { + return server; + } + } + + return null; + } + +}