From 416749144d6f27c0de9505f1e82d6b7e6e0cf8bb Mon Sep 17 00:00:00 2001 From: Pablete1234 Date: Sat, 5 Nov 2022 03:23:02 +0100 Subject: [PATCH 1/3] Cleanup & fixup many, many cloud framework issues Signed-off-by: Pablete1234 --- .../tc/oc/pgm/api/setting/SettingKey.java | 11 +- .../java/tc/oc/pgm/command/ClassCommand.java | 18 +- .../tc/oc/pgm/command/FreeForAllCommand.java | 24 +- .../tc/oc/pgm/command/InventoryCommand.java | 8 +- .../java/tc/oc/pgm/command/JoinCommand.java | 14 +- .../java/tc/oc/pgm/command/MapCommand.java | 8 +- .../java/tc/oc/pgm/command/MapDevCommand.java | 56 ++++- .../tc/oc/pgm/command/MapPoolCommand.java | 230 +++++++++++++----- .../java/tc/oc/pgm/command/ModeCommand.java | 167 +++++-------- .../tc/oc/pgm/command/ProximityCommand.java | 6 +- .../tc/oc/pgm/command/SettingCommand.java | 8 +- .../java/tc/oc/pgm/command/StartCommand.java | 7 +- .../java/tc/oc/pgm/command/StatsCommand.java | 17 +- .../java/tc/oc/pgm/command/TeamCommand.java | 4 +- .../tc/oc/pgm/command/TimeLimitCommand.java | 3 +- .../command/injectors/MapPollProvider.java | 33 +++ .../injectors/MapPoolManagerProvider.java | 25 ++ .../MatchModuleInjectionService.java | 41 ++++ .../injectors/MatchObjectProvider.java | 33 +++ .../pgm/command/injectors/MatchProvider.java | 18 +- .../injectors/TeamMatchModuleProvider.java | 20 ++ .../command/injectors/TeamModuleInjector.java | 29 --- .../tc/oc/pgm/command/parsers/EnumParser.java | 103 ++++++++ .../oc/pgm/command/parsers/MapInfoParser.java | 10 +- .../oc/pgm/command/parsers/MapPoolParser.java | 29 ++- .../command/parsers/MatchObjectParser.java | 94 +++++++ .../command/parsers/MatchPlayerParser.java | 16 +- .../tc/oc/pgm/command/parsers/ModeParser.java | 25 ++ .../oc/pgm/command/parsers/PartyParser.java | 18 +- .../command/parsers/PlayerClassParser.java | 54 +--- .../pgm/command/parsers/RotationParser.java | 32 +++ .../pgm/command/parsers/SettingKeyParser.java | 56 ----- .../command/parsers/SettingValueParser.java | 57 ++--- .../tc/oc/pgm/command/parsers/TeamParser.java | 58 +---- .../oc/pgm/command/parsers/TeamsParser.java | 19 +- .../parsers/VictoryConditionParser.java | 8 +- .../tc/oc/pgm/command/util/CommandGraph.java | 84 ++++--- .../tc/oc/pgm/command/util/CommandKeys.java | 26 ++ .../tc/oc/pgm/command/util/CommandUtils.java | 14 ++ .../oc/pgm/command/util/ParserConstants.java | 1 + .../SelfIdentifyingFeatureDefinition.java | 7 +- core/src/main/java/tc/oc/pgm/modes/Mode.java | 12 + .../pgm/modes/ObjectiveModesMatchModule.java | 12 +- .../tc/oc/pgm/modes/ObjectiveModesModule.java | 30 ++- .../tc/oc/pgm/rotation/MapPoolManager.java | 12 +- .../pgm/rotation/pools/DisabledMapPool.java | 2 +- .../tc/oc/pgm/rotation/pools/MapPool.java | 27 +- .../tc/oc/pgm/rotation/pools/MapPoolType.java | 58 +++++ .../oc/pgm/rotation/pools/RandomMapPool.java | 5 +- .../tc/oc/pgm/rotation/pools/Rotation.java | 5 +- .../tc/oc/pgm/rotation/pools/VotingPool.java | 5 +- .../src/main/java/tc/oc/pgm/util/Players.java | 6 +- .../util/PrettyPaginatedComponentResults.java | 21 +- pom.xml | 15 +- .../main/i18n/templates/command.properties | 4 + util/src/main/i18n/templates/misc.properties | 4 + .../src/main/java/tc/oc/pgm/util/Aliased.java | 3 + .../main/java/tc/oc/pgm/util/StringUtils.java | 57 ++++- .../tc/oc/pgm/util/text/TextException.java | 2 +- 59 files changed, 1166 insertions(+), 605 deletions(-) create mode 100644 core/src/main/java/tc/oc/pgm/command/injectors/MapPollProvider.java create mode 100644 core/src/main/java/tc/oc/pgm/command/injectors/MapPoolManagerProvider.java create mode 100644 core/src/main/java/tc/oc/pgm/command/injectors/MatchModuleInjectionService.java create mode 100644 core/src/main/java/tc/oc/pgm/command/injectors/MatchObjectProvider.java create mode 100644 core/src/main/java/tc/oc/pgm/command/injectors/TeamMatchModuleProvider.java delete mode 100644 core/src/main/java/tc/oc/pgm/command/injectors/TeamModuleInjector.java create mode 100644 core/src/main/java/tc/oc/pgm/command/parsers/EnumParser.java create mode 100644 core/src/main/java/tc/oc/pgm/command/parsers/MatchObjectParser.java create mode 100644 core/src/main/java/tc/oc/pgm/command/parsers/ModeParser.java create mode 100644 core/src/main/java/tc/oc/pgm/command/parsers/RotationParser.java delete mode 100644 core/src/main/java/tc/oc/pgm/command/parsers/SettingKeyParser.java create mode 100644 core/src/main/java/tc/oc/pgm/command/util/CommandKeys.java create mode 100644 core/src/main/java/tc/oc/pgm/command/util/CommandUtils.java create mode 100644 core/src/main/java/tc/oc/pgm/rotation/pools/MapPoolType.java create mode 100644 util/src/main/java/tc/oc/pgm/util/Aliased.java diff --git a/core/src/main/java/tc/oc/pgm/api/setting/SettingKey.java b/core/src/main/java/tc/oc/pgm/api/setting/SettingKey.java index 21bce58ff5..9f3a556278 100644 --- a/core/src/main/java/tc/oc/pgm/api/setting/SettingKey.java +++ b/core/src/main/java/tc/oc/pgm/api/setting/SettingKey.java @@ -5,17 +5,20 @@ import com.google.common.collect.ImmutableList; import java.util.Arrays; import java.util.Collections; +import java.util.Iterator; import java.util.List; import org.bukkit.Material; +import org.jetbrains.annotations.NotNull; import tc.oc.pgm.api.player.MatchPlayer; import tc.oc.pgm.modules.PlayerTimeMatchModule; +import tc.oc.pgm.util.Aliased; /** * A toggleable setting with various possible {@link SettingValue}s. * * @see SettingValue */ -public enum SettingKey { +public enum SettingKey implements Aliased { CHAT( "chat", Material.SIGN, @@ -106,6 +109,12 @@ public List getAliases() { return aliases; } + @NotNull + @Override + public Iterator iterator() { + return aliases.iterator(); + } + /** * Get a list of the possible {@link SettingValue}s. * diff --git a/core/src/main/java/tc/oc/pgm/command/ClassCommand.java b/core/src/main/java/tc/oc/pgm/command/ClassCommand.java index fc80fa1ac5..e61211fd6c 100644 --- a/core/src/main/java/tc/oc/pgm/command/ClassCommand.java +++ b/core/src/main/java/tc/oc/pgm/command/ClassCommand.java @@ -3,16 +3,14 @@ import static net.kyori.adventure.text.Component.space; import static net.kyori.adventure.text.Component.text; import static net.kyori.adventure.text.Component.translatable; -import static tc.oc.pgm.util.text.TextException.exception; import cloud.commandframework.annotations.Argument; import cloud.commandframework.annotations.CommandDescription; import cloud.commandframework.annotations.CommandMethod; -import cloud.commandframework.annotations.specifier.FlagYielding; +import cloud.commandframework.annotations.specifier.Greedy; import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextDecoration; -import tc.oc.pgm.api.match.Match; import tc.oc.pgm.api.player.MatchPlayer; import tc.oc.pgm.classes.ClassMatchModule; import tc.oc.pgm.classes.PlayerClass; @@ -23,8 +21,9 @@ public final class ClassCommand { @CommandMethod("class|selectclass|c|cl [class]") @CommandDescription("Select your class") public void classSelect( - Match match, MatchPlayer player, @Argument("class") @FlagYielding PlayerClass newClass) { - final ClassMatchModule classes = getClasses(match); + ClassMatchModule classes, + MatchPlayer player, + @Argument("class") @Greedy PlayerClass newClass) { final PlayerClass currentClass = classes.getSelectedClass(player.getId()); if (newClass == null) { @@ -49,8 +48,7 @@ public void classSelect( @CommandMethod("classlist|classes|listclasses|cls") @CommandDescription("List all available classes") - public void classList(Match match, MatchPlayer player) { - final ClassMatchModule classes = getClasses(match); + public void classList(ClassMatchModule classes, MatchPlayer player) { final PlayerClass currentClass = classes.getSelectedClass(player.getId()); player.sendMessage( @@ -83,10 +81,4 @@ public void classList(Match match, MatchPlayer player) { player.sendMessage(result.build()); } } - - private ClassMatchModule getClasses(Match match) { - final ClassMatchModule classes = match.getModule(ClassMatchModule.class); - if (classes == null) throw exception("match.class.notEnabled"); - return classes; - } } diff --git a/core/src/main/java/tc/oc/pgm/command/FreeForAllCommand.java b/core/src/main/java/tc/oc/pgm/command/FreeForAllCommand.java index 56dbd81a2c..45437703d9 100644 --- a/core/src/main/java/tc/oc/pgm/command/FreeForAllCommand.java +++ b/core/src/main/java/tc/oc/pgm/command/FreeForAllCommand.java @@ -2,7 +2,6 @@ import static net.kyori.adventure.text.Component.text; import static net.kyori.adventure.text.Component.translatable; -import static tc.oc.pgm.util.text.TextException.exception; import cloud.commandframework.annotations.Argument; import cloud.commandframework.annotations.CommandDescription; @@ -11,7 +10,6 @@ import com.google.common.collect.Range; import net.kyori.adventure.text.format.NamedTextColor; import tc.oc.pgm.api.Permissions; -import tc.oc.pgm.api.match.Match; import tc.oc.pgm.ffa.FreeForAllMatchModule; import tc.oc.pgm.util.Audience; import tc.oc.pgm.util.text.TextParser; @@ -22,8 +20,8 @@ public final class FreeForAllCommand { @CommandMethod("min ") @CommandDescription("Set the min players") @CommandPermission(Permissions.RESIZE) - public void min(Audience audience, Match match, @Argument("min-players") int minPlayers) { - final FreeForAllMatchModule ffa = getFfa(match); + public void min( + Audience audience, FreeForAllMatchModule ffa, @Argument("min-players") int minPlayers) { TextParser.assertInRange(minPlayers, Range.atLeast(0)); ffa.setMinPlayers(minPlayers); @@ -33,8 +31,7 @@ public void min(Audience audience, Match match, @Argument("min-players") int min @CommandMethod("min reset") @CommandDescription("Reset the min players") @CommandPermission(Permissions.RESIZE) - public void min(Audience audience, Match match) { - final FreeForAllMatchModule ffa = getFfa(match); + public void min(Audience audience, FreeForAllMatchModule ffa) { ffa.setMinPlayers(null); sendResizedMessage(audience, "min", ffa.getMinPlayers()); } @@ -44,11 +41,9 @@ public void min(Audience audience, Match match) { @CommandPermission(Permissions.RESIZE) public void max( Audience audience, - Match match, + FreeForAllMatchModule ffa, @Argument("max-players") int maxPlayers, @Argument("max-overfill") Integer maxOverfill) { - final FreeForAllMatchModule ffa = getFfa(match); - TextParser.assertInRange(maxPlayers, Range.atLeast(ffa.getMinPlayers())); if (maxOverfill == null) maxOverfill = (int) Math.ceil(1.25 * maxPlayers); @@ -62,8 +57,7 @@ public void max( @CommandMethod("max reset") @CommandDescription("Reset the max players") @CommandPermission(Permissions.RESIZE) - public void max(Audience audience, Match match) { - final FreeForAllMatchModule ffa = getFfa(match); + public void max(Audience audience, FreeForAllMatchModule ffa) { ffa.setMaxPlayers(null, null); sendResizedMessage(audience, "max", ffa.getMaxPlayers()); } @@ -75,12 +69,4 @@ private void sendResizedMessage(Audience audience, String type, int value) { translatable("match.info.players", NamedTextColor.YELLOW), text(value, NamedTextColor.AQUA))); } - - private FreeForAllMatchModule getFfa(Match match) { - final FreeForAllMatchModule ffa = match.getModule(FreeForAllMatchModule.class); - if (ffa == null) { - throw exception("command.moduleNotFound", text("free-for-all")); - } - return ffa; - } } diff --git a/core/src/main/java/tc/oc/pgm/command/InventoryCommand.java b/core/src/main/java/tc/oc/pgm/command/InventoryCommand.java index 577829211a..6687ddec6b 100644 --- a/core/src/main/java/tc/oc/pgm/command/InventoryCommand.java +++ b/core/src/main/java/tc/oc/pgm/command/InventoryCommand.java @@ -5,16 +5,16 @@ import cloud.commandframework.annotations.Argument; import cloud.commandframework.annotations.CommandDescription; import cloud.commandframework.annotations.CommandMethod; -import tc.oc.pgm.api.match.Match; import tc.oc.pgm.api.player.MatchPlayer; import tc.oc.pgm.inventory.ViewInventoryMatchModule; public final class InventoryCommand { @CommandMethod("inventory|inv|vi ") @CommandDescription("View a player's inventory") - public void inventory(Match match, MatchPlayer viewer, @Argument("player") MatchPlayer holder) { - final ViewInventoryMatchModule inventories = match.needModule(ViewInventoryMatchModule.class); - + public void inventory( + ViewInventoryMatchModule inventories, + MatchPlayer viewer, + @Argument("player") MatchPlayer holder) { if (inventories.canPreviewInventory(viewer, holder)) { inventories.previewInventory(viewer.getBukkit(), holder.getInventory()); } else { diff --git a/core/src/main/java/tc/oc/pgm/command/JoinCommand.java b/core/src/main/java/tc/oc/pgm/command/JoinCommand.java index cca3e71d5e..6dba46d314 100644 --- a/core/src/main/java/tc/oc/pgm/command/JoinCommand.java +++ b/core/src/main/java/tc/oc/pgm/command/JoinCommand.java @@ -7,7 +7,6 @@ import cloud.commandframework.annotations.Flag; import cloud.commandframework.annotations.specifier.FlagYielding; import tc.oc.pgm.api.Permissions; -import tc.oc.pgm.api.match.Match; import tc.oc.pgm.api.party.Competitor; import tc.oc.pgm.api.party.Party; import tc.oc.pgm.api.player.MatchPlayer; @@ -19,27 +18,26 @@ public final class JoinCommand { @CommandDescription("Join the match") @CommandPermission(Permissions.JOIN) public void join( - Match match, + JoinMatchModule joiner, MatchPlayer player, @Flag(value = "force", aliases = "f") boolean force, @Argument("team") @FlagYielding Party team) { if (team != null && !(team instanceof Competitor)) { - leave(player, match); + leave(joiner, player); return; } - final JoinMatchModule join = match.needModule(JoinMatchModule.class); if (force && player.getBukkit().hasPermission(Permissions.JOIN_FORCE)) { - join.forceJoin(player, (Competitor) team); + joiner.forceJoin(player, (Competitor) team); } else { - join.join(player, (Competitor) team); + joiner.join(player, (Competitor) team); } } @CommandMethod("leave|obs|spectator|spec") @CommandDescription("Leave the match") @CommandPermission(Permissions.LEAVE) - public void leave(MatchPlayer player, Match match) { - match.needModule(JoinMatchModule.class).leave(player); + public void leave(JoinMatchModule joiner, MatchPlayer player) { + joiner.leave(player); } } diff --git a/core/src/main/java/tc/oc/pgm/command/MapCommand.java b/core/src/main/java/tc/oc/pgm/command/MapCommand.java index b136b74af3..06ba4160a3 100644 --- a/core/src/main/java/tc/oc/pgm/command/MapCommand.java +++ b/core/src/main/java/tc/oc/pgm/command/MapCommand.java @@ -231,10 +231,10 @@ public void map( if (PGM.get().getMapOrder() instanceof MapPoolManager) { String mapPools = ((MapPoolManager) PGM.get().getMapOrder()) - .getMapPools().stream() - .filter(pool -> pool.getMaps().contains(map)) - .map(MapPool::getName) - .collect(Collectors.joining(", ")); + .getMapPoolStream() + .filter(pool -> pool.getMaps().contains(map)) + .map(MapPool::getName) + .collect(Collectors.joining(", ")); if (!mapPools.isEmpty()) { audience.sendMessage( text() diff --git a/core/src/main/java/tc/oc/pgm/command/MapDevCommand.java b/core/src/main/java/tc/oc/pgm/command/MapDevCommand.java index ea1e794f27..2e77cf3835 100644 --- a/core/src/main/java/tc/oc/pgm/command/MapDevCommand.java +++ b/core/src/main/java/tc/oc/pgm/command/MapDevCommand.java @@ -1,29 +1,69 @@ package tc.oc.pgm.command; import static net.kyori.adventure.text.Component.text; +import static tc.oc.pgm.command.util.ParserConstants.CURRENT; import cloud.commandframework.annotations.Argument; import cloud.commandframework.annotations.CommandDescription; import cloud.commandframework.annotations.CommandMethod; import cloud.commandframework.annotations.CommandPermission; -import org.jetbrains.annotations.NotNull; +import cloud.commandframework.annotations.Flag; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.command.CommandSender; import tc.oc.pgm.api.Permissions; import tc.oc.pgm.api.match.Match; import tc.oc.pgm.api.player.MatchPlayer; +import tc.oc.pgm.util.Audience; +import tc.oc.pgm.util.PrettyPaginatedComponentResults; +import tc.oc.pgm.util.text.TextFormatter; import tc.oc.pgm.variables.Variable; public class MapDevCommand { - @CommandMethod("variables [target]") + @CommandMethod("variables [target] [page]") @CommandDescription("Inspect variables for a player") @CommandPermission(Permissions.DEBUG) public void showVariables( - Match match, @NotNull MatchPlayer sender, @Argument("target") MatchPlayer target) { - MatchPlayer filterable = target == null ? sender : target; + Audience audience, + CommandSender sender, + Match match, + @Argument(value = "target", defaultValue = CURRENT) MatchPlayer target, + @Argument(value = "page", defaultValue = "1") int page, + @Flag(value = "query", aliases = "q") String query, + @Flag(value = "all", aliases = "a") boolean all) { - sender.sendMessage(text("Showing variables for " + filterable.getNameLegacy() + ":")); - for (Variable v : match.getFeatureContext().getAll(Variable.class)) { - sender.sendMessage(text(v.getId() + ": " + v.getValue(filterable))); - } + List> variables = + match.getFeatureContext().getAll().stream() + .filter(Variable.class::isInstance) + .map(v -> (Variable) v) + .filter(v -> query == null || v.getId().contains(query)) + .sorted(Comparator.comparing(Variable::getId)) + .collect(Collectors.toList()); + + int resultsPerPage = all ? variables.size() : 8; + int pages = all ? 1 : (variables.size() + resultsPerPage - 1) / resultsPerPage; + + Component title = + TextFormatter.paginate( + text("Variables for ").append(target.getName()), + page, + pages, + NamedTextColor.DARK_AQUA, + NamedTextColor.AQUA, + true); + Component header = TextFormatter.horizontalLineHeading(sender, title, NamedTextColor.BLUE); + + PrettyPaginatedComponentResults.display( + audience, + variables, + page, + resultsPerPage, + header, + (v, i) -> + text().append(text(v.getId() + ": ", NamedTextColor.AQUA), text(v.getValue(target)))); } } diff --git a/core/src/main/java/tc/oc/pgm/command/MapPoolCommand.java b/core/src/main/java/tc/oc/pgm/command/MapPoolCommand.java index cff6b08ef6..fcbc1eb21c 100644 --- a/core/src/main/java/tc/oc/pgm/command/MapPoolCommand.java +++ b/core/src/main/java/tc/oc/pgm/command/MapPoolCommand.java @@ -3,6 +3,7 @@ import static net.kyori.adventure.text.Component.empty; import static net.kyori.adventure.text.Component.text; import static net.kyori.adventure.text.Component.translatable; +import static net.kyori.adventure.text.event.HoverEvent.showText; import static tc.oc.pgm.util.text.TextException.exception; import cloud.commandframework.annotations.Argument; @@ -10,6 +11,7 @@ import cloud.commandframework.annotations.CommandMethod; import cloud.commandframework.annotations.CommandPermission; import cloud.commandframework.annotations.Flag; +import cloud.commandframework.annotations.injection.RawArgs; import cloud.commandframework.annotations.specifier.FlagYielding; import cloud.commandframework.annotations.specifier.Range; import java.text.DecimalFormat; @@ -18,25 +20,28 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import java.util.stream.Stream; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; import tc.oc.pgm.api.Permissions; import tc.oc.pgm.api.map.MapInfo; -import tc.oc.pgm.api.map.MapOrder; import tc.oc.pgm.api.match.Match; import tc.oc.pgm.api.player.MatchPlayer; import tc.oc.pgm.cycle.CycleCountdown; import tc.oc.pgm.rotation.MapPoolManager; import tc.oc.pgm.rotation.pools.MapPool; +import tc.oc.pgm.rotation.pools.MapPoolType; import tc.oc.pgm.rotation.pools.Rotation; import tc.oc.pgm.rotation.pools.VotingPool; import tc.oc.pgm.rotation.vote.MapPoll; import tc.oc.pgm.util.Audience; import tc.oc.pgm.util.PrettyPaginatedComponentResults; import tc.oc.pgm.util.named.MapNameStyle; +import tc.oc.pgm.util.text.TextException; import tc.oc.pgm.util.text.TextFormatter; public final class MapPoolCommand { @@ -46,20 +51,19 @@ public final class MapPoolCommand { @CommandMethod("pool [page]") @CommandDescription("List the maps in the map pool") public void pool( - Audience audience, - CommandSender sender, - MapOrder mapOrder, + Audience sender, + CommandSender source, + MapPoolManager poolManager, @Argument(value = "page", defaultValue = "1") @Range(min = "1") int page, + @Flag(value = "type", aliases = "t") MapPoolType type, @Flag(value = "pool", aliases = "p") MapPool mapPool, @Flag(value = "score", aliases = "s") boolean scores, @Flag(value = "chance", aliases = "c") boolean chance) { + // Default to current pool + if (mapPool == null) mapPool = poolManager.getActiveMapPool(); - if (mapPool == null) mapPool = getMapPoolManager(mapOrder).getActiveMapPool(); - - if (mapPool == null) { - audience.sendWarning(translatable("pool.noPoolMatch")); - return; - } + if (mapPool == null || (type != null && mapPool.getType() != type)) + throw exception("pool.noPoolMatch"); List maps = mapPool.getMaps(); int resultsPerPage = 8; @@ -80,7 +84,7 @@ public void pool( false); Component title = - TextFormatter.horizontalLineHeading(sender, mapPoolComponent, NamedTextColor.BLUE, 250); + TextFormatter.horizontalLineHeading(source, mapPoolComponent, NamedTextColor.BLUE, 250); VotingPool votes = (scores || chance) && mapPool instanceof VotingPool ? (VotingPool) mapPool : null; @@ -115,29 +119,27 @@ public Component format(MapInfo map, int index) { entry.append(map.getStyledName(MapNameStyle.COLOR_WITH_AUTHORS)); return entry.build(); } - }.display(audience, maps, page); + }.display(sender, maps, page); } @CommandMethod("pools [page]") @CommandDescription("List all the map pools") public void pools( - Audience audience, - CommandSender sender, - MapOrder mapOrder, + Audience sender, + CommandSender source, + MapPoolManager poolManager, @Argument(value = "page", defaultValue = "1") @Range(min = "1") int page, + @Flag(value = "type", aliases = "t") MapPoolType type, @Flag(value = "dynamic", aliases = "d") boolean dynamicOnly) { - MapPoolManager mapPoolManager = getMapPoolManager(mapOrder); + if (poolManager.getPoolSize() <= 0) throw exception("pool.noMapPools"); - List mapPools = mapPoolManager.getMapPools(); - if (mapPools.isEmpty()) { - audience.sendWarning(translatable("pool.noMapPools")); - return; - } + Stream poolStream = poolManager.getMapPoolStream(); + if (dynamicOnly) poolStream = poolStream.filter(MapPool::isDynamic); + if (type != null) poolStream = poolStream.filter(mp -> mp.getType() == type); - if (dynamicOnly) { - mapPools = mapPools.stream().filter(MapPool::isDynamic).collect(Collectors.toList()); - } + List mapPools = poolStream.collect(Collectors.toList()); + if (mapPools.isEmpty()) throw exception("pool.noPoolMatch"); int resultsPerPage = 8; int pages = (mapPools.size() + resultsPerPage - 1) / resultsPerPage; @@ -152,7 +154,7 @@ public void pools( true); Component formattedTitle = - TextFormatter.horizontalLineHeading(sender, paginated, NamedTextColor.BLUE, 250); + TextFormatter.horizontalLineHeading(source, paginated, NamedTextColor.BLUE); new PrettyPaginatedComponentResults(formattedTitle, resultsPerPage) { @Override @@ -160,7 +162,7 @@ public Component format(MapPool mapPool, int index) { Component arrow = text( "ยป ", - mapPoolManager.getActiveMapPool().getName().equals(mapPool.getName()) + poolManager.getActiveMapPool().equals(mapPool) ? NamedTextColor.GREEN : NamedTextColor.WHITE); @@ -189,33 +191,26 @@ public Component format(MapPool mapPool, int index) { .append(mapPool.isDynamic() ? players : empty()) .build(); } - }.display(audience, mapPools, page); + }.display(sender, mapPools, page); } - @CommandMethod("setpool [pool]") + @CommandMethod("setpool ") @CommandDescription("Change the map pool") @CommandPermission(Permissions.SETNEXT) public void setPool( Audience sender, CommandSender source, Match match, - MapOrder mapOrder, + MapPoolManager poolManager, @Argument("pool") MapPool newPool, - @Flag(value = "reset", aliases = "r") boolean reset, @Flag(value = "timelimit", aliases = "t") Duration timeLimit, @Flag(value = "matches", aliases = "m") Integer matchLimit) { if (!match.getCountdown().getAll(CycleCountdown.class).isEmpty()) throw exception("admin.setPool.activeCycle"); - MapPoolManager mapPoolManager = getMapPoolManager(mapOrder); - if (reset) - newPool = - mapPoolManager - .getAppropriateDynamicPool(match) - .orElseThrow(() -> exception("pool.noDynamic")); - else if (newPool == null) throw exception("pool.noPoolMatch"); + if (newPool == null) throw exception("pool.noPoolMatch"); - if (newPool.equals(mapPoolManager.getActiveMapPool())) { + if (newPool.equals(poolManager.getActiveMapPool())) { sender.sendMessage( translatable( "pool.matching", @@ -224,23 +219,40 @@ public void setPool( return; } - mapPoolManager.updateActiveMapPool( + poolManager.updateActiveMapPool( newPool, match, true, source, timeLimit, matchLimit != null ? matchLimit : 0); } + @CommandMethod("setpool reset") + @CommandDescription("Reset the pool back to appropriate default dynamic pool") + @CommandPermission(Permissions.SETNEXT) + public void resetPool( + Audience sender, + CommandSender source, + Match match, + MapPoolManager poolManager, + @Flag(value = "timelimit", aliases = "t") Duration timeLimit, + @Flag(value = "matches", aliases = "m") Integer matchLimit) { + setPool( + sender, + source, + match, + poolManager, + poolManager.getAppropriateDynamicPool(match).orElseThrow(() -> exception("pool.noDynamic")), + timeLimit, + matchLimit); + } + @CommandMethod("skip [positions]") @CommandDescription("Skip the next map") @CommandPermission(Permissions.SETNEXT) public void skip( - Audience viewer, - MapOrder mapOrder, + Audience sender, + MapPoolManager poolManager, @Argument(value = "positions", defaultValue = "1") @Range(min = "1") int positions) { - MapPool pool = getMapPoolManager(mapOrder).getActiveMapPool(); - if (!(pool instanceof Rotation)) { - viewer.sendWarning(translatable("pool.noRotation")); - return; - } + MapPool pool = poolManager.getActiveMapPool(); + if (!(pool instanceof Rotation)) throw exception("pool.noRotation"); ((Rotation) pool).advance(positions); @@ -256,19 +268,17 @@ public void skip( "pool.skip", NamedTextColor.GREEN, text(positions, NamedTextColor.AQUA))) .build(); - viewer.sendMessage(message); + sender.sendMessage(message); } @CommandMethod("votenext [map]") @CommandDescription("Vote for the next map") public void voteNext( MatchPlayer player, - CommandSender sender, - MapOrder mapOrder, + MapPoll poll, @Flag(value = "open", aliases = "o") boolean forceOpen, @Argument("map") @FlagYielding MapInfo map) { - MapPoll poll = getVotingPool(mapOrder); - boolean voteResult = poll.toggleVote(map, ((Player) sender).getUniqueId()); + boolean voteResult = poll.toggleVote(map, player.getId()); Component voteAction = translatable( voteResult ? "vote.for" : "vote.abstain", @@ -280,19 +290,115 @@ public void voteNext( @CommandMethod("votebook") @CommandDescription("Spawn a vote book") - public void voteBook(MatchPlayer player, MapOrder mapOrder) { - getVotingPool(mapOrder).sendBook(player, false); + public void voteBook(MatchPlayer player, MapPoll poll) { + poll.sendBook(player, false); + } + + // Legacy rotation command aliases + + @CommandMethod("rot [page]") + @CommandDescription("List the maps in the rotation. Use /pool to see unfiltered results.") + @RawArgs + public void rot( + Audience sender, + CommandSender source, + MapPoolManager poolManager, + @Argument(value = "page", defaultValue = "1") @Range(min = "1") int page, + @Flag(value = "score", aliases = "s") boolean scores, + @Flag(value = "chance", aliases = "c") boolean chance, + String[] rawArgs) { + wrapLegacy( + "pool", + sender, + rawArgs, + () -> { + if (poolManager.getActiveMapPool().getType() != MapPoolType.ORDERED) + throw exception("pool.noRotation"); + + pool(sender, source, poolManager, page, MapPoolType.ORDERED, null, scores, chance); + }); + } + + @CommandMethod("rots [page]") + @CommandDescription("List all the rotations. Use /pools to see unfiltered results.") + @RawArgs + public void rots( + Audience sender, + CommandSender source, + MapPoolManager poolManager, + @Argument(value = "page", defaultValue = "1") @Range(min = "1") int page, + String[] rawArgs) { + pools(sender, source, poolManager, page, MapPoolType.ORDERED, false); + // Always follow-up, as they're filtered results that may not error out + sender.sendMessage(alternativeUsage(rawArgs, "pools")); + } + + @CommandMethod("setrot ") + @CommandDescription("Set a rotation as current pool. Use /setpool to set other types of pools.") + @CommandPermission(Permissions.SETNEXT) + @RawArgs + public void setRot( + Audience sender, + CommandSender source, + Match match, + MapPoolManager poolManager, + @Argument("rotation") Rotation rotation, + @Flag(value = "timelimit", aliases = "t") Duration timeLimit, + @Flag(value = "matches", aliases = "m") Integer matchLimit, + String[] rawArgs) { + wrapLegacy( + "setpool", + sender, + rawArgs, + () -> setPool(sender, source, match, poolManager, rotation, timeLimit, matchLimit)); + } + + @CommandMethod("setrot reset") + @CommandDescription( + "Reset the rotation to default. Use /setpool to reset to other types of pools.") + @CommandPermission(Permissions.SETNEXT) + @RawArgs + public void resetRot( + Audience sender, + CommandSender source, + Match match, + MapPoolManager poolManager, + @Flag(value = "timelimit", aliases = "t") Duration timeLimit, + @Flag(value = "matches", aliases = "m") Integer matchLimit, + String[] rawArgs) { + + MapPool resetRot = + poolManager.getAppropriateDynamicPool(match).orElseThrow(() -> exception("pool.noDynamic")); + + wrapLegacy( + "setpool", + sender, + rawArgs, + () -> { + if (resetRot.getType() != MapPoolType.ORDERED) throw exception("pool.noRotation"); + setPool(sender, source, match, poolManager, resetRot, timeLimit, matchLimit); + }); } - private static MapPoll getVotingPool(MapOrder mapOrder) { - MapPool pool = getMapPoolManager(mapOrder).getActiveMapPool(); - MapPoll poll = pool instanceof VotingPool ? ((VotingPool) pool).getCurrentPoll() : null; - if (poll == null) throw exception("vote.noVote"); - return poll; + private void wrapLegacy(String replace, Audience sender, String[] rawArgs, Runnable task) { + try { + task.run(); + } catch (TextException e) { + sender.sendWarning(e.componentMessage()); + throw alternativeUsage(rawArgs, replace); + } } - public static MapPoolManager getMapPoolManager(MapOrder mapOrder) { - if (mapOrder instanceof MapPoolManager) return (MapPoolManager) mapOrder; - throw exception("pool.mapPoolsDisabled"); + private TextException alternativeUsage(String[] rawArgs, String replace) { + rawArgs[0] = "/" + replace; + String altCommand = String.join(" ", rawArgs); + Component cmd = + text(altCommand).color(NamedTextColor.YELLOW).decorate(TextDecoration.UNDERLINED); + + return exception( + "command.alternativeUsage", + cmd.hoverEvent( + showText(translatable("command.clickToRun", cmd).color(NamedTextColor.GREEN))) + .clickEvent(ClickEvent.runCommand(altCommand))); } } diff --git a/core/src/main/java/tc/oc/pgm/command/ModeCommand.java b/core/src/main/java/tc/oc/pgm/command/ModeCommand.java index 15e42c01c5..c2059538bb 100644 --- a/core/src/main/java/tc/oc/pgm/command/ModeCommand.java +++ b/core/src/main/java/tc/oc/pgm/command/ModeCommand.java @@ -20,6 +20,7 @@ import tc.oc.pgm.api.Permissions; import tc.oc.pgm.api.match.Match; import tc.oc.pgm.countdowns.CountdownContext; +import tc.oc.pgm.modes.Mode; import tc.oc.pgm.modes.ModeChangeCountdown; import tc.oc.pgm.modes.ModesPaginatedResult; import tc.oc.pgm.modes.ObjectiveModesMatchModule; @@ -31,70 +32,68 @@ public final class ModeCommand { @CommandMethod("next") @CommandDescription("Show the next objective mode") - public void next(Audience audience, Match match) { - ObjectiveModesMatchModule modes = getModes(match); + public void next(Audience audience, ObjectiveModesMatchModule modes) { + List countdowns = modes.getActiveCountdowns(); - if (modes == null) { - throwNoResults(); + if (countdowns.isEmpty()) throwNoResults(); + + TextComponent.Builder builder = + text().append(translatable("command.nextMode", NamedTextColor.DARK_PURPLE).append(space())); + + ModeChangeCountdown next = countdowns.get(0); + Duration timeLeft = modes.getCountdown().getTimeLeft(next); + + if (timeLeft == null) { + builder.append(text(next.getMode().getPreformattedMaterialName(), NamedTextColor.GOLD)); + } else if (timeLeft.getSeconds() >= 0) { + builder.append( + text( + WordUtils.capitalize(next.getMode().getPreformattedMaterialName()), + NamedTextColor.GOLD) + .append(space()) + .append(text("(", NamedTextColor.AQUA)) + .append( + new ModesPaginatedResult(modes) + .formatSingleCountdown(next) + .color(NamedTextColor.AQUA)) + .append(text(")", NamedTextColor.AQUA))); } else { - List countdowns = modes.getActiveCountdowns(); - - if (countdowns.isEmpty()) { - throwNoResults(); - } else { - TextComponent.Builder builder = - text() - .append( - translatable("command.nextMode", NamedTextColor.DARK_PURPLE).append(space())); - - ModeChangeCountdown next = countdowns.get(0); - Duration timeLeft = modes.getCountdown().getTimeLeft(next); - - if (timeLeft == null) { - builder.append(text(next.getMode().getPreformattedMaterialName(), NamedTextColor.GOLD)); - } else if (timeLeft.getSeconds() >= 0) { - builder.append( - text( - WordUtils.capitalize(next.getMode().getPreformattedMaterialName()), - NamedTextColor.GOLD) - .append(space()) - .append(text("(", NamedTextColor.AQUA)) - .append( - new ModesPaginatedResult(modes) - .formatSingleCountdown(next) - .color(NamedTextColor.AQUA)) - .append(text(")", NamedTextColor.AQUA))); - } else { - throwNoResults(); - } - - audience.sendMessage(builder.build()); - } + throwNoResults(); } + + audience.sendMessage(builder.build()); } @CommandMethod("list|page [page]") @CommandDescription("List all objective modes") public void list( Audience audience, - Match match, + ObjectiveModesMatchModule modes, @Argument(value = "page", defaultValue = "1") @Range(min = "1") int page) { - showList(page, audience, getModes(match)); + List modeList = modes.getSortedCountdowns(true); + int resultsPerPage = 8; + int pages = (modeList.size() + resultsPerPage - 1) / resultsPerPage; + Component header = + TextFormatter.paginate( + translatable("command.monumentModes"), + page, + pages, + NamedTextColor.DARK_AQUA, + NamedTextColor.AQUA, + true); + + new ModesPaginatedResult(header, resultsPerPage, modes).display(audience, modeList, page); } @CommandMethod("push