diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/GamerulesCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/GamerulesCommand.java new file mode 100644 index 00000000..0a18d6b3 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/GamerulesCommand.java @@ -0,0 +1,132 @@ +package com.onarandombox.MultiverseCore.commands; + +import co.aikar.commands.CommandIssuer; +import co.aikar.commands.InvalidCommandArgument; +import co.aikar.commands.MessageType; +import co.aikar.commands.annotation.CommandAlias; +import co.aikar.commands.annotation.CommandCompletion; +import co.aikar.commands.annotation.CommandPermission; +import co.aikar.commands.annotation.Description; +import co.aikar.commands.annotation.Flags; +import co.aikar.commands.annotation.Optional; +import co.aikar.commands.annotation.Subcommand; +import co.aikar.commands.annotation.Syntax; +import com.onarandombox.MultiverseCore.api.MVWorld; +import com.onarandombox.MultiverseCore.commandtools.MVCommandIssuer; +import com.onarandombox.MultiverseCore.commandtools.MVCommandManager; +import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand; +import com.onarandombox.MultiverseCore.commandtools.flags.CommandValueFlag; +import com.onarandombox.MultiverseCore.commandtools.flags.ParsedCommandFlags; +import com.onarandombox.MultiverseCore.display.ContentDisplay; +import com.onarandombox.MultiverseCore.display.filters.ContentFilter; +import com.onarandombox.MultiverseCore.display.filters.DefaultContentFilter; +import com.onarandombox.MultiverseCore.display.filters.RegexContentFilter; +import com.onarandombox.MultiverseCore.display.handlers.PagedSendHandler; +import com.onarandombox.MultiverseCore.display.parsers.MapContentProvider; +import com.onarandombox.MultiverseCore.utils.MVCorei18n; +import jakarta.inject.Inject; +import org.bukkit.ChatColor; +import org.bukkit.GameRule; +import org.bukkit.World; +import org.jetbrains.annotations.NotNull; +import org.jvnet.hk2.annotations.Service; + +import java.util.HashMap; +import java.util.Map; + +/** + * List all gamerules in your current or specified world. + */ +@Service +@CommandAlias("mv") +public class GamerulesCommand extends MultiverseCommand { + + private final CommandValueFlag PAGE_FLAG = flag(CommandValueFlag + .builder("--page", Integer.class) + .addAlias("-p") + .context(value -> { + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + throw new InvalidCommandArgument("Invalid page number: " + value); + } + }) + .build()); + + private final CommandValueFlag FILTER_FLAG = flag(CommandValueFlag + .builder("--filter", ContentFilter.class) + .addAlias("-f") + .context(value -> { + try { + return RegexContentFilter.fromString(value); + } catch (IllegalArgumentException e) { + throw new InvalidCommandArgument("Invalid filter: " + value); + } + }) + .build()); + + @Inject + GamerulesCommand(@NotNull MVCommandManager commandManager) { + super(commandManager); + } + + @Subcommand("gamerules|rules") + @CommandPermission("multiverse.core.gamerule.list") + @CommandCompletion("@mvworlds|@flags:groupName=mvgamerulescommand @flags:groupName=mvgamerulescommand") + @Syntax("[world] [--page ] [--filter ]") + @Description("{@@mv-core.gamerules.description}") + public void onGamerulesCommand( + @NotNull MVCommandIssuer issuer, + + @Flags("resolve=issuerAware") + @Syntax("") + @Description("{@@mv-core.gamerules.description.world}") + MVWorld world, + + @Optional + @Syntax("[--page ] [--filter ]") + @Description("{@@mv-core.gamerules.description.page}") + String[] flags + ) { + ParsedCommandFlags parsedFlags = parseFlags(flags); + + ContentDisplay.create() + .addContent(new MapContentProvider<>(getGameRuleMap(world.getCBWorld())) + .withKeyColor(ChatColor.AQUA) + .withValueColor(ChatColor.WHITE)) + .withSendHandler(new PagedSendHandler() + .withHeader(this.getTitle(issuer, world.getCBWorld())) + .doPagination(true) + .withTargetPage(parsedFlags.flagValue(PAGE_FLAG, 1)) + .withFilter(parsedFlags.flagValue(FILTER_FLAG, DefaultContentFilter.get()))) + .send(issuer); + } + + /** + * Gets all the gamerules and their values for a given world. + * + * @param world The world to find gamerules for. + * @return A map of the gamerules and their values + */ + private Map getGameRuleMap(World world) { + Map gameRuleMap = new HashMap<>(); + + for (GameRule gamerule : GameRule.values()) { + Object gameruleValue = world.getGameRuleValue(gamerule); + if (gameruleValue == null) { + gameRuleMap.put(gamerule.getName(), "null"); + continue; + } + gameRuleMap.put(gamerule.getName(), gameruleValue.toString()); + } + return gameRuleMap; + } + + private String getTitle(CommandIssuer issuer, World world) { + return this.commandManager.formatMessage( + issuer, + MessageType.INFO, + MVCorei18n.GAMERULES_TITLE, + "{world}", world.getName()); + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandCompletions.java b/src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandCompletions.java index ac21dc11..77f66d6a 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandCompletions.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandCompletions.java @@ -14,6 +14,7 @@ import com.onarandombox.MultiverseCore.destination.ParsedDestination; import com.onarandombox.MultiverseCore.worldnew.LoadedMultiverseWorld; import com.onarandombox.MultiverseCore.worldnew.MultiverseWorld; import com.onarandombox.MultiverseCore.worldnew.WorldManager; +import io.vavr.control.Try; import jakarta.inject.Inject; import org.bukkit.GameRule; import org.jetbrains.annotations.NotNull; @@ -96,8 +97,11 @@ public class MVCommandCompletions extends PaperCommandCompletions { } private Collection suggestFlags(@NotNull BukkitCommandCompletionContext context) { - return this.commandManager.getFlagsManager().suggest( - context.getConfig("groupName", ""), context.getContextValue(String[].class)); + String groupName = context.getConfig("groupName", ""); + + return Try.of(() -> context.getContextValue(String[].class)) + .map(flags -> commandManager.getFlagsManager().suggest(groupName, flags)) + .getOrElse(Collections.emptyList()); } private Collection suggestGamerules() { diff --git a/src/main/java/com/onarandombox/MultiverseCore/commandtools/MultiverseCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commandtools/MultiverseCommand.java index b198166b..1225319f 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commandtools/MultiverseCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commandtools/MultiverseCommand.java @@ -1,32 +1,54 @@ package com.onarandombox.MultiverseCore.commandtools; import co.aikar.commands.BaseCommand; +import com.dumptruckman.minecraft.util.Logging; +import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlag; import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlagGroup; import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlagsManager; import com.onarandombox.MultiverseCore.commandtools.flags.ParsedCommandFlags; +import jakarta.annotation.PostConstruct; import org.jetbrains.annotations.NotNull; import org.jvnet.hk2.annotations.Contract; @Contract -public abstract class MultiverseCommand extends BaseCommand { +public abstract class MultiverseCommand extends BaseCommand { protected final MVCommandManager commandManager; private String flagGroupName; + private CommandFlagGroup.Builder flagGroupBuilder; protected MultiverseCommand(@NotNull MVCommandManager commandManager) { this.commandManager = commandManager; } + @PostConstruct + private void postConstruct() { + if (flagGroupBuilder != null) { + registerFlagGroup(flagGroupBuilder.build()); + flagGroupBuilder = null; + } + } + protected CommandFlagsManager getFlagsManager() { return commandManager.getFlagsManager(); } + protected T flag(T flag) { + if (flagGroupBuilder == null) { + flagGroupBuilder = CommandFlagGroup.builder("mv" + getClass().getSimpleName().toLowerCase()); + } + flagGroupBuilder.add(flag); + Logging.finest("Registered flag: " + flag); + return flag; + } + protected void registerFlagGroup(@NotNull CommandFlagGroup flagGroup) { if (flagGroupName != null) { throw new IllegalStateException("Flag group already registered! (name: " + flagGroupName + ")"); } getFlagsManager().registerFlagGroup(flagGroup); flagGroupName = flagGroup.getName(); + Logging.fine("Registered flag group: " + flagGroupName); } protected @NotNull ParsedCommandFlags parseFlags(@NotNull String[] flags) { diff --git a/src/main/java/com/onarandombox/MultiverseCore/commandtools/flags/CommandFlag.java b/src/main/java/com/onarandombox/MultiverseCore/commandtools/flags/CommandFlag.java index 0604f028..a11582e0 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commandtools/flags/CommandFlag.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commandtools/flags/CommandFlag.java @@ -52,6 +52,17 @@ public class CommandFlag { return aliases; } + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return "Builder{" + + "key='" + key + '\'' + + ", aliases=" + aliases + + '}'; + } + /** * A builder for a flag. * diff --git a/src/main/java/com/onarandombox/MultiverseCore/commandtools/flags/CommandValueFlag.java b/src/main/java/com/onarandombox/MultiverseCore/commandtools/flags/CommandValueFlag.java index 8f1b6bc3..4e2acb13 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commandtools/flags/CommandValueFlag.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commandtools/flags/CommandValueFlag.java @@ -190,7 +190,7 @@ public class CommandValueFlag extends CommandFlag { * @return The flag. */ @Override - public @NotNull CommandFlag build() { + public @NotNull CommandValueFlag build() { if (context == null && !String.class.equals(type)) { throw new IllegalStateException("Context is required for none-string value flags"); } diff --git a/src/main/java/com/onarandombox/MultiverseCore/commandtools/flags/ParsedCommandFlags.java b/src/main/java/com/onarandombox/MultiverseCore/commandtools/flags/ParsedCommandFlags.java index 4f522925..605237bd 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commandtools/flags/ParsedCommandFlags.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commandtools/flags/ParsedCommandFlags.java @@ -15,7 +15,7 @@ public class ParsedCommandFlags private final Map flagValues; - public ParsedCommandFlags() { + ParsedCommandFlags() { flagValues = new HashMap<>(); } @@ -29,6 +29,16 @@ public class ParsedCommandFlags flagValues.put(key, value); } + /** + * Check if a flag is present. + * + * @param flag The flag to check. + * @return True if the flag is present, false otherwise. + */ + public boolean hasFlag(@NotNull CommandFlag flag) { + return hasFlag(flag.getKey()); + } + /** * Check if a flag is present. * @@ -39,6 +49,12 @@ public class ParsedCommandFlags return this.flagValues.containsKey(key); } + /** + * Check if a flag is present and has a value. + * + * @param key The key of the flag. + * @return True if the flag is present and has a value, false otherwise. + */ public boolean hasFlagValue(@Nullable String key) { return flagValue(key, Object.class) != null; } @@ -46,7 +62,20 @@ public class ParsedCommandFlags /** * Get the value of a flag. * - * @param key The key of the flag. + * @param The type of the value. + * @param flag The flag to get the value of. + * @param type The type of the value. + * @return The value of the flag, null if flag does not exist or no value. + */ + public @Nullable T flagValue(@NotNull CommandFlag flag, @NotNull Class type) { + return flagValue(flag.getKey(), type); + } + + /** + * Get the value of a flag. + * + * @param key The key of the flag to get the value of. + * @param type The type of the value. * @return The value of the flag, null if flag does not exist or no value. */ public @Nullable T flagValue(@Nullable String key, @NotNull Class type) { @@ -54,6 +83,27 @@ public class ParsedCommandFlags return (T) value; } + /** + * Get the value of a flag. + * + * @param The type of the value. + * @param flag The flag to get the value of. + * @param defaultValue The default value if flag does not exist or no value. + * @return The value of the flag, default value if flag does not exist or no value. + */ + public @NotNull T flagValue(@NotNull CommandValueFlag flag, @NotNull T defaultValue) { + return flagValue(flag.getKey(), defaultValue, flag.getType()); + } + + /** + * Get the value of a flag. + * + * @param The type of the value. + * @param key The key of the flag to get the value of. + * @param defaultValue The default value if flag does not exist or no value. + * @param type The type of the value. + * @return The value of the flag, default value if flag does not exist or no value. + */ public @NotNull T flagValue(@Nullable String key, @NotNull T defaultValue, @NotNull Class type) { T value = flagValue(key, type); return value != null ? value : defaultValue; diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/handlers/PagedSendHandler.java b/src/main/java/com/onarandombox/MultiverseCore/display/handlers/PagedSendHandler.java index 301e7347..03458779 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/display/handlers/PagedSendHandler.java +++ b/src/main/java/com/onarandombox/MultiverseCore/display/handlers/PagedSendHandler.java @@ -99,7 +99,7 @@ public class PagedSendHandler extends BaseSendHandler { /** * Sets whether display output should be paginated if is for console output. - * This option will be useless of {@link PagedSendHandler#paginate} is set to false. + * This option will be useless if {@link PagedSendHandler#paginate} is set to false. * * @param paginateInConsole State of doing pagination in console. * @return Same {@link PagedSendHandler} for method chaining. diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/MVCorei18n.java b/src/main/java/com/onarandombox/MultiverseCore/utils/MVCorei18n.java index 669df54a..f1fba352 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/utils/MVCorei18n.java +++ b/src/main/java/com/onarandombox/MultiverseCore/utils/MVCorei18n.java @@ -48,6 +48,12 @@ public enum MVCorei18n implements MessageKeyProvider { GAMERULE_SUCCESS_SINGLE, GAMERULE_SUCCESS_MULTIPLE, + // Gamerules command + GAMERULES_DESCRIPTION, + GAMERULES_DESCRIPTION_PAGE, + GAMERULES_DESCRIPTION_WORLD, + GAMERULES_TITLE, + // import command IMPORT_IMPORTING, diff --git a/src/main/resources/multiverse-core_en.properties b/src/main/resources/multiverse-core_en.properties index c9138ec1..0143c2fe 100644 --- a/src/main/resources/multiverse-core_en.properties +++ b/src/main/resources/multiverse-core_en.properties @@ -66,6 +66,12 @@ mv-core.gamerule.failed=Failed to set gamerule {gamerule} to {value} in {world}. mv-core.gamerule.success.single=&aSuccessfully set {gamerule} to {value} in {world}. mv-core.gamerule.success.multiple=&aSuccessfully set {gamerule} to {value} in {count} worlds. +# /mv gamerules +mv-core.gamerules.description=Lists gamerules for the specified world +mv-core.gamerules.description.page=The page to view +mv-core.gamerules.description.world=The world to list gamerules in +mv-core.gamerules.title= --- Gamerules for {world} --- + # /mv import mv-core.import.description=Imports an existing world folder. mv-core.import.name.description=Name of the world folder.