From 8f03150005f801a3e14aea52997520df395433ed Mon Sep 17 00:00:00 2001 From: benwoo1110 <30431861+benwoo1110@users.noreply.github.com> Date: Tue, 9 Mar 2021 10:07:53 +0800 Subject: [PATCH] Implement new queue command system. --- .../commands/CreateCommand.java | 73 +++--- .../commandtools/flag/CommandFlag.java | 136 +++++++++++ .../commandtools/flag/CoreFlags.java | 217 ++++++++++++++++++ .../commandtools/flag/FlagGroup.java | 96 ++++++++ .../flag/FlagParseFailedException.java | 27 +++ .../commandtools/flag/FlagResult.java | 198 ++++++++++++++++ .../commandtools/flag/NoValueCommandFlag.java | 39 ++++ .../flag/OptionalCommandFlag.java | 16 ++ .../flag/RequiredCommandFlag.java | 25 ++ .../utils/webpaste/PasteServiceType.java | 6 +- .../MultiverseCore/TestWorldStuff.java | 2 +- 11 files changed, 793 insertions(+), 42 deletions(-) create mode 100644 src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/CommandFlag.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/CoreFlags.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/FlagGroup.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/FlagParseFailedException.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/FlagResult.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/NoValueCommandFlag.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/OptionalCommandFlag.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/RequiredCommandFlag.java diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/CreateCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/CreateCommand.java index 87bdacab..41a4c68d 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/CreateCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/CreateCommand.java @@ -8,7 +8,12 @@ package com.onarandombox.MultiverseCore.commands; import com.onarandombox.MultiverseCore.MultiverseCore; +import com.onarandombox.MultiverseCore.api.Core; import com.onarandombox.MultiverseCore.api.MVWorldManager; +import com.onarandombox.MultiverseCore.commandtools.flag.CoreFlags; +import com.onarandombox.MultiverseCore.commandtools.flag.FlagGroup; +import com.onarandombox.MultiverseCore.commandtools.flag.FlagParseFailedException; +import com.onarandombox.MultiverseCore.commandtools.flag.FlagResult; import com.pneumaticraft.commandhandler.CommandHandler; import org.bukkit.ChatColor; import org.bukkit.World.Environment; @@ -26,7 +31,16 @@ import java.util.List; * Creates a new world and loads it. */ public class CreateCommand extends MultiverseCommand { - private MVWorldManager worldManager; + + private static final FlagGroup FLAG_GROUP = FlagGroup.of( + CoreFlags.SEED, + CoreFlags.WORLD_TYPE, + CoreFlags.GENERATOR, + CoreFlags.GENERATE_STRUCTURES, + CoreFlags.SPAWN_ADJUST + ); + + private final MVWorldManager worldManager; public CreateCommand(MultiverseCore plugin) { super(plugin); @@ -50,22 +64,7 @@ public class CreateCommand extends MultiverseCommand { @Override public void runCommand(CommandSender sender, List args) { String worldName = args.get(0); - File worldFile = new File(this.plugin.getServer().getWorldContainer(), worldName); String env = args.get(1); - String seed = CommandHandler.getFlag("-s", args); - String generator = CommandHandler.getFlag("-g", args); - boolean allowStructures = true; - String structureString = CommandHandler.getFlag("-a", args); - if (structureString != null) { - allowStructures = Boolean.parseBoolean(structureString); - } - String typeString = CommandHandler.getFlag("-t", args); - boolean useSpawnAdjust = true; - for (String s : args) { - if (s.equalsIgnoreCase("-n")) { - useSpawnAdjust = false; - } - } if (this.worldManager.isMVWorld(worldName)) { sender.sendMessage(ChatColor.RED + "Multiverse cannot create " + ChatColor.GOLD + ChatColor.UNDERLINE @@ -73,6 +72,7 @@ public class CreateCommand extends MultiverseCommand { return; } + File worldFile = new File(this.plugin.getServer().getWorldContainer(), worldName); if (worldFile.exists()) { sender.sendMessage(ChatColor.RED + "A Folder/World already exists with this name!"); sender.sendMessage(ChatColor.RED + "If you are confident it is a world you can import with /mvimport"); @@ -86,35 +86,28 @@ public class CreateCommand extends MultiverseCommand { return; } - // If they didn't specify a type, default to NORMAL - if (typeString == null) { - typeString = "NORMAL"; - } - WorldType type = EnvironmentCommand.getWorldTypeFromString(typeString); - if (type == null) { - sender.sendMessage(ChatColor.RED + "That is not a valid World Type."); - EnvironmentCommand.showWorldTypes(sender); + FlagResult flags; + try { + flags = FLAG_GROUP.calculateResult(args.subList(2, args.size()).toArray(new String[0])); + } catch (FlagParseFailedException e) { + sender.sendMessage(String.format("%sError: %s", ChatColor.RED, e.getMessage())); return; } - // Determine if the generator is valid. #918 - if (generator != null) { - List genarray = new ArrayList(Arrays.asList(generator.split(":"))); - if (genarray.size() < 2) { - // If there was only one arg specified, pad with another empty one. - genarray.add(""); - } - if (this.worldManager.getChunkGenerator(genarray.get(0), genarray.get(1), "test") == null) { - // We have an invalid generator. - sender.sendMessage("Invalid generator! '" + generator + "'. " + ChatColor.RED + "Aborting world creation."); - return; - } - } + Command.broadcastCommandMessage(sender, "Starting creation of world '" + worldName + "'..."); - if (this.worldManager.addWorld(worldName, environment, seed, type, allowStructures, generator, useSpawnAdjust)) { + if (this.worldManager.addWorld( + worldName, + environment, + flags.getValue(CoreFlags.SEED), + flags.getValue(CoreFlags.WORLD_TYPE), + flags.getValue(CoreFlags.GENERATE_STRUCTURES), + flags.getValue(CoreFlags.GENERATOR), + flags.getValue(CoreFlags.SPAWN_ADJUST))) { + Command.broadcastCommandMessage(sender, "Complete!"); - } else { - Command.broadcastCommandMessage(sender, "FAILED."); + return; } + Command.broadcastCommandMessage(sender, "FAILED."); } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/CommandFlag.java b/src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/CommandFlag.java new file mode 100644 index 00000000..5c0b593c --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/CommandFlag.java @@ -0,0 +1,136 @@ +package com.onarandombox.MultiverseCore.commandtools.flag; + +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +/** + *

Represents a flag that can be used in commands. This works as a key value pair.

+ * + *

Key is the {@link #identifier} and {@link #aliases} set.

+ *

Value is the {@link T} parsed based on 3 scenarios during command input:

+ *
    + *
  1. Flag completely not present. {@link #getDefaultValue()}
  2. + *
  3. Flag key present but no value. {@link #getValue()}
  4. + *
  5. Flag key and value present. {@link #getValue(String)}
  6. + *
+ * + * @param The flag Type. + */ +public abstract class CommandFlag { + + protected final String name; + protected final String identifier; + protected final Class type; + protected final Collection aliases; + + /** + * @param name Readable name for the flag. + * @param identifier Unique key to identify the flag in command arguments. + * @param type The type of value this flag represents. + */ + protected CommandFlag(@NotNull String name, + @NotNull String identifier, + @NotNull Class type) { + + this.name = name; + this.identifier = identifier; + this.type = type; + this.aliases = new ArrayList<>(); + } + + /** + * Gets name of the Command Flag. + * + * @return The Command Flag name. + */ + @NotNull + public String getName() { + return this.name; + } + + /** + * Gets identifier of the Command Flag. + * + * @return The Command Flag identifier. + */ + @NotNull + public String getIdentifier() { + return this.identifier; + } + + /** + * Gets {@link T} Type of the Command Flag. + * + * @return The Command Flag type. + */ + @NotNull + public Class getType() { + return this.type; + } + + /** + * Gets all the alternative key identifiers set for this Command Flag. + * + * @return Collection of aliases. + */ + @NotNull + public Collection getAliases() { + return this.aliases; + } + + /** + * Add alternative key identifiers for this Command Flag. + * + * @param aliases Alias(es) to be added. + * @return A {@link CommandFlag}. + */ + public CommandFlag addAliases(String...aliases) { + Collections.addAll(this.aliases, aliases); + return this; + } + + /** + * Tab-complete suggestion for this Command Flag values. + * + * @return Collection of suggested values available. + */ + public abstract Collection suggestValue(); + + /** + * When this Command Flag can get value by a user input. + * + * @return The {@link T} value. + */ + public abstract T getValue(@NotNull String input) throws FlagParseFailedException; + + /** + * When this Command Flag user input value is null/not present. + * + * @return The {@link T} value. + */ + public T getValue() throws FlagParseFailedException { + return null; + } + + /** + * When this Command Flag is not present in command input. + * + * @return The {@link T} value. + */ + public T getDefaultValue() { + return null; + } + + @Override + public String toString() { + return "CommandFlag{" + + "name='" + name + '\'' + + ", identifier='" + identifier + '\'' + + ", type=" + type + + ", aliases=" + aliases + + '}'; + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/CoreFlags.java b/src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/CoreFlags.java new file mode 100644 index 00000000..6de6b64d --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/CoreFlags.java @@ -0,0 +1,217 @@ +package com.onarandombox.MultiverseCore.commandtools.flag; + +import com.onarandombox.MultiverseCore.MultiverseCore; +import com.onarandombox.MultiverseCore.utils.webpaste.PasteServiceType; +import org.bukkit.Bukkit; +import org.bukkit.WorldType; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.stream.Collectors; + +public class CoreFlags { + + private static MultiverseCore multiverse; + + public static void setCoreInstance(MultiverseCore plugin) { + multiverse = plugin; + } + + /** + * Flag for custom seed. + */ + public static final CommandFlag SEED = new RequiredCommandFlag + ("Seed", "--seed", String.class) { + @Override + public Collection suggestValue() { + return Collections.singleton(String.valueOf(new Random().nextLong())); + } + + @Override + public String getValue(@NotNull String input) throws FlagParseFailedException { + return input; + } + }.addAliases("-s"); + + /** + * Flag for custom seed. No value means random seed. + */ + public static final CommandFlag RANDOM_SEED = new OptionalCommandFlag + ("Seed", "--seed", String.class) { + @Override + public Collection suggestValue() { + return Collections.singletonList(String.valueOf(new Random().nextLong())); + } + + @Override + public String getValue(@NotNull String input) throws FlagParseFailedException { + return input; + } + }.addAliases("-s"); + + /** + * Flag for world type used. + */ + public static final CommandFlag WORLD_TYPE = new RequiredCommandFlag + ("WorldType", "--type", WorldType.class) { + + private final Map typeAlias = new HashMap(4){{ + put("normal", "NORMAL"); + put("flat", "FLAT"); + put("largebiomes", "LARGE_BIOMES"); + put("amplified", "AMPLIFIED"); + }}; + + @Override + public Collection suggestValue() { + return typeAlias.keySet(); + } + + @Override + public WorldType getValue(@NotNull String input) throws FlagParseFailedException { + String typeName = typeAlias.getOrDefault(input, input); + try { + return WorldType.valueOf(input.toUpperCase()); + } + catch (IllegalArgumentException e) { + throw new FlagParseFailedException("'%s' is not a valid World Type. See /mv env for available World Types.", input); + } + } + + @Override + public WorldType getDefaultValue() { + return WorldType.NORMAL; + } + }.addAliases("-t"); + + /** + * Flag for world generator. + */ + public static final CommandFlag GENERATOR = new RequiredCommandFlag + ("Generator", "--gen", String.class) { + @Override + public Collection suggestValue() { + return Arrays.stream(Bukkit.getServer().getPluginManager().getPlugins()) + .filter(Plugin::isEnabled) + .filter(plugin -> multiverse.getUnsafeCallWrapper().wrap( + () -> plugin.getDefaultWorldGenerator("world", ""), + plugin.getName(), + "Get generator" + ) != null) + .map(plugin -> plugin.getDescription().getName()) + .collect(Collectors.toList()); + } + + @Override + public String getValue(@NotNull String input) throws FlagParseFailedException { + String[] genArray = input.split(":"); + String generator = genArray[0]; + String generatorId = (genArray.length > 1) ? genArray[1] : ""; + try { + if (multiverse.getMVWorldManager().getChunkGenerator(generator, generatorId, "test") == null) { + throw new Exception(); + } + } catch (Exception e) { + throw new FlagParseFailedException("Invalid generator string '%s'. See /mv gens for available generators.", input); + } + return input; + } + }.addAliases("-g"); + + /** + * Flag to toggle if world should generate structures. + */ + public static final CommandFlag GENERATE_STRUCTURES = new RequiredCommandFlag + ("GenerateStructures", "--structures", Boolean.class) { + @Override + public Collection suggestValue() { + return Arrays.asList("true", "false"); + } + + @Override + public Boolean getValue(@NotNull String input) throws FlagParseFailedException { + return input.equalsIgnoreCase("true"); + } + + @Override + public Boolean getDefaultValue() { + return true; + } + }.addAliases("--structure", "-a"); + + /** + * Flag to toggle if world spawn should be adjusted. + */ + public static final CommandFlag SPAWN_ADJUST = new NoValueCommandFlag + ("AdjustSpawn", "--dont-adjust-spawn", Boolean.class) { + @Override + public Boolean getValue() throws FlagParseFailedException { + return false; + } + + @Override + public Boolean getDefaultValue() { + return true; + } + }.addAliases("-n"); + + /** + * Flag to specify a paste service. + */ + public static final CommandFlag PASTE_SERVICE_TYPE = new OptionalCommandFlag + ("PasteServiceType", "--paste", PasteServiceType.class) { + + private final List pasteTypes = Arrays.stream(PasteServiceType.values()) + .filter(pt -> pt != PasteServiceType.NONE) + .map(p -> p.toString().toLowerCase()) + .collect(Collectors.toList()); + + @Override + public Collection suggestValue() { + return pasteTypes; + } + + @Override + public PasteServiceType getValue(@NotNull String input) throws FlagParseFailedException { + try { + return PasteServiceType.valueOf(input.toUpperCase()); + } + catch (IllegalArgumentException e) { + throw new FlagParseFailedException(String.format("Invalid paste service type '%s'.", input)); + } + } + + @Override + public PasteServiceType getValue() throws FlagParseFailedException { + return PasteServiceType.PASTEGG; + } + + @Override + public PasteServiceType getDefaultValue() { + return PasteServiceType.NONE; + } + }.addAliases("-p"); + + /** + * Flag to toggle if plugin list should be included. + */ + public static final CommandFlag INCLUDE_PLUGIN_LIST = new NoValueCommandFlag + ("IncludePlugins", "--include-plugin-list", Boolean.class) { + @Override + public Boolean getValue() throws FlagParseFailedException { + return true; + } + + @Override + public Boolean getDefaultValue() { + return true; + } + }.addAliases("-pl"); +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/FlagGroup.java b/src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/FlagGroup.java new file mode 100644 index 00000000..701d8365 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/FlagGroup.java @@ -0,0 +1,96 @@ +package com.onarandombox.MultiverseCore.commandtools.flag; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * A group of {@link CommandFlag}, with indexed keys for efficient lookup. + */ +public class FlagGroup { + + /** + * Create a new Flag Group with multiple {@link CommandFlag}. + * + * @param flags Multiple flags. + * @return A new {@link FlagGroup} generated from the flags. + */ + public static FlagGroup of(CommandFlag...flags) { + return new FlagGroup(flags); + } + + private final List identifiers; + private final Map> keyMap; + + /** + * Create a new Flag Group with multiple {@link CommandFlag}. + * + * @param commandFlags Array of flags + */ + public FlagGroup(CommandFlag[] commandFlags) { + this.identifiers = new ArrayList<>(commandFlags.length); + this.keyMap = new HashMap<>(); + for (CommandFlag flag : commandFlags) { + addFlag(flag); + } + } + + /** + * Add and indexes a flag. + * + * @param flag The flag to add. + */ + private void addFlag(CommandFlag flag) { + this.identifiers.add(flag.getIdentifier()); + this.keyMap.put(flag.getIdentifier(), flag); + for (String flagAlias : flag.getAliases()) { + this.keyMap.put(flagAlias, flag); + } + } + + /** + * Parse the arguments to get it's flag values. + * + * @param args The arguments to parse. + * @return A {@link FlagResult} containing value results. + * @throws FlagParseFailedException When there is an error parsing, such as invalid format. + */ + @NotNull + public FlagResult calculateResult(String[] args) throws FlagParseFailedException { + return FlagResult.parse(args,this); + } + + /** + * Gets flag from pre-indexed key mapping. + * + * @param key The target key. + * @return A {@link CommandFlag} if found, else null. + */ + @Nullable + public CommandFlag getByKey(String key) { + return this.keyMap.get(key); + } + + /** + * Suggest possible identifiers available for this Flag Group. + * + * @return A collection of identifier strings. + */ + @NotNull + public Collection suggestIdentifiers() { + return identifiers; + } + + @Override + public String toString() { + return "FlagGroup{" + + "flagIdentifiers=" + identifiers + + ", keyFlagMap=" + keyMap + + '}'; + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/FlagParseFailedException.java b/src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/FlagParseFailedException.java new file mode 100644 index 00000000..06efc7f1 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/FlagParseFailedException.java @@ -0,0 +1,27 @@ +package com.onarandombox.MultiverseCore.commandtools.flag; + +/** + * Thrown when there is an issue with parsing flags from string arguments. + */ +//TODO: extend this from ACF CommandArgumentFailed exception class. +public class FlagParseFailedException extends Exception { + + public FlagParseFailedException() { + } + + public FlagParseFailedException(String message, Object...replacements) { + super(String.format(message, replacements)); + } + + public FlagParseFailedException(String message, Throwable cause) { + super(message, cause); + } + + public FlagParseFailedException(Throwable cause) { + super(cause); + } + + public FlagParseFailedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/FlagResult.java b/src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/FlagResult.java new file mode 100644 index 00000000..e3ad74e3 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/FlagResult.java @@ -0,0 +1,198 @@ +package com.onarandombox.MultiverseCore.commandtools.flag; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; + +/** + * Represents the value result parsed from command arguments. + */ +public class FlagResult { + + /** + * Parse arguments into its flag key and values. + * + * @param args The arguments to parse. + * @param flagGroup The flags available to parse into. + * @return The {@link FlagResult} from the parse. + * @throws FlagParseFailedException there is an issue with parsing flags from string arguments. + */ + public static FlagResult parse(@Nullable String[] args, + @NotNull FlagGroup flagGroup) throws FlagParseFailedException { + + FlagResult flagResult = new FlagResult(); + + // No args to parse. + if (args == null || args.length <= 0) { + return flagResult; + } + + // First arg must be a flag. + CommandFlag currentFlag = flagGroup.getByKey(args[0]); + boolean completed = false; + + // Parse the arguments. + for (int i = 1, argsLength = args.length; i <= argsLength; i++) { + if (currentFlag == null) { + throw new FlagParseFailedException("%s is not a valid flag.", args[i-1]); + } + // This ensures that flag is not null during final parse. + if (i >= argsLength) { + break; + } + + String arg = args[i]; + if (arg == null) { + throw new FlagParseFailedException("Arguments cannot be null!"); + } + + CommandFlag nextFlag = flagGroup.getByKey(arg); + + // Arg must be a flag key. + if (currentFlag instanceof NoValueCommandFlag) { + flagResult.add(currentFlag, currentFlag.getValue(), false); + currentFlag = nextFlag; + continue; + } + + // Arg can be a flag key or value. + if (currentFlag instanceof OptionalCommandFlag) { + if (nextFlag != null) { + // It's a key. + flagResult.add(currentFlag, currentFlag.getValue(), false); + currentFlag = nextFlag; + continue; + } + // It's a value. + flagResult.add(currentFlag, currentFlag.getValue(arg), true); + if (i == argsLength - 1) { + completed = true; + break; + } + currentFlag = flagGroup.getByKey(args[++i]); + continue; + } + + // Arg must be a flag value. + if (currentFlag instanceof RequiredCommandFlag) { + if (nextFlag != null) { + // It's a key, error! + throw new FlagParseFailedException("%s flag '%s' requires a value input.", + currentFlag.getName(), currentFlag.getIdentifier()); + } + // It's a value. + flagResult.add(currentFlag, currentFlag.getValue(arg), true); + if (i == argsLength - 1) { + completed = true; + break; + } + currentFlag = flagGroup.getByKey(args[++i]); + } + } + + // Parse last flag. + if (!completed) { + if (currentFlag instanceof RequiredCommandFlag) { + throw new FlagParseFailedException("%s flag '%s' requires a value input.", + currentFlag.getName(), currentFlag.getIdentifier()); + } + flagResult.add(currentFlag, currentFlag.getValue(), false); + } + + return flagResult; + } + + private final Map, SingleFlagResult> resultMap; + + private FlagResult() { + resultMap = new HashMap<>(); + } + + /** + * Add a new value result from parsing arguments. + * + * @param flag The flag that the value represents. + * @param value The value of the flag. + * @param fromInput Denotes if flag was parsed by a user input. + */ + private void add(CommandFlag flag, Object value, boolean fromInput) { + resultMap.put(flag, new SingleFlagResult<>(value, fromInput)); + } + + /** + * Gets value of a flag. + * + * @param flag The flag to get value from. + * @param The type of value. + * @return The value which is associated with the flag. + */ + public T getValue(CommandFlag flag) { + SingleFlagResult result = resultMap.get(flag); + if (result == null) { + return flag.getDefaultValue(); + } + return (T) result.value; + } + + /** + * Gets if the flag value is by a user input. + * + * @param flag The flag to check against. + * @return True if value is by user input, else false. + */ + public boolean isByUserInput(CommandFlag flag) { + SingleFlagResult result = resultMap.get(flag); + if (result == null) { + return false; + } + return result.isFromUserInput; + } + + /** + * Gets if the flag is a default value, and key was not present in user's command arguments. + * i.e. Not in the {@link #resultMap}. + * + * @param flag The flag to check against. + * @return True if flag was not present in user's command arguments, else false. + */ + public boolean isDefaulted(CommandFlag flag) { + return resultMap.get(flag) != null; + } + + @Override + public String toString() { + return "FlagResult{" + + "resultMap=" + resultMap + + '}'; + } + + /** + * Represents a single value result parsed. + * Stores value and addition data such as if value is by user input. + * + * @param The type of value. + */ + private static class SingleFlagResult { + private final T value; + private final boolean isFromUserInput; + + /** + * @param value The resultant value from argument parsing. + * @param fromInput Indicates if value is parsed by user input. + */ + private SingleFlagResult(T value, boolean fromInput) { + this.value = value; + this.isFromUserInput = fromInput; + } + + @Override + public String toString() { + return "SingleFlagResult{" + + "value=" + value + + ", isFromUserInput=" + isFromUserInput + + '}'; + } + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/NoValueCommandFlag.java b/src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/NoValueCommandFlag.java new file mode 100644 index 00000000..51c79747 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/NoValueCommandFlag.java @@ -0,0 +1,39 @@ +package com.onarandombox.MultiverseCore.commandtools.flag; + +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.Collections; + +/** + * This flag will always not require a user input to parse value. + * + * @param The flag Type. + */ +public abstract class NoValueCommandFlag extends CommandFlag { + + /** + * {@inheritDoc} + */ + public NoValueCommandFlag(String name, String identifier, Class type) { + super(name, identifier, type); + } + + /** + * {@link NoValueCommandFlag} will always not require a user input to parse value. + * Thus, no value suggestion needed. + */ + @Override + public final Collection suggestValue() { + return Collections.emptyList(); + } + + /** + * {@link NoValueCommandFlag} will always not require a user input to parse value. + * Thus, this operation is not allowed. + */ + @Override + public final T getValue(@NotNull String input) throws FlagParseFailedException { + throw new FlagParseFailedException("%s flag '%s' does not require a value.", this.name, this.identifier); + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/OptionalCommandFlag.java b/src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/OptionalCommandFlag.java new file mode 100644 index 00000000..cac60a44 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/OptionalCommandFlag.java @@ -0,0 +1,16 @@ +package com.onarandombox.MultiverseCore.commandtools.flag; + +/** + * Command Flag that optionally allows a user input value. + * + * @param The flag Type. + */ +public abstract class OptionalCommandFlag extends CommandFlag { + + /** + * {@inheritDoc} + */ + public OptionalCommandFlag(String name, String identifier, Class type) { + super(name, identifier, type); + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/RequiredCommandFlag.java b/src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/RequiredCommandFlag.java new file mode 100644 index 00000000..bafabd90 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/commandtools/flag/RequiredCommandFlag.java @@ -0,0 +1,25 @@ +package com.onarandombox.MultiverseCore.commandtools.flag; + +/** + * This flag will always require a user input to parse value. + * + * @param The flag Type. + */ +public abstract class RequiredCommandFlag extends CommandFlag { + + /** + * {@inheritDoc} + */ + public RequiredCommandFlag(String name, String identifier, Class type) { + super(name, identifier, type); + } + + /** + * {@link RequiredCommandFlag} will always require a user input to parse value. + * Thus, this operation is not allowed. + */ + @Override + public final T getValue() throws FlagParseFailedException { + throw new FlagParseFailedException("%s flag '%s' requires a value input.", this.name, this.identifier); + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PasteServiceType.java b/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PasteServiceType.java index 09424c0b..fc67310d 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PasteServiceType.java +++ b/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PasteServiceType.java @@ -22,5 +22,9 @@ public enum PasteServiceType { /** * @see GitHubPasteService */ - GITHUB + GITHUB, + /** + * No paste service used. + */ + NONE } diff --git a/src/test/java/com/onarandombox/MultiverseCore/TestWorldStuff.java b/src/test/java/com/onarandombox/MultiverseCore/TestWorldStuff.java index 05957c84..6e063cfa 100644 --- a/src/test/java/com/onarandombox/MultiverseCore/TestWorldStuff.java +++ b/src/test/java/com/onarandombox/MultiverseCore/TestWorldStuff.java @@ -207,7 +207,7 @@ public class TestWorldStuff { assertEquals(0, creator.getCore().getMVWorldManager().getMVWorlds().size()); // Verify - verify(mockCommandSender).sendMessage("Invalid generator! 'BogusGen'. " + ChatColor.RED + "Aborting world creation."); + verify(mockCommandSender).sendMessage("§cError: Invalid generator string 'BogusGen'. See /mv gens for available generators."); } @Test