diff --git a/core/pom.xml b/core/pom.xml index 56c0aa0051..576cf85da7 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -35,6 +35,20 @@ + + org.apache.maven.plugins + maven-compiler-plugin + + + + cloud.commandframework + cloud-annotations + 1.7.1 + + + + + org.apache.maven.plugins maven-shade-plugin @@ -47,7 +61,8 @@ tc.oc.pgm:*:* org.jdom:jdom2:* net.kyori:*:* - app.ashcon.intake:intake-*:* + cloud.commandframework:cloud-*:* + me.lucko:commodore:* fr.mrmicky:*:* org.eclipse.jgit:org.eclipse.jgit:* org.slf4j:slf4j-api:* @@ -65,8 +80,12 @@ - app.ashcon.intake - tc.oc.pgm.lib.app.ashcon.intake + cloud.commandframework + tc.oc.pgm.lib.cloud.commandframework + + + me.lucko + tc.oc.pgm.lib.me.lucko fr.mrmicky diff --git a/core/src/main/java/tc/oc/pgm/PGMPlugin.java b/core/src/main/java/tc/oc/pgm/PGMPlugin.java index ac0eb9fa85..52fe2f39b5 100644 --- a/core/src/main/java/tc/oc/pgm/PGMPlugin.java +++ b/core/src/main/java/tc/oc/pgm/PGMPlugin.java @@ -42,15 +42,12 @@ import tc.oc.pgm.api.module.Module; import tc.oc.pgm.api.module.exception.ModuleLoadException; import tc.oc.pgm.api.player.VanishManager; -import tc.oc.pgm.command.graph.CommandExecutor; -import tc.oc.pgm.command.graph.CommandGraph; -import tc.oc.pgm.community.command.CommunityCommandGraph; +import tc.oc.pgm.command.util.CommandGraph; import tc.oc.pgm.community.features.VanishManagerImpl; import tc.oc.pgm.db.CacheDatastore; import tc.oc.pgm.db.SQLDatastore; import tc.oc.pgm.listeners.AntiGriefListener; import tc.oc.pgm.listeners.BlockTransformListener; -import tc.oc.pgm.listeners.ChatDispatcher; import tc.oc.pgm.listeners.FormattingListener; import tc.oc.pgm.listeners.MatchAnnouncer; import tc.oc.pgm.listeners.MotdListener; @@ -338,13 +335,11 @@ public InventoryManager getInventoryManager() { } private void registerCommands() { - final CommandGraph graph = - config.isCommunityMode() ? new CommunityCommandGraph() : new CommandGraph(); - - graph.register(vanishManager); - graph.register(ChatDispatcher.get()); - - new CommandExecutor(this, graph).register(); + try { + new CommandGraph(this); + } catch (Exception e) { + getLogger().log(Level.SEVERE, "Exception registering commands", e); + } } private void registerEvents(Object listener) { diff --git a/core/src/main/java/tc/oc/pgm/api/integration/Integration.java b/core/src/main/java/tc/oc/pgm/api/integration/Integration.java new file mode 100644 index 0000000000..ce1d2918d6 --- /dev/null +++ b/core/src/main/java/tc/oc/pgm/api/integration/Integration.java @@ -0,0 +1,21 @@ +package tc.oc.pgm.api.integration; + +import org.bukkit.entity.Player; +import org.jetbrains.annotations.Nullable; +import tc.oc.pgm.api.PGM; + +public interface Integration { + + public static boolean isFriend(Player a, Player b) { + return false; + } + + @Nullable + public static String getNick(Player player) { + return null; + } + + public static boolean isVanished(Player player) { + return PGM.get().getVanishManager().isVanished(player.getUniqueId()); + } +} diff --git a/core/src/main/java/tc/oc/pgm/api/map/MapInfo.java b/core/src/main/java/tc/oc/pgm/api/map/MapInfo.java index 1e94033349..711738a591 100644 --- a/core/src/main/java/tc/oc/pgm/api/map/MapInfo.java +++ b/core/src/main/java/tc/oc/pgm/api/map/MapInfo.java @@ -1,6 +1,5 @@ package tc.oc.pgm.api.map; -import java.text.Normalizer; import java.time.LocalDate; import java.util.Collection; import net.kyori.adventure.text.Component; @@ -38,10 +37,17 @@ public interface MapInfo extends Comparable, Cloneable { /** * Get a unique, human-readable name for the map. * - * @return A name, alphanumeric with spaces are allowed. + * @return A name, alphanumeric with spaces allowed. */ String getName(); + /** + * Get the maps' name, but normalized to standard english characters and lower case. + * + * @return The map's name, lowercase with spaces allowed. + */ + String getNormalizedName(); + /** * Gets a styled map name. * @@ -161,12 +167,4 @@ default String getStyledNameLegacy(MapNameStyle style, @Nullable CommandSender s default int compareTo(MapInfo o) { return getId().compareTo(o.getId()); } - - static String normalizeName(@Nullable String idOrName) { - return idOrName == null - ? "" - : Normalizer.normalize(idOrName, Normalizer.Form.NFD) - .replaceAll("[^A-Za-z0-9]", "") - .toLowerCase(); - } } diff --git a/core/src/main/java/tc/oc/pgm/api/map/MapLibrary.java b/core/src/main/java/tc/oc/pgm/api/map/MapLibrary.java index d645f38b28..c0df467f69 100644 --- a/core/src/main/java/tc/oc/pgm/api/map/MapLibrary.java +++ b/core/src/main/java/tc/oc/pgm/api/map/MapLibrary.java @@ -2,6 +2,7 @@ import java.util.Iterator; import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; import org.jetbrains.annotations.Nullable; import tc.oc.pgm.api.map.includes.MapIncludeProcessor; @@ -17,6 +18,13 @@ public interface MapLibrary { @Nullable MapInfo getMap(String idOrName); + /** + * Get all {@link MapInfo}s matching the query. + * + * @return A stream of {@link MapInfo}s. + */ + Stream getMaps(String query); + /** * Get all {@link MapInfo}s, without any duplicate ids or names. * diff --git a/core/src/main/java/tc/oc/pgm/api/region/Region.java b/core/src/main/java/tc/oc/pgm/api/region/Region.java index 95e80e6113..9a2c54b356 100644 --- a/core/src/main/java/tc/oc/pgm/api/region/Region.java +++ b/core/src/main/java/tc/oc/pgm/api/region/Region.java @@ -5,11 +5,8 @@ import java.util.Collections; import java.util.Iterator; import java.util.Random; -import java.util.Spliterator; -import java.util.Spliterators; import java.util.stream.IntStream; import java.util.stream.Stream; -import java.util.stream.StreamSupport; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; @@ -21,6 +18,7 @@ import tc.oc.pgm.api.filter.query.LocationQuery; import tc.oc.pgm.filters.matcher.TypedFilter; import tc.oc.pgm.regions.Bounds; +import tc.oc.pgm.util.StreamUtils; import tc.oc.pgm.util.block.BlockVectors; import tc.oc.pgm.util.chunk.ChunkVector; import tc.oc.pgm.util.event.PlayerCoarseMoveEvent; @@ -142,8 +140,7 @@ default Iterable getBlockVectors() { } default Stream getBlockPositions() { - return StreamSupport.stream( - Spliterators.spliterator(getBlockVectorIterator(), 0, Spliterator.ORDERED), false); + return StreamUtils.of(getBlockVectorIterator()); } default Iterable getBlocks(World world) { 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 b0939725fb..21bce58ff5 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 @@ -109,7 +109,7 @@ public List getAliases() { /** * Get a list of the possible {@link SettingValue}s. * - * @return A array of {@link SettingValue}s, sorted by defined order. + * @return An array of {@link SettingValue}s, sorted by defined order. */ public SettingValue[] getPossibleValues() { return values; diff --git a/core/src/main/java/tc/oc/pgm/api/setting/SettingValue.java b/core/src/main/java/tc/oc/pgm/api/setting/SettingValue.java index fa67dd6e38..41618fa7da 100644 --- a/core/src/main/java/tc/oc/pgm/api/setting/SettingValue.java +++ b/core/src/main/java/tc/oc/pgm/api/setting/SettingValue.java @@ -2,12 +2,7 @@ import static tc.oc.pgm.util.Assert.assertNotNull; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; import org.bukkit.DyeColor; -import org.jetbrains.annotations.Nullable; -import tc.oc.pgm.util.StringUtils; /** * Values of a particular {@link SettingKey}, a toggleable setting. @@ -83,7 +78,7 @@ public String getName() { /** * Get {@link DyeColor} related to this setting value . * - * @see {@link SettingMenu} for usage. + * @see tc.oc.pgm.settings.SettingsMenu for usage. * @return {@link DyeColor} for this setting value. */ public DyeColor getColor() { @@ -94,18 +89,4 @@ public DyeColor getColor() { public String toString() { return getName(); } - - public static SettingValue search(SettingKey key, @Nullable String query) { - final SettingValue value = - StringUtils.bestFuzzyMatch( - query, - Stream.of(SettingValue.values()) - .filter(entry -> entry.getKey().equals(key)) - .collect(Collectors.toMap(SettingValue::getName, Function.identity())), - 0.6); - if (value == null) { - return key.getDefaultValue(); - } - return value; - } } diff --git a/core/src/main/java/tc/oc/pgm/classes/ClassMatchModule.java b/core/src/main/java/tc/oc/pgm/classes/ClassMatchModule.java index 70e17f53cd..0c8e7adf9d 100644 --- a/core/src/main/java/tc/oc/pgm/classes/ClassMatchModule.java +++ b/core/src/main/java/tc/oc/pgm/classes/ClassMatchModule.java @@ -2,6 +2,7 @@ import static tc.oc.pgm.util.Assert.assertNotNull; import static tc.oc.pgm.util.Assert.assertTrue; +import static tc.oc.pgm.util.text.TextException.exception; import com.google.common.collect.Maps; import com.google.common.collect.Sets; @@ -158,7 +159,7 @@ public boolean getCanChangeClass(UUID userId) { * @param userId player to set the class * @param cls class to set * @return old class or default if none selected - * @throws IllegalStateException if the player may not change classes + * @throws tc.oc.pgm.util.text.TextException if the player may not change classes */ public PlayerClass setPlayerClass(UUID userId, PlayerClass cls) { assertNotNull(userId, "player id"); @@ -166,7 +167,7 @@ public PlayerClass setPlayerClass(UUID userId, PlayerClass cls) { assertTrue(this.classes.containsValue(cls), "class is not valid for this match"); if (!this.getCanChangeClass(userId)) { - throw new IllegalStateException("cannot change sticky class"); + throw exception("match.class.sticky"); } PlayerClass oldClass = this.selectedClasses.put(userId, cls); diff --git a/core/src/main/java/tc/oc/pgm/command/AdminCommand.java b/core/src/main/java/tc/oc/pgm/command/AdminCommand.java index 3bd449b334..d33ab5de77 100644 --- a/core/src/main/java/tc/oc/pgm/command/AdminCommand.java +++ b/core/src/main/java/tc/oc/pgm/command/AdminCommand.java @@ -1,27 +1,26 @@ package tc.oc.pgm.command; -import app.ashcon.intake.Command; -import app.ashcon.intake.parametric.annotation.Switch; +import cloud.commandframework.annotations.CommandDescription; +import cloud.commandframework.annotations.CommandMethod; +import cloud.commandframework.annotations.CommandPermission; +import cloud.commandframework.annotations.Flag; import tc.oc.pgm.api.PGM; import tc.oc.pgm.api.Permissions; import tc.oc.pgm.api.map.MapLibrary; public final class AdminCommand { - @Command( - aliases = {"pgm"}, - desc = "Reload the config", - perms = Permissions.RELOAD) + @CommandMethod("pgm") + @CommandDescription("Reload the config") + @CommandPermission(Permissions.RELOAD) public void pgm() { PGM.get().reloadConfig(); } - @Command( - aliases = {"loadnewmaps", "findnewmaps", "newmaps"}, - desc = "Load new maps", - flags = "f", - perms = Permissions.RELOAD) - public void loadNewMaps(MapLibrary library, @Switch('f') boolean force) { + @CommandMethod("loadnewmaps|findnewmaps|newmaps") + @CommandDescription("Reload the config") + @CommandPermission(Permissions.RELOAD) + public void loadNewMaps(MapLibrary library, @Flag(value = "force", aliases = "f") boolean force) { library.loadNewMaps(force); } } diff --git a/core/src/main/java/tc/oc/pgm/command/CancelCommand.java b/core/src/main/java/tc/oc/pgm/command/CancelCommand.java index 4c34f19fbb..66dc659ec5 100644 --- a/core/src/main/java/tc/oc/pgm/command/CancelCommand.java +++ b/core/src/main/java/tc/oc/pgm/command/CancelCommand.java @@ -2,7 +2,9 @@ import static net.kyori.adventure.text.Component.translatable; -import app.ashcon.intake.Command; +import cloud.commandframework.annotations.CommandDescription; +import cloud.commandframework.annotations.CommandMethod; +import cloud.commandframework.annotations.CommandPermission; import net.kyori.adventure.text.format.NamedTextColor; import tc.oc.pgm.api.Permissions; import tc.oc.pgm.api.match.Match; @@ -15,10 +17,9 @@ public final class CancelCommand { - @Command( - aliases = {"cancel", "cancelrestart", "cr"}, - desc = "Cancels all countdowns", - perms = Permissions.STOP) + @CommandMethod("cancel|cancelrestart|cr") + @CommandDescription("Cancels all countdowns") + @CommandPermission(Permissions.STOP) public void cancel(Audience audience, Match match) { if (RestartManager.isQueued()) { match.callEvent(new CancelRestartEvent()); 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 17ec55e06d..fc80fa1ac5 100644 --- a/core/src/main/java/tc/oc/pgm/command/ClassCommand.java +++ b/core/src/main/java/tc/oc/pgm/command/ClassCommand.java @@ -5,48 +5,36 @@ import static net.kyori.adventure.text.Component.translatable; import static tc.oc.pgm.util.text.TextException.exception; -import app.ashcon.intake.Command; -import app.ashcon.intake.parametric.annotation.Maybe; -import app.ashcon.intake.parametric.annotation.Text; +import cloud.commandframework.annotations.Argument; +import cloud.commandframework.annotations.CommandDescription; +import cloud.commandframework.annotations.CommandMethod; +import cloud.commandframework.annotations.specifier.FlagYielding; import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextDecoration; -import org.bukkit.ChatColor; 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; -import tc.oc.pgm.util.LegacyFormatUtils; -import tc.oc.pgm.util.StringUtils; -import tc.oc.pgm.util.text.TextTranslations; +import tc.oc.pgm.util.text.TextFormatter; public final class ClassCommand { - @Command( - aliases = {"class", "selectclass", "c", "cl"}, - desc = "Select your class") - public void classSelect(Match match, MatchPlayer player, @Maybe @Text String query) { + @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); final PlayerClass currentClass = classes.getSelectedClass(player.getId()); - if (query == null) { + if (newClass == null) { player.sendMessage( translatable("match.class.current", NamedTextColor.GREEN) .append(space()) .append(text(currentClass.getName(), NamedTextColor.GOLD, TextDecoration.BOLD))); player.sendMessage(translatable("match.class.view", NamedTextColor.GOLD)); } else { - final PlayerClass newClass = StringUtils.bestFuzzyMatch(query, classes.getClasses(), 0.9); - - if (newClass == null) { - throw exception("match.class.notFound"); - } - - try { - classes.setPlayerClass(player.getId(), newClass); - } catch (IllegalStateException e) { - throw exception("match.class.sticky"); - } + classes.setPlayerClass(player.getId(), newClass); player.sendMessage( translatable( @@ -59,20 +47,18 @@ public void classSelect(Match match, MatchPlayer player, @Maybe @Text String que } } - @Command( - aliases = {"classlist", "classes", "listclasses", "cls"}, - desc = "List all available classes") + @CommandMethod("classlist|classes|listclasses|cls") + @CommandDescription("List all available classes") public void classList(Match match, MatchPlayer player) { final ClassMatchModule classes = getClasses(match); final PlayerClass currentClass = classes.getSelectedClass(player.getId()); player.sendMessage( - text( - LegacyFormatUtils.dashedChatMessage( - ChatColor.GOLD - + TextTranslations.translate("match.class.title", player.getBukkit()), - "-", - ChatColor.RED.toString()))); + TextFormatter.horizontalLineHeading( + player.getBukkit(), + translatable("match.class.title").color(NamedTextColor.GOLD), + NamedTextColor.RED)); + int i = 1; for (PlayerClass cls : classes.getClasses()) { TextComponent.Builder result = text().append(text(i++ + ". ")); @@ -100,9 +86,7 @@ public void classList(Match match, MatchPlayer player) { private ClassMatchModule getClasses(Match match) { final ClassMatchModule classes = match.getModule(ClassMatchModule.class); - if (classes == null) { - throw exception("match.class.notEnabled"); - } + if (classes == null) throw exception("match.class.notEnabled"); return classes; } } diff --git a/core/src/main/java/tc/oc/pgm/command/CycleCommand.java b/core/src/main/java/tc/oc/pgm/command/CycleCommand.java index 4413cf6813..fb7974bae8 100644 --- a/core/src/main/java/tc/oc/pgm/command/CycleCommand.java +++ b/core/src/main/java/tc/oc/pgm/command/CycleCommand.java @@ -2,11 +2,12 @@ import static tc.oc.pgm.util.text.TextException.exception; -import app.ashcon.intake.Command; -import app.ashcon.intake.parametric.annotation.Default; -import app.ashcon.intake.parametric.annotation.Maybe; -import app.ashcon.intake.parametric.annotation.Switch; -import app.ashcon.intake.parametric.annotation.Text; +import cloud.commandframework.annotations.Argument; +import cloud.commandframework.annotations.CommandDescription; +import cloud.commandframework.annotations.CommandMethod; +import cloud.commandframework.annotations.CommandPermission; +import cloud.commandframework.annotations.Flag; +import cloud.commandframework.annotations.specifier.FlagYielding; import java.time.Duration; import tc.oc.pgm.api.Permissions; import tc.oc.pgm.api.map.MapInfo; @@ -16,17 +17,15 @@ public final class CycleCommand { - @Command( - aliases = {"cycle"}, - desc = "Cycle to the next match", - flags = "f", - perms = Permissions.START) + @CommandMethod("cycle [duration] [map]") + @CommandDescription("Cycle to the next match") + @CommandPermission(Permissions.START) public void cycle( Match match, MapOrder mapOrder, - @Maybe Duration duration, - @Text @Default("next") MapInfo map, - @Switch('f') boolean force) { + @Argument("duration") Duration duration, + @Argument("map") @FlagYielding MapInfo map, + @Flag(value = "force", aliases = "f") boolean force) { if (match.isRunning() && !force) { throw exception("admin.matchRunning.cycle"); } @@ -38,14 +37,14 @@ public void cycle( match.needModule(CycleMatchModule.class).startCountdown(duration); } - @Command( - aliases = {"recycle", "rematch"}, - desc = "Reload (cycle to) the current map", - usage = "[seconds]", - flags = "f", - perms = Permissions.START) + @CommandMethod("recycle|rematch [duration]") + @CommandDescription("Reload (cycle to) the current map") + @CommandPermission(Permissions.START) public void recycle( - Match match, MapOrder mapOrder, @Maybe Duration duration, @Switch('f') boolean force) { + Match match, + MapOrder mapOrder, + @Argument("duration") Duration duration, + @Flag(value = "force", aliases = "f") boolean force) { cycle(match, mapOrder, duration, match.getMap(), force); } } diff --git a/core/src/main/java/tc/oc/pgm/command/FinishCommand.java b/core/src/main/java/tc/oc/pgm/command/FinishCommand.java index 6bc583462c..b41dd3d15a 100644 --- a/core/src/main/java/tc/oc/pgm/command/FinishCommand.java +++ b/core/src/main/java/tc/oc/pgm/command/FinishCommand.java @@ -2,23 +2,21 @@ import static tc.oc.pgm.util.text.TextException.exception; -import app.ashcon.intake.Command; -import app.ashcon.intake.parametric.annotation.Maybe; -import app.ashcon.intake.parametric.annotation.Text; +import cloud.commandframework.annotations.Argument; +import cloud.commandframework.annotations.CommandDescription; +import cloud.commandframework.annotations.CommandMethod; +import cloud.commandframework.annotations.CommandPermission; 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.teams.Team; public final class FinishCommand { - @Command( - aliases = {"finish", "end"}, - desc = "End the match", - usage = "[competitor]", - perms = Permissions.STOP) - public void end(Match match, @Text @Maybe Party team) { - if (!match.finish(team instanceof Competitor ? (Competitor) team : null)) { + @CommandMethod("finish|end [team]") + @CommandDescription("End the match") + @CommandPermission(Permissions.STOP) + public void end(Match match, @Argument("team") Team team) { + if (!match.finish(team)) { throw exception("admin.end.unknownError"); } } 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 64330d8189..56dbd81a2c 100644 --- a/core/src/main/java/tc/oc/pgm/command/FreeForAllCommand.java +++ b/core/src/main/java/tc/oc/pgm/command/FreeForAllCommand.java @@ -4,8 +4,10 @@ import static net.kyori.adventure.text.Component.translatable; import static tc.oc.pgm.util.text.TextException.exception; -import app.ashcon.intake.Command; -import app.ashcon.intake.parametric.annotation.Maybe; +import cloud.commandframework.annotations.Argument; +import cloud.commandframework.annotations.CommandDescription; +import cloud.commandframework.annotations.CommandMethod; +import cloud.commandframework.annotations.CommandPermission; import com.google.common.collect.Range; import net.kyori.adventure.text.format.NamedTextColor; import tc.oc.pgm.api.Permissions; @@ -14,52 +16,64 @@ import tc.oc.pgm.util.Audience; import tc.oc.pgm.util.text.TextParser; +@CommandMethod("ffa|players") public final class FreeForAllCommand { - @Command( - aliases = {"min"}, - desc = "Set the min players on a team", - usage = " (reset | )", - perms = Permissions.RESIZE) - public void min(Audience audience, Match match, String minPlayers) { + @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); - if (minPlayers.equalsIgnoreCase("reset")) { - ffa.setMaxPlayers(null, null); - } else { - ffa.setMinPlayers(TextParser.parseInteger(minPlayers, Range.atLeast(0))); - } + TextParser.assertInRange(minPlayers, Range.atLeast(0)); - audience.sendMessage( - translatable( - "match.resize.min", - translatable("match.info.players", NamedTextColor.YELLOW), - text(ffa.getMinPlayers(), NamedTextColor.AQUA))); + ffa.setMinPlayers(minPlayers); + sendResizedMessage(audience, "min", ffa.getMinPlayers()); } - @Command( - aliases = {"size"}, - desc = "Set the max players", - usage = "(reset | [max-overfill]") + @CommandDescription("Set the max players") + @CommandPermission(Permissions.RESIZE) + public void max( + Audience audience, + Match match, + @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); + else TextParser.assertInRange(maxOverfill, Range.atLeast(maxPlayers)); + + ffa.setMaxPlayers(maxPlayers, maxOverfill); + + sendResizedMessage(audience, "max", ffa.getMaxPlayers()); + } + + @CommandMethod("max reset") + @CommandDescription("Reset the max players") + @CommandPermission(Permissions.RESIZE) + public void max(Audience audience, Match match) { + final FreeForAllMatchModule ffa = getFfa(match); + ffa.setMaxPlayers(null, null); + sendResizedMessage(audience, "max", ffa.getMaxPlayers()); + } + private void sendResizedMessage(Audience audience, String type, int value) { audience.sendMessage( translatable( - "match.resize.max", + "match.resize." + type, translatable("match.info.players", NamedTextColor.YELLOW), - text(ffa.getMaxPlayers(), NamedTextColor.AQUA))); + text(value, NamedTextColor.AQUA))); } private FreeForAllMatchModule getFfa(Match match) { 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 532d4fc64b..577829211a 100644 --- a/core/src/main/java/tc/oc/pgm/command/InventoryCommand.java +++ b/core/src/main/java/tc/oc/pgm/command/InventoryCommand.java @@ -2,22 +2,21 @@ import static tc.oc.pgm.util.text.TextException.exception; -import app.ashcon.intake.Command; -import app.ashcon.intake.bukkit.parametric.annotation.Sender; -import org.bukkit.entity.Player; +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 { - - @Command( - aliases = {"inventory", "inv", "vi"}, - desc = "View a player's inventory") - public void inventory(Match match, @Sender Player viewer, Player holder) { + @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); if (inventories.canPreviewInventory(viewer, holder)) { - inventories.previewInventory(viewer, holder.getInventory()); + inventories.previewInventory(viewer.getBukkit(), holder.getInventory()); } else { throw exception("preview.notViewable"); } 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 f0275ee166..cca3e71d5e 100644 --- a/core/src/main/java/tc/oc/pgm/command/JoinCommand.java +++ b/core/src/main/java/tc/oc/pgm/command/JoinCommand.java @@ -1,9 +1,11 @@ package tc.oc.pgm.command; -import app.ashcon.intake.Command; -import app.ashcon.intake.parametric.annotation.Maybe; -import app.ashcon.intake.parametric.annotation.Switch; -import app.ashcon.intake.parametric.annotation.Text; +import cloud.commandframework.annotations.Argument; +import cloud.commandframework.annotations.CommandDescription; +import cloud.commandframework.annotations.CommandMethod; +import cloud.commandframework.annotations.CommandPermission; +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; @@ -13,14 +15,14 @@ public final class JoinCommand { - @Command( - aliases = {"join", "play"}, - desc = "Join the match", - usage = "[team] - defaults to random", - flags = "f", - perms = Permissions.JOIN) + @CommandMethod("join|play [team]") + @CommandDescription("Join the match") + @CommandPermission(Permissions.JOIN) public void join( - Match match, MatchPlayer player, @Switch('f') boolean force, @Text @Maybe Party team) { + Match match, + MatchPlayer player, + @Flag(value = "force", aliases = "f") boolean force, + @Argument("team") @FlagYielding Party team) { if (team != null && !(team instanceof Competitor)) { leave(player, match); return; @@ -34,10 +36,9 @@ public void join( } } - @Command( - aliases = {"leave", "obs", "spectator", "spec"}, - desc = "Leave the match", - perms = Permissions.LEAVE) + @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); } diff --git a/core/src/main/java/tc/oc/pgm/command/ListCommand.java b/core/src/main/java/tc/oc/pgm/command/ListCommand.java index f23f0aa0b1..87fc95621f 100644 --- a/core/src/main/java/tc/oc/pgm/command/ListCommand.java +++ b/core/src/main/java/tc/oc/pgm/command/ListCommand.java @@ -4,7 +4,8 @@ import static net.kyori.adventure.text.Component.text; import static net.kyori.adventure.text.Component.translatable; -import app.ashcon.intake.Command; +import cloud.commandframework.annotations.CommandDescription; +import cloud.commandframework.annotations.CommandMethod; import java.util.Collection; import java.util.List; import java.util.UUID; @@ -21,12 +22,10 @@ import tc.oc.pgm.util.named.NameStyle; import tc.oc.pgm.util.text.TextFormatter; -// TODO: clean up format and use new components public final class ListCommand { - @Command( - aliases = {"list", "who", "online", "ls"}, - desc = "View a list of online players") + @CommandMethod("list|who|online|ls") + @CommandDescription("View a list of online players") public void list(CommandSender sender, Audience viewer, Match match) { TeamMatchModule tmm = match.getModule(TeamMatchModule.class); if (tmm != null) { 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 4510081287..b136b74af3 100644 --- a/core/src/main/java/tc/oc/pgm/command/MapCommand.java +++ b/core/src/main/java/tc/oc/pgm/command/MapCommand.java @@ -6,16 +6,16 @@ import static net.kyori.adventure.text.Component.translatable; import static net.kyori.adventure.text.event.ClickEvent.runCommand; import static net.kyori.adventure.text.event.HoverEvent.showText; +import static tc.oc.pgm.command.util.ParserConstants.CURRENT; import static tc.oc.pgm.util.Assert.assertNotNull; -import static tc.oc.pgm.util.text.TextException.invalidFormat; -import app.ashcon.intake.Command; -import app.ashcon.intake.CommandException; -import app.ashcon.intake.parametric.annotation.Default; -import app.ashcon.intake.parametric.annotation.Switch; -import app.ashcon.intake.parametric.annotation.Text; +import cloud.commandframework.annotations.Argument; +import cloud.commandframework.annotations.CommandDescription; +import cloud.commandframework.annotations.CommandMethod; +import cloud.commandframework.annotations.Flag; +import cloud.commandframework.annotations.specifier.Greedy; +import cloud.commandframework.annotations.specifier.Range; import com.google.common.collect.ImmutableSortedSet; -import com.google.common.collect.Sets; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.*; @@ -37,6 +37,7 @@ import tc.oc.pgm.rotation.pools.MapPool; import tc.oc.pgm.util.Audience; import tc.oc.pgm.util.PrettyPaginatedComponentResults; +import tc.oc.pgm.util.StringUtils; import tc.oc.pgm.util.named.MapNameStyle; import tc.oc.pgm.util.named.NameStyle; import tc.oc.pgm.util.text.TextFormatter; @@ -44,24 +45,22 @@ public final class MapCommand { - @Command( - aliases = {"maps", "maplist", "ml"}, - desc = "List all maps loaded", - usage = "[-a ] [-t ,] [-n ]") + @CommandMethod("maps|maplist|ml [page]") + @CommandDescription("List all maps loaded") public void maps( Audience audience, CommandSender sender, MapLibrary library, - @Default("1") Integer page, - @Switch('t') String tags, - @Switch('a') String author, - @Switch('n') String name, - @Switch('p') String phaseType) - throws CommandException { - Stream search = Sets.newHashSet(library.getMaps()).stream(); - if (tags != null) { + @Argument(value = "page", defaultValue = "1") @Range(min = "1") int page, + @Flag(value = "tags", aliases = "t", repeatable = true) List tags, + @Flag(value = "author", aliases = "a") String author, + @Flag(value = "name", aliases = "n") String name, + @Flag(value = "phase", aliases = "p") Phase phase) { + Stream search = library.getMaps(name); + if (!tags.isEmpty()) { final Map> tagSet = - Stream.of(tags.split(",")) + tags.stream() + .flatMap(t -> Arrays.stream(t.split(","))) .map(String::toLowerCase) .map(String::trim) .collect( @@ -74,17 +73,13 @@ public void maps( } if (author != null) { - search = search.filter(map -> matchesAuthor(map, author)); + String query = StringUtils.normalize(author); + search = search.filter(map -> matchesAuthor(map, query)); } - if (name != null) { - search = search.filter(map -> matchesName(map, name)); - } - - Phase phase = phaseType == null ? Phase.PRODUCTION : Phase.of(phaseType); - if (phase == null) throw invalidFormat(phaseType, Phase.class, null); - - search = search.filter(map -> map.getPhase() == phase); + // FIXME: change when cloud gets support for default flag values + final Phase finalPhase = phase == null ? Phase.PRODUCTION : phase; + search = search.filter(map -> map.getPhase() == finalPhase); Set maps = search.collect(Collectors.toCollection(TreeSet::new)); int resultsPerPage = 8; @@ -135,34 +130,20 @@ private static boolean matchesTags( } private static boolean matchesAuthor(MapInfo map, String query) { - assertNotNull(map); - query = assertNotNull(query).toLowerCase(); - for (Contributor contributor : map.getAuthors()) { - if (contributor.getNameLegacy().toLowerCase().contains(query)) { + if (StringUtils.normalize(contributor.getNameLegacy()).contains(query)) { return true; } } return false; } - private static boolean matchesName(MapInfo map, String query) { - assertNotNull(map); - query = assertNotNull(query).toLowerCase(); - return map.getName().toLowerCase().contains(query); - } - - private static boolean matchesPhase(MapInfo map, String query) { - assertNotNull(map); - query = assertNotNull(query).toLowerCase(); - return map.getPhase().equals(Phase.of(query)); - } - - @Command( - aliases = {"map", "mapinfo"}, - desc = "Show info about a map", - usage = "[map name] - defaults to the current map") - public void map(Audience audience, CommandSender sender, @Text MapInfo map) { + @CommandMethod("map|mapinfo [map]") + @CommandDescription("Show info about a map") + public void map( + Audience audience, + CommandSender sender, + @Argument(value = "map", defaultValue = CURRENT) @Greedy MapInfo map) { audience.sendMessage( TextFormatter.horizontalLineHeading( sender, 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 fec8767445..ea1e794f27 100644 --- a/core/src/main/java/tc/oc/pgm/command/MapDevCommand.java +++ b/core/src/main/java/tc/oc/pgm/command/MapDevCommand.java @@ -2,9 +2,11 @@ import static net.kyori.adventure.text.Component.text; -import app.ashcon.intake.Command; -import app.ashcon.intake.parametric.annotation.Maybe; -import org.bukkit.entity.Player; +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 tc.oc.pgm.api.Permissions; import tc.oc.pgm.api.match.Match; import tc.oc.pgm.api.player.MatchPlayer; @@ -12,12 +14,12 @@ public class MapDevCommand { - @Command( - aliases = {"variables"}, - desc = "Inspect variables for a player", - perms = Permissions.DEBUG) - public void showVariables(Match match, MatchPlayer sender, @Maybe Player target) { - MatchPlayer filterable = target == null ? sender : match.getPlayer(target); + @CommandMethod("variables [target]") + @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; sender.sendMessage(text("Showing variables for " + filterable.getNameLegacy() + ":")); for (Variable v : match.getFeatureContext().getAll(Variable.class)) { diff --git a/core/src/main/java/tc/oc/pgm/command/MapOrderCommand.java b/core/src/main/java/tc/oc/pgm/command/MapOrderCommand.java index 2e666718fb..b26e420501 100644 --- a/core/src/main/java/tc/oc/pgm/command/MapOrderCommand.java +++ b/core/src/main/java/tc/oc/pgm/command/MapOrderCommand.java @@ -2,12 +2,14 @@ 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 app.ashcon.intake.Command; -import app.ashcon.intake.CommandException; -import app.ashcon.intake.parametric.annotation.Maybe; -import app.ashcon.intake.parametric.annotation.Switch; -import app.ashcon.intake.parametric.annotation.Text; +import cloud.commandframework.annotations.Argument; +import cloud.commandframework.annotations.CommandDescription; +import cloud.commandframework.annotations.CommandMethod; +import cloud.commandframework.annotations.CommandPermission; +import cloud.commandframework.annotations.Flag; +import cloud.commandframework.annotations.specifier.FlagYielding; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.command.CommandSender; @@ -20,20 +22,15 @@ import tc.oc.pgm.util.Audience; import tc.oc.pgm.util.UsernameFormatUtils; import tc.oc.pgm.util.named.MapNameStyle; -import tc.oc.pgm.util.text.TextTranslations; public final class MapOrderCommand { - @Command( - aliases = {"nextmap", "mn", "mapnext", "nm", "next"}, - desc = "Show which map is playing next") + @CommandMethod("nextmap|mn|mapnext|nm|next") + @CommandDescription("Show which map is playing next") public void nextmap(Audience audience, MapOrder mapOrder) { final MapInfo next = mapOrder.getNextMap(); - if (next == null) { - audience.sendMessage(translatable("map.noNextMap", NamedTextColor.RED)); - return; - } + if (next == null) throw exception("map.noNextMap"); audience.sendMessage( translatable( @@ -42,23 +39,19 @@ public void nextmap(Audience audience, MapOrder mapOrder) { next.getStyledName(MapNameStyle.COLOR_WITH_AUTHORS))); } - @Command( - aliases = {"setnext", "sn"}, - desc = "Change the next map", - usage = "[map name] -f (force) -r (revert)", - flags = "fr", - perms = Permissions.SETNEXT) + @CommandMethod("setnext|sn [map]") + @CommandDescription("Change the next map") + @CommandPermission(Permissions.SETNEXT) public void setNext( Audience viewer, CommandSender sender, MapOrder mapOrder, Match match, - @Switch('f') boolean force, - @Switch('r') boolean reset, - @Maybe @Text MapInfo map) - throws CommandException { + @Flag(value = "force", aliases = "f") boolean force, + @Flag(value = "reset", aliases = "r") boolean reset, + @Argument("map") @FlagYielding MapInfo map) { if (RestartManager.isQueued() && !force) { - throw new CommandException(TextTranslations.translate("map.setNext.confirm", sender)); + throw exception("map.setNext.confirm"); } if (reset) { 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 3843a1e95f..cff6b08ef6 100644 --- a/core/src/main/java/tc/oc/pgm/command/MapPoolCommand.java +++ b/core/src/main/java/tc/oc/pgm/command/MapPoolCommand.java @@ -3,13 +3,15 @@ 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 app.ashcon.intake.Command; -import app.ashcon.intake.CommandException; -import app.ashcon.intake.parametric.annotation.Default; -import app.ashcon.intake.parametric.annotation.Maybe; -import app.ashcon.intake.parametric.annotation.Switch; -import app.ashcon.intake.parametric.annotation.Text; +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.CommandPermission; +import cloud.commandframework.annotations.Flag; +import cloud.commandframework.annotations.specifier.FlagYielding; +import cloud.commandframework.annotations.specifier.Range; import java.text.DecimalFormat; import java.time.Duration; import java.util.HashMap; @@ -36,33 +38,23 @@ import tc.oc.pgm.util.PrettyPaginatedComponentResults; import tc.oc.pgm.util.named.MapNameStyle; import tc.oc.pgm.util.text.TextFormatter; -import tc.oc.pgm.util.text.TextTranslations; public final class MapPoolCommand { private static final DecimalFormat SCORE_FORMAT = new DecimalFormat("00.00%"); - @Command( - aliases = {"pool", "rotation", "rot"}, - desc = "List the maps in the map pool", - usage = "[page] [-p pool] [-s scores] [-c chance of vote]") - public static void pool( + @CommandMethod("pool [page]") + @CommandDescription("List the maps in the map pool") + public void pool( Audience audience, CommandSender sender, MapOrder mapOrder, - @Default("1") int page, - @Switch('r') String rotationName, - @Switch('p') String poolName, - @Switch('s') boolean scores, - @Switch('c') boolean chance) - throws CommandException { - if (rotationName != null) poolName = rotationName; - - MapPoolManager mapPoolManager = getMapPoolManager(sender, mapOrder); - MapPool mapPool = - poolName == null - ? mapPoolManager.getActiveMapPool() - : mapPoolManager.getMapPoolByName(poolName); + @Argument(value = "page", defaultValue = "1") @Range(min = "1") int page, + @Flag(value = "pool", aliases = "p") MapPool mapPool, + @Flag(value = "score", aliases = "s") boolean scores, + @Flag(value = "chance", aliases = "c") boolean chance) { + + if (mapPool == null) mapPool = getMapPoolManager(mapOrder).getActiveMapPool(); if (mapPool == null) { audience.sendWarning(translatable("pool.noPoolMatch")); @@ -126,19 +118,16 @@ public Component format(MapInfo map, int index) { }.display(audience, maps, page); } - @Command( - aliases = {"pools", "rotations", "rots"}, - desc = "List all the map pools", - flags = "d") - public static void pools( + @CommandMethod("pools [page]") + @CommandDescription("List all the map pools") + public void pools( Audience audience, CommandSender sender, MapOrder mapOrder, - @Default("1") int page, - @Switch('d') boolean dynamicOnly) - throws CommandException { + @Argument(value = "page", defaultValue = "1") @Range(min = "1") int page, + @Flag(value = "dynamic", aliases = "d") boolean dynamicOnly) { - MapPoolManager mapPoolManager = getMapPoolManager(sender, mapOrder); + MapPoolManager mapPoolManager = getMapPoolManager(mapOrder); List mapPools = mapPoolManager.getMapPools(); if (mapPools.isEmpty()) { @@ -203,64 +192,51 @@ public Component format(MapPool mapPool, int index) { }.display(audience, mapPools, page); } - @Command( - aliases = {"setpool", "setrot"}, - desc = "Change the map pool", - usage = "[pool name] -r (revert to dynamic) -t (time limit for map pool) -m (match # limit)", - flags = "rtm", - perms = Permissions.SETNEXT) + @CommandMethod("setpool [pool]") + @CommandDescription("Change the map pool") + @CommandPermission(Permissions.SETNEXT) public void setPool( Audience sender, CommandSender source, Match match, MapOrder mapOrder, - @Maybe String poolName, - @Switch('r') boolean reset, - @Switch('t') Duration timeLimit, - @Switch('m') Integer matchLimit) - throws CommandException { - if (!match.getCountdown().getAll(CycleCountdown.class).isEmpty()) { - sender.sendMessage(translatable("admin.setPool.activeCycle", NamedTextColor.RED)); + @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.equals(mapPoolManager.getActiveMapPool())) { + sender.sendMessage( + translatable( + "pool.matching", + NamedTextColor.GRAY, + text(newPool.getName(), NamedTextColor.LIGHT_PURPLE))); return; } - MapPoolManager mapPoolManager = getMapPoolManager(source, mapOrder); - MapPool newPool = - reset - ? mapPoolManager.getAppropriateDynamicPool(match).orElse(null) - : mapPoolManager.getMapPoolByName(poolName); - - if (newPool == null) { - sender.sendWarning(translatable(reset ? "pool.noDynamic" : "pool.noPoolMatch")); - } else { - if (newPool.equals(mapPoolManager.getActiveMapPool())) { - sender.sendMessage( - translatable( - "pool.matching", - NamedTextColor.GRAY, - text(newPool.getName(), NamedTextColor.LIGHT_PURPLE))); - return; - } - mapPoolManager.updateActiveMapPool( - newPool, match, true, source, timeLimit, matchLimit != null ? matchLimit : 0); - } + mapPoolManager.updateActiveMapPool( + newPool, match, true, source, timeLimit, matchLimit != null ? matchLimit : 0); } - @Command( - aliases = {"skip"}, - desc = "Skip the next map", - usage = "[positions]", - perms = Permissions.SETNEXT) - public static void skip( - Audience viewer, CommandSender sender, MapOrder mapOrder, @Default("1") int positions) - throws CommandException { - - if (positions < 0) { - viewer.sendWarning(translatable("pool.skip.negative")); - return; - } + @CommandMethod("skip [positions]") + @CommandDescription("Skip the next map") + @CommandPermission(Permissions.SETNEXT) + public void skip( + Audience viewer, + MapOrder mapOrder, + @Argument(value = "positions", defaultValue = "1") @Range(min = "1") int positions) { - MapPool pool = getMapPoolManager(sender, mapOrder).getActiveMapPool(); + MapPool pool = getMapPoolManager(mapOrder).getActiveMapPool(); if (!(pool instanceof Rotation)) { viewer.sendWarning(translatable("pool.noRotation")); return; @@ -283,50 +259,40 @@ public static void skip( viewer.sendMessage(message); } - @Command(aliases = "votenext", desc = "Vote for the next map", usage = "map") - public static void voteNext( + @CommandMethod("votenext [map]") + @CommandDescription("Vote for the next map") + public void voteNext( MatchPlayer player, CommandSender sender, MapOrder mapOrder, - @Switch('o') boolean forceOpen, - @Text MapInfo map) - throws CommandException { - MapPoll poll = getVotingPool(player, sender, mapOrder); - if (poll != null) { - boolean voteResult = poll.toggleVote(map, ((Player) sender).getUniqueId()); - Component voteAction = - translatable( - voteResult ? "vote.for" : "vote.abstain", - voteResult ? NamedTextColor.GREEN : NamedTextColor.RED, - map.getStyledName(MapNameStyle.COLOR)); - player.sendMessage(voteAction); - poll.sendBook(player, forceOpen); - } + @Flag(value = "open", aliases = "o") boolean forceOpen, + @Argument("map") @FlagYielding MapInfo map) { + MapPoll poll = getVotingPool(mapOrder); + boolean voteResult = poll.toggleVote(map, ((Player) sender).getUniqueId()); + Component voteAction = + translatable( + voteResult ? "vote.for" : "vote.abstain", + voteResult ? NamedTextColor.GREEN : NamedTextColor.RED, + map.getStyledName(MapNameStyle.COLOR)); + player.sendMessage(voteAction); + poll.sendBook(player, forceOpen); } - @Command(aliases = "votebook", desc = "Spawn a vote book") - public void voteBook(MatchPlayer player, CommandSender sender, MapOrder mapOrder) - throws CommandException { - MapPoll poll = getVotingPool(player, sender, mapOrder); - if (poll != null) { - poll.sendBook(player, false); - } + @CommandMethod("votebook") + @CommandDescription("Spawn a vote book") + public void voteBook(MatchPlayer player, MapOrder mapOrder) { + getVotingPool(mapOrder).sendBook(player, false); } - private static MapPoll getVotingPool(MatchPlayer player, CommandSender sender, MapOrder mapOrder) - throws CommandException { - MapPool pool = getMapPoolManager(sender, mapOrder).getActiveMapPool(); + private static MapPoll getVotingPool(MapOrder mapOrder) { + MapPool pool = getMapPoolManager(mapOrder).getActiveMapPool(); MapPoll poll = pool instanceof VotingPool ? ((VotingPool) pool).getCurrentPoll() : null; - if (poll == null) { - player.sendWarning(translatable("vote.noVote")); - } + if (poll == null) throw exception("vote.noVote"); return poll; } - public static MapPoolManager getMapPoolManager(CommandSender sender, MapOrder mapOrder) - throws CommandException { + public static MapPoolManager getMapPoolManager(MapOrder mapOrder) { if (mapOrder instanceof MapPoolManager) return (MapPoolManager) mapOrder; - - throw new CommandException(TextTranslations.translate("pool.mapPoolsDisabled", sender)); + throw exception("pool.mapPoolsDisabled"); } } diff --git a/core/src/main/java/tc/oc/pgm/command/MatchCommand.java b/core/src/main/java/tc/oc/pgm/command/MatchCommand.java index 2b83eede6e..d504dbbc27 100644 --- a/core/src/main/java/tc/oc/pgm/command/MatchCommand.java +++ b/core/src/main/java/tc/oc/pgm/command/MatchCommand.java @@ -7,7 +7,8 @@ import static net.kyori.adventure.text.Component.translatable; import static tc.oc.pgm.util.text.TemporalComponent.clock; -import app.ashcon.intake.Command; +import cloud.commandframework.annotations.CommandDescription; +import cloud.commandframework.annotations.CommandMethod; import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; @@ -40,12 +41,10 @@ import tc.oc.pgm.util.text.TextFormatter; import tc.oc.pgm.util.text.TextTranslations; -// TODO: improve format and translate public final class MatchCommand { - @Command( - aliases = {"match", "matchinfo"}, - desc = "Show the match info") + @CommandMethod("match|matchinfo") + @CommandDescription("Show the match info") public void match(Audience viewer, CommandSender sender, Match match) { // indicates whether we have game information from the match yet boolean haveGameInfo = 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 391f4fc3d5..15e42c01c5 100644 --- a/core/src/main/java/tc/oc/pgm/command/ModeCommand.java +++ b/core/src/main/java/tc/oc/pgm/command/ModeCommand.java @@ -6,9 +6,11 @@ import static tc.oc.pgm.util.text.TemporalComponent.clock; import static tc.oc.pgm.util.text.TextException.exception; -import app.ashcon.intake.Command; -import app.ashcon.intake.CommandException; -import app.ashcon.intake.parametric.annotation.Default; +import cloud.commandframework.annotations.Argument; +import cloud.commandframework.annotations.CommandDescription; +import cloud.commandframework.annotations.CommandMethod; +import cloud.commandframework.annotations.CommandPermission; +import cloud.commandframework.annotations.specifier.Range; import java.time.Duration; import java.util.List; import net.kyori.adventure.text.Component; @@ -24,12 +26,11 @@ import tc.oc.pgm.util.Audience; import tc.oc.pgm.util.text.TextFormatter; -// TODO: make the output nicer +@CommandMethod("mode|modes") public final class ModeCommand { - @Command( - aliases = {"next"}, - desc = "Show the next objective mode") + @CommandMethod("next") + @CommandDescription("Show the next objective mode") public void next(Audience audience, Match match) { ObjectiveModesMatchModule modes = getModes(match); @@ -72,19 +73,19 @@ public void next(Audience audience, Match match) { } } - @Command( - aliases = {"list", "page"}, - desc = "List all objective modes", - usage = "[page]") - public void list(Audience audience, Match match, @Default("1") int page) throws CommandException { + @CommandMethod("list|page [page]") + @CommandDescription("List all objective modes") + public void list( + Audience audience, + Match match, + @Argument(value = "page", defaultValue = "1") @Range(min = "1") int page) { showList(page, audience, getModes(match)); } - @Command( - aliases = {"push"}, - desc = "Reschedule all objective modes with active countdowns", - perms = Permissions.GAMEPLAY) - public void push(Audience audience, Match match, Duration duration) { + @CommandMethod("push