package com.lifeknight.relaymcbungeemain.queue; import com.google.gson.JsonArray; import com.lifeknight.relaymcbungeemain.Main; import com.lifeknight.relaymcbungeemain.player.Party; import com.lifeknight.relaymcbungeemain.player.SmartPlayer; import com.lifeknight.relaymcbungeemain.utilities.MessageUtils; import com.lifeknight.relaymcbungeemain.utilities.Utilities; import com.lifeknight.relayutils.RelayUtils; import com.lifeknight.relayutils.basic.Miscellaneous; import com.lifeknight.relayutils.basic.Text; import com.lifeknight.relayutils.data.QueueData; import com.lifeknight.relayutils.game.GameDetails; import com.lifeknight.relayutils.game.GameType; import com.lifeknight.relayutils.game.MainGame; import com.lifeknight.relayutils.network.Command; import com.lifeknight.relayutils.player.Group; import com.lifeknight.relayutils.utilities.ComponentBuilder; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.CommandSender; import java.util.*; public class Queue { public final static Map<MainGame, Queue> QUEUES = new HashMap<>(); static { for (MainGame gameTypeMainName : MainGame.values()) { QUEUES.put(gameTypeMainName, new Queue()); } } private final PlayerGroupList remainingPlayersToJoin; public Queue() { this.remainingPlayersToJoin = new PlayerGroupList(); } public static void onPlayerLeave(SmartPlayer smartPlayer) { for (Queue queue : QUEUES.values()) { GameType wasInGameType; if ((wasInGameType = queue.remainingPlayersToJoin.removePlayerInadvertently(smartPlayer)) != null) { smartPlayer.queueInfoMessageForJoin("Left %s queue.", wasInGameType.getPrefix()); smartPlayer.emptyQueue(); check(); break; } } } public static synchronized int getQueueSize(GameType gameType) { Queue queue = QUEUES.get(gameType.getMainGame()); return queue.getSize(gameType); } public static synchronized int getQueuePosition(SmartPlayer smartPlayer) { for (Queue value : QUEUES.values()) { if (value.remainingPlayersToJoin.hasPlayer(smartPlayer)) { return value.remainingPlayersToJoin.getPosition(smartPlayer); } } return -1; } public static synchronized int getQueueSize(SmartPlayer smartPlayer) { for (Queue value : QUEUES.values()) { if (value.remainingPlayersToJoin.hasPlayer(smartPlayer)) { return value.remainingPlayersToJoin.getQueueSize(smartPlayer); } } return -1; } public static void onGameDetailsUpdate() { Main.schedule(Queue::check, 2); } public static void check() { Main.synchronous(() -> { for (Queue queue : QUEUES.values()) { queue.onQueueChange(); queue.checkForNextGame(null, null, new ArrayList<>()); } }); } public static void removePlayerInadvertently(SmartPlayer smartPlayer, Queue queueing) { for (Queue value : QUEUES.values()) { if (value != queueing) value.cancelPlayerInadvertently(smartPlayer); } } public static void removePartyInadvertently(SmartPlayer smartPlayer, Party party, Queue queuing) { for (Queue value : QUEUES.values()) { if (value != queuing) value.cancelPartyInadvertently(smartPlayer, party); } } public static void removePlayersInadvertently(List<SmartPlayer> smartPlayers, Queue queue) { for (Queue value : QUEUES.values()) { if (queue != value) { value.cancelPlayersInadvertently(smartPlayers); } } } public static void addPartyToQueue(GameType gameType, QueueData queueData, SmartPlayer smartPlayer, Party party) { Main.synchronous(() -> QUEUES.get(gameType.getMainGame()).addParty(smartPlayer, party, gameType, queueData)); } public static void addPlayerToQueue(GameType gameType, QueueData queueData, SmartPlayer smartPlayer) { Main.synchronous(() -> QUEUES.get(gameType.getMainGame()).addPlayer(smartPlayer, gameType, queueData)); } public static void removePartyFromQueue(GameType gameType, SmartPlayer smartPlayer, Party party) { Main.synchronous(() -> QUEUES.get(gameType.getMainGame()).cancelParty(smartPlayer, party, gameType)); } public static void removePlayerFromQueue(GameType gameType, SmartPlayer smartPlayer) { Main.synchronous(() -> QUEUES.get(gameType.getMainGame()).cancelPlayer(smartPlayer, gameType)); } public static synchronized boolean isInFastQueue(SmartPlayer smartPlayer) { for (Queue value : QUEUES.values()) { if (value.remainingPlayersToJoin.hasPlayer(smartPlayer)) { return value.remainingPlayersToJoin.isFastQueue(smartPlayer); } } return false; } public static void rematch(SmartPlayer smartPlayer, SmartPlayer opponent, GameType rematchGameType, QueueData rematchQueueData) { QUEUES.get(rematchGameType.getMainGame()).addPlayers(Miscellaneous.getList(smartPlayer, opponent), rematchGameType, rematchQueueData); } public static List<QueueData> getQueuedGames() { List<QueueData> data = new ArrayList<>(); for (Queue value : QUEUES.values()) { PlayerGroupList playerGroupList = value.remainingPlayersToJoin; List<PlayerGroup> groups = Miscellaneous.with(playerGroupList.fastPlayerGroups, playerGroupList.normalPlayerGroups); for (PlayerGroup group : groups) { group.queueData.attachData("gameType", group.gameType); group.queueData.attachData("queued", Text.toCSV(Miscellaneous.processList(group.players, SmartPlayer::getUUID))); data.add(group.queueData); } } return data; } public void addPlayers(List<SmartPlayer> smartPlayers, GameType gameType, QueueData queueData) { removePlayersInadvertently(smartPlayers, this); int max = queueData.isParty() ? 64 : (gameType.isTeamGame() ? gameType.getTeamSize() : gameType.getTotalPlayerCount()); if (smartPlayers.size() > max && !(queueData.hasData("owner") || queueData.hasData("with"))) { smartPlayers.get(0).sendErrorMessage("Your party size is too large! You can play with a maximum of %d players.", max); } else if (this.remainingPlayersToJoin.addPlayers(smartPlayers, gameType, queueData)) { if (!this.checkForNextGame(gameType, queueData, smartPlayers)) { boolean hasChampion = !Miscellaneous.filter(smartPlayers, SmartPlayer::hasChampion).isEmpty(); if (hasChampion) { smartPlayers.forEach(smartPlayer -> smartPlayer.sendSuccessMessage("Joined %s queue. Use %s/cancel%s to leave.", gameType.getPrefix(), ChatColor.YELLOW, ChatColor.GREEN)); } else { smartPlayers.forEach(smartPlayer -> smartPlayer.sendSuccessMessage("Joined %s queue. Use %s/cancel%s to leave. To skip the queue, purchase %sPremium %srank using %s/premium!", gameType.getPrefix(), ChatColor.YELLOW, ChatColor.GREEN, Group.CHAMPION.getColor(), ChatColor.GREEN, ChatColor.AQUA)); } smartPlayers.forEach(smartPlayer -> { smartPlayer.setQueue(gameType); smartPlayer.playSuccessSound(); }); if (queueData.hasData("/duel")) { smartPlayers.forEach(smartPlayer -> smartPlayer.sendInfoMessage("No servers are currently available, so you have been placed into the queue.")); } } this.onQueueChange(); } } public int getSize(GameType gameType) { return this.remainingPlayersToJoin.getSize(gameType); } public static int[] getQueueInformation(SmartPlayer smartPlayer) { int queueSize = -1; int queuePosition = -1; int specificSize = -1; int specificPosition = -1; int typeSize = -1; boolean fastQueue = false; boolean serverAvailable = false; if (smartPlayer.isInQueue()) { Queue queue = QUEUES.get(smartPlayer.getCurrentQueue().getMainGame()); if (queue.remainingPlayersToJoin.hasPlayer(smartPlayer)) { queuePosition = queue.remainingPlayersToJoin.getPosition(smartPlayer); queueSize = queue.remainingPlayersToJoin.getQueueSize(smartPlayer); specificPosition = queue.remainingPlayersToJoin.getSpecificPosition(smartPlayer); specificSize = queue.remainingPlayersToJoin.getSpecificSize(smartPlayer); typeSize = queue.remainingPlayersToJoin.getTypeSize(smartPlayer); fastQueue = queue.remainingPlayersToJoin.isFastQueue(smartPlayer); serverAvailable = queue.remainingPlayersToJoin.availableServer(smartPlayer); } } return new int[]{queueSize, queuePosition, specificSize, specificPosition, typeSize, fastQueue ? 1 : 0, serverAvailable ? 1 : 0}; } public synchronized boolean checkForNextGame(GameType gameType, QueueData queueData, List<SmartPlayer> smartPlayers) { /*if (gameType != null && !gameType.isWaitForFullQueue()) { if (!smartPlayers.isEmpty()) { GameServer gameServer = Utilities.getBestServer(gameType, smartPlayers); if (gameServer == null) { if (RelayUtils.log) { Main.info("Was going to queue players, no server found."); } return false; } GameDetails gameDetails = gameServer.getAvailable(gameType, smartPlayers); if () this.queuePlayers(gameServer, smartPlayers, gameType, queueData); return true; } }*/ List<PlayerGroup> nextPlayers = this.remainingPlayersToJoin.nextPlayers(); if (nextPlayers != null) { List<SmartPlayer> asSmartPlayers = new ArrayList<>(); GameType theGameType = Miscellaneous.getFirstEntry(nextPlayers).gameType; QueueData theQueueData = new QueueData(); for (PlayerGroup playerGroup : nextPlayers) { asSmartPlayers.addAll(playerGroup.players); if (playerGroup.queueData.isParty()) { theQueueData.setParty(); } } for (PlayerGroup nextPlayer : nextPlayers) { if (nextPlayer.queueData.hasData("other") && !nextPlayer.queueData.getBoolean("other")) { theQueueData = nextPlayer.queueData.attachData("owner", nextPlayer.leader.getUUID()); break; } else if (nextPlayer.queueData.hasData("owner")) { theQueueData = nextPlayer.queueData; break; } } for (PlayerGroup nextPlayer : nextPlayers) { if (nextPlayer.queueData.hasData("lobby")) { theQueueData.attachData("lobby", nextPlayer.queueData.getData("lobby")); } } if (nextPlayers.size() == 1 && !theQueueData.isParty()) { theQueueData.attachBoolean("/duel", true); } GameServer gameServer = Utilities.getBestServer(theGameType, asSmartPlayers); if (gameServer == null) { if (RelayUtils.log) { Main.info("Was going to queue players, no server found."); } return false; } GameDetails gameDetails = gameServer.getAvailable(gameType, asSmartPlayers); if (gameDetails != null && (Utilities.suitableQueueSize(theGameType, Miscellaneous.processList(nextPlayers, playerGroup -> playerGroup.queueData), gameDetails.getPlayerCount() + asSmartPlayers.size()) || gameDetails.getPlayerCount() > 0)) { this.syncQueue(gameServer, asSmartPlayers, theGameType, theQueueData); return new HashSet<>(asSmartPlayers).containsAll(smartPlayers); } } return false; } public void syncQueue(GameServer gameServer, List<SmartPlayer> smartPlayers, GameType gameType, QueueData queueData) { Main.synchronous(() -> this.queuePlayers(gameServer, smartPlayers, gameType, queueData)); } public synchronized void queuePlayers(GameServer gameServer, List<SmartPlayer> smartPlayers, GameType gameType, QueueData queueData) { if (gameServer == null) return; List<String> uuids = new ArrayList<>(); for (SmartPlayer smartPlayer : smartPlayers) { uuids.add(smartPlayer.getUUID().toString()); if (smartPlayer.getCurrentQueue() == null) { Main.warn("Player is being queued despite not having current queue! %s", smartPlayer.getName()); } if (!queueData.hasData("/duel")) { smartPlayer.emptyQueue(); } this.remainingPlayersToJoin.removePlayer(smartPlayer, true); } GameDetails gameDetails = gameServer.getAvailable(gameType, smartPlayers); if (gameDetails == null) { Main.error("Game details for queing are null: %s | %s | %s", gameServer.getServer().getName(), gameType, queueData); return; } UUID queueUUID = gameDetails.getUUID(); gameDetails.increasePlayerCount(smartPlayers.size()); if (gameDetails.getPlayerCount() + smartPlayers.size() >= gameType.getTotalPlayerCount() || (gameType.isPartyType() && queueData.isParty())) { gameServer.markQueue(queueUUID); } if (RelayUtils.log) { Main.info("Queueing players to %s (%s | %s): %s | %s", gameServer.getServer().getName(), gameType.getFullPrettyName(), queueData, Text.toStringList(smartPlayers, SmartPlayer::getName), queueUUID); } List<Party> parties = new ArrayList<>(); for (SmartPlayer smartPlayer : smartPlayers) { if (smartPlayer.isInParty()) { Miscellaneous.addIfAbsent(parties, smartPlayer.getCurrentParty()); } } JsonArray partiesJson = new JsonArray(); for (Party party1 : parties) { partiesJson.add(party1.getPartyData().getAsJson()); } MessageUtils.createAndSend(gameServer.getRecipient(), Command.QUEUE, queueUUID, gameType.getCodeName(), queueData, partiesJson, Text.toCSV(uuids)); } public void addPlayer(SmartPlayer smartPlayer, GameType gameType, QueueData queueData) { removePlayerInadvertently(smartPlayer, this); if (this.remainingPlayersToJoin.addPlayer(smartPlayer, gameType, queueData)) { if (!this.checkForNextGame(gameType, queueData, Miscellaneous.getList(smartPlayer))) { if (smartPlayer.isInGroupOrHigher(Group.CHAMPION)) { smartPlayer.sendSuccessMessage("Joined %s queue. Use %s/cancel%s to leave.", gameType.getPrefix(), ChatColor.YELLOW, ChatColor.GREEN); } else { smartPlayer.sendSuccessMessage("Joined %s queue. Use %s/cancel%s to leave. To skip the queue, purchase %sPremium %srank using %s/premium!", gameType.getPrefix(), ChatColor.YELLOW, ChatColor.GREEN, Group.CHAMPION.getColor(), ChatColor.GREEN, ChatColor.AQUA); } smartPlayer.setQueue(gameType); smartPlayer.playSuccessSound(); } this.onQueueChange(); } else { smartPlayer.sendErrorMessage("You are already in the %s queue!", gameType.getMainGameName()); } } public void cancelPlayer(SmartPlayer smartPlayer, GameType game) { if (this.remainingPlayersToJoin.removePlayer(smartPlayer)) { this.onQueueChange(); smartPlayer.sendInfoMessage("Left %s queue.", game.getPrefix()); smartPlayer.emptyQueue(); } else { smartPlayer.sendErrorMessage("You are not in the %s queue!", game.getPrefix()); } } public void cancelPlayerInadvertently(SmartPlayer smartPlayer) { GameType wasInGameType; if ((wasInGameType = this.remainingPlayersToJoin.removePlayerInadvertently(smartPlayer)) != null) { this.onQueueChange(); smartPlayer.sendInfoMessage("Left %s queue.", wasInGameType.getPrefix()); smartPlayer.emptyQueue(); } } public void cancelPlayerInadvertently(SmartPlayer smartPlayer, GameType gameType) { GameType wasInGameType; if ((wasInGameType = this.remainingPlayersToJoin.removePlayerInadvertently(smartPlayer)) != null) { if (wasInGameType != gameType) { this.onQueueChange(); smartPlayer.sendInfoMessage("Left %s queue.", wasInGameType.getPrefix()); smartPlayer.emptyQueue(); } } } public void duelPlayers(GameType gameType, SmartPlayer caller, SmartPlayer otherPlayer) { /* GameServer gameServer = Utilities.getBestServer(gameType, Miscellaneous.getList(caller, otherPlayer)); if (gameServer != null) { this.syncQueue(gameServer, Miscellaneous.getList(caller, otherPlayer), gameType, new QueueData().attachBoolean("/duel", true).attachData("owner", caller.getUUID())); this.onQueueChange(); } else { caller.sendErrorMessage("There are no servers for you to play on."); otherPlayer.sendErrorMessage("There are no servers for you to play on."); } */ if (gameType == GameType.DUELS_CUSTOM) { addPlayers(Miscellaneous.getList(caller, otherPlayer), gameType, new QueueData().attachData("/duel", true).attachData("owner", caller.getUUID())); } else { addPlayers(Miscellaneous.getList(caller, otherPlayer), gameType, new QueueData().attachData("/duel", true)); } } public void addParty(SmartPlayer smartPlayer, Party party, GameType gameType, QueueData queueData) { removePartyInadvertently(smartPlayer, party, this); int max = queueData.isParty() ? 64 : (gameType.isTeamGame() ? gameType.getTeamSize() : gameType.getTotalPlayerCount()); if (party.getSize() > max && !(queueData.hasData("owner") || queueData.hasData("with"))) { smartPlayer.sendErrorMessage("Your party size is too large! You can play with a maximum of %d players.", max); } else if (this.remainingPlayersToJoin.addParty(party, gameType, queueData)) { if (!this.checkForNextGame(gameType, queueData, party.getPlayers())) { if (smartPlayer.isInGroupOrHigher(Group.CHAMPION)) { smartPlayer.sendSuccessMessage("Joined %s queue. Use %s/cancel%s to leave.", gameType.getPrefix(), ChatColor.YELLOW, ChatColor.GREEN); } else { smartPlayer.sendSuccessMessage("Joined %s queue. Use %s/cancel%s to leave. To skip the queue, purchase %sPremium %srank using %s/premium!", gameType.getPrefix(), ChatColor.YELLOW, ChatColor.GREEN, Group.CHAMPION.getColor(), ChatColor.GREEN, ChatColor.AQUA); } smartPlayer.setQueue(gameType); smartPlayer.playSuccessSound(); for (SmartPlayer otherPlayer : party.getPlayers()) { if (smartPlayer != otherPlayer) { otherPlayer.sendPartySuccessMessage("%s%s joined the %s queue.", smartPlayer.getFormattedName(), ChatColor.GREEN, gameType.getPrefix()); otherPlayer.setQueue(gameType); otherPlayer.playSuccessSound(); } } } this.onQueueChange(); } else { smartPlayer.sendErrorMessage("At least one of your party members is already in the %s queue!", gameType.getPrefix()); } } public void cancelParty(SmartPlayer smartPlayer, Party party, GameType gameType) { if (this.remainingPlayersToJoin.removeParty(party)) { smartPlayer.sendInfoMessage("Left %s queue.", gameType.getPrefix()); smartPlayer.emptyQueue(); for (SmartPlayer otherPlayer : party.getPlayers()) { if (smartPlayer != otherPlayer) { otherPlayer.sendInfoMessage("%s%s left the %s queue.", smartPlayer.getFormattedName(), ChatColor.YELLOW, gameType.getPrefix()); otherPlayer.emptyQueue(); } } this.onQueueChange(); } else { smartPlayer.sendErrorMessage("None of your party members are in the %s queue!", gameType.getPrefix()); } } public void cancelPartyInadvertently(SmartPlayer smartPlayer, Party party) { GameType wasInGameType; if ((wasInGameType = this.remainingPlayersToJoin.removePartyInadvertently(party)) != null) { smartPlayer.sendInfoMessage("Left %s queue.", wasInGameType.getPrefix()); smartPlayer.emptyQueue(); for (SmartPlayer otherPlayer : party.getPlayers()) { if (smartPlayer != otherPlayer) { otherPlayer.sendInfoMessage("%s%s left the %s queue.", smartPlayer.getFormattedName(), ChatColor.YELLOW, wasInGameType.getPrefix()); otherPlayer.emptyQueue(); } } this.onQueueChange(); } } public void cancelPlayersInadvertently(List<SmartPlayer> smartPlayers) { for (SmartPlayer smartPlayer : smartPlayers) { cancelPlayerInadvertently(smartPlayer); } } public void cancelPartyInadvertently(SmartPlayer smartPlayer, Party party, GameType gameType) { GameType wasInGameType; if ((wasInGameType = this.remainingPlayersToJoin.removePartyInadvertently(party)) != null) { if (wasInGameType != gameType) { smartPlayer.sendInfoMessage("Left %s queue.", wasInGameType.getPrefix()); smartPlayer.emptyQueue(); smartPlayer.updateScoreboard(); for (SmartPlayer otherPlayer : party.getPlayers()) { if (smartPlayer != otherPlayer) { otherPlayer.sendInfoMessage("%s%s left the %s queue.", smartPlayer.getFormattedName(), ChatColor.YELLOW, wasInGameType.getPrefix()); otherPlayer.emptyQueue(); otherPlayer.updateScoreboard(); } } } this.onQueueChange(); } } public void removePlayer(SmartPlayer smartPlayer) { this.remainingPlayersToJoin.removePlayer(smartPlayer); } public void printQueue(CommandSender commandSender) { ComponentBuilder component = new ComponentBuilder("Queue").append("\n"); component.append("----------------"); commandSender.sendMessage(component.getResult()); component = new ComponentBuilder(); for (PlayerGroup playerGroup : this.remainingPlayersToJoin.allPlayerGroups) { List<String> playerNames = new ArrayList<>(); for (SmartPlayer player : playerGroup.players) { playerNames.add(player.getName()); } component.append("\n").append(playerGroup.getType().getFullPrettyName()).append(" - ").append(playerNames); commandSender.sendMessage(component.getResult()); component = new ComponentBuilder(); } component.append("\n").append("----------------"); commandSender.sendMessage(component.getResult()); } public synchronized void onQueueChange() { this.remainingPlayersToJoin.removeNullPlayerGroups(); for (PlayerGroup allPlayerGroup : this.remainingPlayersToJoin.allPlayerGroups) { for (SmartPlayer player : allPlayerGroup.players) { player.updateScoreboard(); } } Main.broadcastPublicQueues(); Main.schedule(Main::broadcastPublicQueues, 2); } }