diff --git a/README.md b/README.md index 9f75e389c5..2235a44bbb 100644 --- a/README.md +++ b/README.md @@ -375,6 +375,7 @@ This is the current roadmap for the CommandAPI (as of 11th May 2023): diff --git a/commandapi-core/src/main/java/dev/jorel/commandapi/CommandAPIExecutor.java b/commandapi-core/src/main/java/dev/jorel/commandapi/CommandAPIExecutor.java index 19d45814bf..afa28015e3 100644 --- a/commandapi-core/src/main/java/dev/jorel/commandapi/CommandAPIExecutor.java +++ b/commandapi-core/src/main/java/dev/jorel/commandapi/CommandAPIExecutor.java @@ -83,7 +83,7 @@ public int execute(ExecutionInfo info) throws Comman } catch (WrapperCommandSyntaxException e) { throw e.getException(); } catch (Throwable ex) { - CommandAPI.getLogger().severe("Unhandled exception executing '" + info.args().getFullInput() + "'", ex); + CommandAPI.getLogger().severe("Unhandled exception executing '" + info.args().fullInput() + "'", ex); if (ex instanceof Exception) { throw ex; } else { @@ -97,7 +97,7 @@ public int execute(ExecutionInfo info) throws Comman } catch (WrapperCommandSyntaxException e) { throw e.getException(); } catch (Throwable ex) { - CommandAPI.getLogger().severe("Unhandled exception executing '" + info.args().getFullInput() + "'", ex); + CommandAPI.getLogger().severe("Unhandled exception executing '" + info.args().fullInput() + "'", ex); if (ex instanceof Exception) { throw ex; } else { diff --git a/commandapi-core/src/main/java/dev/jorel/commandapi/CommandAPIHandler.java b/commandapi-core/src/main/java/dev/jorel/commandapi/CommandAPIHandler.java index 163b2074f1..47730718c6 100644 --- a/commandapi-core/src/main/java/dev/jorel/commandapi/CommandAPIHandler.java +++ b/commandapi-core/src/main/java/dev/jorel/commandapi/CommandAPIHandler.java @@ -23,8 +23,6 @@ import java.awt.Component; import java.io.File; import java.io.IOException; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.VarHandle; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; @@ -102,11 +100,15 @@ public static String getRawArgumentInput(CommandContext parsedArgument = commandContextArguments.get(cmdCtx).get(key); // TODO: Issue #310: Parsing this argument via /execute run doesn't have the value in - // the arguments for this command context (most likely because it's a redirected command). - // We need to figure out how to handle this case. - if(parsedArgument != null) { + // the arguments for this command context (most likely because it's a redirected command). + // We need to figure out how to handle this case. + if (parsedArgument != null) { + // Sanity check: See https://github.com/JorelAli/CommandAPI/wiki/Implementation-details#chatcomponentargument-raw-arguments StringRange range = parsedArgument.getRange(); - return cmdCtx.getInput().substring(range.getStart(), range.getEnd()); + if (range.getEnd() > cmdCtx.getInput().length()) { + range = StringRange.between(range.getStart(), cmdCtx.getInput().length()); + } + return range.get(cmdCtx.getInput()); } else { return ""; } @@ -223,7 +225,7 @@ public AbstractCommandSender senderWrapper() { @Override public CommandArguments args() { - return new CommandArguments(result, new LinkedHashMap<>(), "/" + cmdCtx.getInput()); + return new CommandArguments(result, new LinkedHashMap<>(), result, new LinkedHashMap<>(), "/" + cmdCtx.getInput()); } }; @@ -274,16 +276,30 @@ CommandArguments argsToCommandArgs(CommandContext cmdCtx, Argument[] arg // LinkedHashMap for arguments for executor Map argsMap = new LinkedHashMap<>(); + // List for raw arguments + List rawArguments = new ArrayList<>(); + + // LinkedHashMap for raw arguments + Map rawArgumentsMap = new LinkedHashMap<>(); + // Populate array for (Argument argument : args) { if (argument.isListed()) { - Object parsedArgument = parseArgument(cmdCtx, argument.getNodeName(), argument, new CommandArguments(argList.toArray(), argsMap, "/" + cmdCtx.getInput())); + Object parsedArgument = parseArgument(cmdCtx, argument.getNodeName(), argument, new CommandArguments(argList.toArray(), argsMap, rawArguments.toArray(new String[0]), rawArgumentsMap, "/" + cmdCtx.getInput())); + + // Add the parsed argument argList.add(parsedArgument); argsMap.put(argument.getNodeName(), parsedArgument); + + // Add the raw argument + String rawArgumentString = getRawArgumentInput(cmdCtx, argument.getNodeName()); + + rawArguments.add(rawArgumentString); + rawArgumentsMap.put(argument.getNodeName(), rawArgumentString); } } - return new CommandArguments(argList.toArray(), argsMap, "/" + cmdCtx.getInput()); + return new CommandArguments(argList.toArray(), argsMap, rawArguments.toArray(new String[0]), rawArgumentsMap, "/" + cmdCtx.getInput()); } /** @@ -809,6 +825,12 @@ CommandArguments generatePreviousArguments(CommandContext context, Argum // LinkedHashMap for arguments Map argsMap = new LinkedHashMap<>(); + // List for raw arguments + List rawArguments = new ArrayList<>(); + + // LinkedHashMap for raw arguments + Map rawArgumentsMap = new LinkedHashMap<>(); + for (Argument arg : args) { if (arg.getNodeName().equals(nodeName) && !(arg instanceof Literal)) { break; @@ -816,7 +838,7 @@ CommandArguments generatePreviousArguments(CommandContext context, Argum Object result; try { - result = parseArgument(context, arg.getNodeName(), arg, new CommandArguments(previousArguments.toArray(), argsMap, "/" + context.getInput())); + result = parseArgument(context, arg.getNodeName(), arg, new CommandArguments(previousArguments.toArray(), argsMap, rawArguments.toArray(new String[0]), rawArgumentsMap, "/" + context.getInput())); } catch (IllegalArgumentException e) { /* * Redirected commands don't parse previous arguments properly. Simplest way to @@ -829,11 +851,18 @@ CommandArguments generatePreviousArguments(CommandContext context, Argum result = null; } if (arg.isListed()) { + // Add the parsed argument previousArguments.add(result); argsMap.put(arg.getNodeName(), result); + + // Add the raw argument + String rawArgumentString = getRawArgumentInput(context, arg.getNodeName()); + + rawArguments.add(rawArgumentString); + rawArgumentsMap.put(arg.getNodeName(), rawArgumentString); } } - return new CommandArguments(previousArguments.toArray(), argsMap, "/" + context.getInput()); + return new CommandArguments(previousArguments.toArray(), argsMap, rawArguments.toArray(new String[0]), rawArgumentsMap, "/" + context.getInput()); } SuggestionProvider toSuggestions(Argument theArgument, Argument[] args, diff --git a/commandapi-core/src/main/java/dev/jorel/commandapi/arguments/SuggestionsBranch.java b/commandapi-core/src/main/java/dev/jorel/commandapi/arguments/SuggestionsBranch.java index 413b341062..27a8810f46 100644 --- a/commandapi-core/src/main/java/dev/jorel/commandapi/arguments/SuggestionsBranch.java +++ b/commandapi-core/src/main/java/dev/jorel/commandapi/arguments/SuggestionsBranch.java @@ -79,7 +79,7 @@ private ArgumentSuggestions getNextSuggestion(CommandSender sende if (currentSuggestion != null) { // Validate argument on the path - SuggestionInfo info = new SuggestionInfo<>(sender, new CommandArguments(processedArguments.toArray(), new HashMap<>(), currentInput.toString()), currentInput.toString(), ""); + SuggestionInfo info = new SuggestionInfo<>(sender, new CommandArguments(processedArguments.toArray(), new LinkedHashMap<>(), processedArguments.toArray(new String[0]), new LinkedHashMap<>(), currentInput.toString()), currentInput.toString(), ""); SuggestionsBuilder builder = new SuggestionsBuilder(currentInput.toString(), currentInput.length()); currentSuggestion.suggest(info, builder); if (builder.build().getList().stream().map(Suggestion::getText).noneMatch(currentArgument::equals)) { @@ -184,7 +184,7 @@ private EnforceReplacementsResult enforceReplacements(CommandSender sender, Stri if (currentSuggestion != null) { // Validate argument on the path - SuggestionInfo info = new SuggestionInfo<>(sender, new CommandArguments(processedArguments.toArray(), new HashMap<>(), currentInput.toString()), currentInput.toString(), ""); + SuggestionInfo info = new SuggestionInfo<>(sender, new CommandArguments(processedArguments.toArray(), new LinkedHashMap<>(), processedArguments.toArray(new String[0]), new LinkedHashMap<>(), currentInput.toString()), currentInput.toString(), ""); SuggestionsBuilder builder = new SuggestionsBuilder(currentInput.toString(), currentInput.length()); try { currentSuggestion.suggest(info, builder); diff --git a/commandapi-core/src/main/java/dev/jorel/commandapi/executors/CommandArguments.java b/commandapi-core/src/main/java/dev/jorel/commandapi/executors/CommandArguments.java index 67d4293dce..7fcdcb6519 100644 --- a/commandapi-core/src/main/java/dev/jorel/commandapi/executors/CommandArguments.java +++ b/commandapi-core/src/main/java/dev/jorel/commandapi/executors/CommandArguments.java @@ -2,6 +2,7 @@ import javax.annotation.Nullable; +import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.Optional; @@ -9,36 +10,44 @@ /** * This class stores the arguments for this command + * + * @param args The arguments for this command + * @param argsMap The arguments for this command mapped to their node names. This is an ordered map + * @param rawArgs The raw arguments for this command. + * @param rawArgsMap The raw arguments for this command mapped to their node names. This is an ordered map + * @param fullInput The command string a player has entered (including the /) */ @SuppressWarnings("unchecked") -public class CommandArguments { +public record CommandArguments( - private final Object[] args; - private final Map argsMap; - private final String fullInput; + /** + * @param The arguments for this command + */ + Object[] args, /** - * Constructs a new CommandArguments instance - * - * @param args The arguments for this command - * @param argsMap The arguments for this command mapped to the node names. This is an ordered map - * @param fullInput The raw command a player has entered - */ - public CommandArguments(Object[] args, Map argsMap, String fullInput) { - this.args = args; - this.argsMap = argsMap; - this.fullInput = fullInput; - } - - // Access the inner structure directly + * @param The arguments for this command mapped to their node names. This is an ordered map + */ + Map argsMap, /** - * @return The complete argument array of this command + * @param The raw arguments for this command */ - public Object[] args() { - return args; - } - + String[] rawArgs, + + /** + * @param The raw arguments for this command mapped to their node names. This is an ordered map + */ + Map rawArgsMap, + + /** + * @param The command string a player has entered (including the /) + */ + String fullInput +) { + + // Access the inner structure directly + /** * @return An unmodifiable clone of the mapping of node names to argument values */ @@ -47,7 +56,25 @@ public Map argsMap() { } /** - * @return The number of arguments in this object + * @return An unmodifiable clone of the mapping of node names to raw arguments + */ + public Map rawArgsMap() { + return Collections.unmodifiableMap(rawArgsMap); + } + + /** + * This returns the raw command string a player has entered + * + * @deprecated This method has been deprecated in favour of {@link CommandArguments#fullInput()} + * @return The raw command string a player has entered + */ + @Deprecated(since = "9.0.4", forRemoval = true) + public String getFullInput() { + return fullInput; + } + + /** + * @return The number of arguments for this command */ public int count() { return args.length; @@ -77,31 +104,20 @@ public Object get(int index) { * Returns an argument by its node name * * @param nodeName The node name of this argument. This was set when initializing an argument - * @return An argument which has the given node name. Can be null if nodeName was not found. + * @return An argument which has the given node name. Can be {@code null} if nodeName was not found. */ @Nullable public Object get(String nodeName) { return argsMap.get(nodeName); } - /** - * This returns the raw command string a player has entered - * - * @return The raw command string a player has entered - */ - public String getFullInput() { - return fullInput; - } - /** * Returns an argument by its index * * @param index The position of this argument * @param defaultValue The Object returned if the argument is not existent - * @deprecated This method has been deprecated! Please use {@link CommandArguments#getOptional(int)} * @return An argument which is placed at the given index, or the provided default value */ - @Deprecated(since = "9.0.1", forRemoval = true) public Object getOrDefault(int index, Object defaultValue) { if (args.length <= index) { return defaultValue; @@ -115,10 +131,8 @@ public Object getOrDefault(int index, Object defaultValue) { * * @param nodeName The node name of this argument. This was set when initializing an argument * @param defaultValue The Object returned if the argument was not found. - * @deprecated This method has been deprecated! Please use {@link CommandArguments#getOptional(String)} * @return The argument with the specified node name or the provided default value */ - @Deprecated(since = "9.0.1", forRemoval = true) public Object getOrDefault(String nodeName, Object defaultValue) { return argsMap.getOrDefault(nodeName, defaultValue); } @@ -128,10 +142,8 @@ public Object getOrDefault(String nodeName, Object defaultValue) { * * @param index The position of this argument * @param defaultValue The Object returned if the argument is not existent - * @deprecated This method has been deprecated! Please use {@link CommandArguments#getOptional(int)} * @return An argument which is placed at the given index, or the provided default value */ - @Deprecated(since = "9.0.1", forRemoval = true) public Object getOrDefault(int index, Supplier defaultValue) { if (args.length <= index) { return defaultValue.get(); @@ -145,10 +157,8 @@ public Object getOrDefault(int index, Supplier defaultValue) { * * @param nodeName The node name of this argument. This was set when initializing an argument * @param defaultValue The Object returned if the argument was not found. - * @deprecated This method has been deprecated! Please use {@link CommandArguments#getOptional(String)} * @return The argument with the specified node name or the provided default value */ - @Deprecated(since = "9.0.1", forRemoval = true) public Object getOrDefault(String nodeName, Supplier defaultValue) { return argsMap.getOrDefault(nodeName, defaultValue.get()); } @@ -179,6 +189,159 @@ public Optional getOptional(String nodeName) { } return Optional.of(argsMap.get(nodeName)); } + + /** + * Returns a raw argument by its position + *

+ * A raw argument is the {@link String} form of an argument as written in a command. For example take this command: + *

+ * {@code /mycommand @e 15.3} + *

+ * When using this method to access these arguments, {@code @e} and {@code 15.3} will be available as {@link String}s and not as a {@link Collection} and {@link Double} + * + * @param index The position of this argument + * @return An argument which is placed at the given index, or {@code null} if the provided index does not point to an argument. + */ + @Nullable + public String getRaw(int index) { + if (rawArgs.length <= index) { + return null; + } else { + return rawArgs[index]; + } + } + + /** + * Returns a raw argument by its node name + *

+ * A raw argument is the {@link String} form of an argument as written in a command. For example take this command: + *

+ * {@code /mycommand @e 15.3} + *

+ * When using this method to access these arguments, {@code @e} and {@code 15.3} will be available as {@link String}s and not as a {@link Collection} and {@link Double} + * + * @param nodeName The node name of this argument. This was set when initializing an argument + * @return A raw argument which has the given node name. Can be {@code null} if nodeName was not found. + */ + @Nullable + public String getRaw(String nodeName) { + return rawArgsMap.get(nodeName); + } + + /** + * Returns a raw argument by its index + *

+ * A raw argument is the {@link String} form of an argument as written in a command. For example take this command: + *

+ * {@code /mycommand @e 15.3} + *

+ * When using this method to access these arguments, {@code @e} and {@code 15.3} will be available as {@link String}s and not as a {@link Collection} and {@link Double} + * + * @param index The position of this argument + * @param defaultValue The String returned if the raw argument is not existent + * @return A raw argument which is placed at the given index, or the provided default value + */ + public String getOrDefaultRaw(int index, String defaultValue) { + if (rawArgs.length <= index) { + return defaultValue; + } else { + return rawArgs[index]; + } + } + + /** + * Returns a raw argument by its node name + *

+ * A raw argument is the {@link String} form of an argument as written in a command. For example take this command: + *

+ * {@code /mycommand @e 15.3} + *

+ * When using this method to access these arguments, {@code @e} and {@code 15.3} will be available as {@link String}s and not as a {@link Collection} and {@link Double} + * + * @param nodeName The node name of this argument. This was set when initializing an argument + * @param defaultValue The String returned if the raw argument was not found. + * @return A raw argument with the specified node name or the provided default value + */ + public String getOrDefaultRaw(String nodeName, String defaultValue) { + return rawArgsMap.getOrDefault(nodeName, defaultValue); + } + + /** + * Returns a raw argument by its index + *

+ * A raw argument is the {@link String} form of an argument as written in a command. For example take this command: + *

+ * {@code /mycommand @e 15.3} + *

+ * When using this method to access these arguments, {@code @e} and {@code 15.3} will be available as {@link String}s and not as a {@link Collection} and {@link Double} + * + * @param index The position of this argument + * @param defaultValue The String returned if the raw argument is not existent + * @return A raw argument which is placed at the given index, or the provided default value + */ + public String getOrDefaultRaw(int index, Supplier defaultValue) { + if (rawArgs.length <= index) { + return defaultValue.get(); + } else { + return rawArgs[index]; + } + } + + /** + * Returns a raw argument by its node name + *

+ * A raw argument is the {@link String} form of an argument as written in a command. For example take this command: + *

+ * {@code /mycommand @e 15.3} + *

+ * When using this method to access these arguments, {@code @e} and {@code 15.3} will be available as {@link String}s and not as a {@link Collection} and {@link Double} + * + * @param nodeName The node name of this raw argument. This was set when initializing an argument + * @param defaultValue The String returned if the raw argument was not found. + * @return A raw argument with the specified node name or the provided default value + */ + public String getOrDefaultRaw(String nodeName, Supplier defaultValue) { + return rawArgsMap.getOrDefault(nodeName, defaultValue.get()); + } + + /** + * Returns an {@link Optional} holding the raw argument by its index + *

+ * A raw argument is the {@link String} form of an argument as written in a command. For example take this command: + *

+ * {@code /mycommand @e 15.3} + *

+ * When using this method to access these arguments, {@code @e} and {@code 15.3} will be available as {@link String}s and not as a {@link Collection} and {@link Double} + * + * @param index The position of this argument + * @return An optional holding the raw argument which is placed at the given index, or an empty optional if index is invalid + */ + public Optional getRawOptional(int index) { + if (rawArgs.length <= index) { + return Optional.empty(); + } else { + return Optional.of(rawArgs[index]); + } + } + + /** + * Returns an {@link Optional} holding the raw argument by its node name + *

+ * A raw argument is the {@link String} form of an argument as written in a command. For example take this command: + *

+ * {@code /mycommand @e 15.3} + *

+ * When using this method to access these arguments, {@code @e} and {@code 15.3} will be available as {@link String}s and not as a {@link Collection} and {@link Double} + * + * @param nodeName The node name of this argument. This was set when initializing an argument + * @return An optional holding the argument with the specified node name or an empty optional if the node name was not found + */ + public Optional getRawOptional(String nodeName) { + if (!rawArgsMap.containsKey(nodeName)) { + return Optional.empty(); + } + return Optional.of(rawArgsMap.get(nodeName)); + } /** Unchecked methods. These are the same as the methods above, but use * unchecked generics to conform to the type they are declared as. In Java, @@ -192,14 +355,6 @@ public Optional getOptional(String nodeName) { * CommandArguments args = ...; * String myString = args.getUnchecked("target"); * - * These methods are to be avoided in Kotlin as Kotlin's type inference - * system cannot infer the type variable T by default and would require - * explicit generic type parameters or type declaration, as well as a - * non-null assertion operator: - * - * val args: CommandArguments = ... - * val myString = args.getUnchecked("target")!! // Needs this - * val myString: String = args.getUnchecked(0)!! // Or this */ /** @@ -229,10 +384,8 @@ public T getUnchecked(String nodeName) { * * @param index The position of this argument * @param defaultValue The Object returned if the argument is not existent - * @deprecated This method has been deprecated! Please use {@link CommandArguments#getOptionalUnchecked(int)} * @return An argument which is placed at the given index, or the provided default value */ - @Deprecated(since = "9.0.1", forRemoval = true) public T getOrDefaultUnchecked(int index, T defaultValue) { return (T) getOrDefault(index, defaultValue); } @@ -242,10 +395,8 @@ public T getOrDefaultUnchecked(int index, T defaultValue) { * * @param nodeName The node name of this argument. This was set when initializing an argument * @param defaultValue The Object returned if the argument was not found. - * @deprecated This method has been deprecated! Please use {@link CommandArguments#getOptionalUnchecked(String)} * @return The argument with the specified node name or the provided default value */ - @Deprecated(since = "9.0.1", forRemoval = true) public T getOrDefaultUnchecked(String nodeName, T defaultValue) { return (T) getOrDefault(nodeName, defaultValue); } @@ -255,10 +406,8 @@ public T getOrDefaultUnchecked(String nodeName, T defaultValue) { * * @param index The position of this argument * @param defaultValue The Object returned if the argument is not existent - * @deprecated This method has been deprecated! Please use {@link CommandArguments#getOptionalUnchecked(int)} * @return An argument which is placed at the given index, or the provided default value */ - @Deprecated(since = "9.0.1", forRemoval = true) public T getOrDefaultUnchecked(int index, Supplier defaultValue) { return (T) getOrDefault(index, defaultValue); } @@ -268,10 +417,8 @@ public T getOrDefaultUnchecked(int index, Supplier defaultValue) { * * @param nodeName The node name of this argument. This was set when initializing an argument * @param defaultValue The Object returned if the argument was not found. - * @deprecated This method has been deprecated! Please use {@link CommandArguments#getOptionalUnchecked(String)} * @return The argument with the specified node name or the provided default value */ - @Deprecated(since = "9.0.1", forRemoval = true) public T getOrDefaultUnchecked(String nodeName, Supplier defaultValue) { return (T) getOrDefault(nodeName, defaultValue); } diff --git a/commandapi-documentation-code/src/main/java/dev/jorel/commandapi/examples/java/Examples.java b/commandapi-documentation-code/src/main/java/dev/jorel/commandapi/examples/java/Examples.java index a8de923b2a..ba15367fc0 100644 --- a/commandapi-documentation-code/src/main/java/dev/jorel/commandapi/examples/java/Examples.java +++ b/commandapi-documentation-code/src/main/java/dev/jorel/commandapi/examples/java/Examples.java @@ -104,8 +104,8 @@ void advancementArgument() { .withArguments(new PlayerArgument("player")) .withArguments(new AdvancementArgument("advancement")) .executes((sender, args) -> { - Player target = (Player) args.get(0); - Advancement advancement = (Advancement) args.get(1); + Player target = (Player) args.get("player"); + Advancement advancement = (Advancement) args.get("advancement"); // Award all criteria for the advancement AdvancementProgress progress = target.getAdvancementProgress(advancement); @@ -151,7 +151,7 @@ void argument_angle() { .withArguments(new AngleArgument("amount")) .executesPlayer((player, args) -> { Location newLocation = player.getLocation(); - newLocation.setYaw((float) args.get(0)); + newLocation.setYaw((float) args.get("amount")); player.teleport(newLocation); }) .register(); @@ -163,7 +163,7 @@ void argument_biome() { new CommandAPICommand("setbiome") .withArguments(new BiomeArgument("biome")) .executesPlayer((player, args) -> { - Biome biome = (Biome) args.get(0); + Biome biome = (Biome) args.get("biome"); Chunk chunk = player.getLocation().getChunk(); player.getWorld().setBiome(chunk.getX(), player.getLocation().getBlockY(), chunk.getZ(), biome); @@ -187,10 +187,10 @@ void argument_blockPredicate() { .executesPlayer((player, args) -> { // Parse the arguments - int radius = (int) args.get(0); + int radius = (int) args.get("radius"); @SuppressWarnings("unchecked") - Predicate predicate = (Predicate) args.get(1); - BlockData blockData = (BlockData) args.get(2); + Predicate predicate = (Predicate) args.get("fromBlock"); + BlockData blockData = (BlockData) args.get("toBlock"); // Find a (solid) sphere of blocks around the player with a given radius Location center = player.getLocation(); @@ -220,7 +220,7 @@ void argument_blockState() { new CommandAPICommand("set") .withArguments(new BlockStateArgument("block")) .executesPlayer((player, args) -> { - BlockData blockdata = (BlockData) args.get(0); + BlockData blockdata = (BlockData) args.get("block"); Block targetBlock = player.getTargetBlockExact(256); // Set the block, along with its data @@ -239,10 +239,10 @@ void argument_chatAdventure() { .withArguments(new StringArgument("author")) .withArguments(new AdventureChatComponentArgument("contents")) .executes((sender, args) -> { - Player target = (Player) args.get(0); - String title = (String) args.get(1); - String author = (String) args.get(2); - Component content = (Component) args.get(3); + Player target = (Player) args.get("target"); + String title = (String) args.get("title"); + String author = (String) args.get("author"); + Component content = (Component) args.get("contents"); // Create a book and show it to the user (Requires Paper) Book mybook = Book.book(Component.text(title), Component.text(author), content); @@ -255,7 +255,7 @@ void argument_chatAdventure() { new CommandAPICommand("pbroadcast") .withArguments(new AdventureChatArgument("message")) .executes((sender, args) -> { - Component message = (Component) args.get(0); + Component message = (Component) args.get("message"); // Broadcast the message to everyone with broadcast permissions. Bukkit.getServer().broadcast(message, Server.BROADCAST_CHANNEL_USERS); @@ -271,7 +271,7 @@ void argument_chats(){ new CommandAPICommand("namecolor") .withArguments(new ChatColorArgument("chatcolor")) .executesPlayer((player, args) -> { - ChatColor color = (ChatColor) args.get(0); + ChatColor color = (ChatColor) args.get("chatcolor"); player.setDisplayName(color + player.getName()); }) .register(); @@ -284,8 +284,8 @@ void argument_chatSpigot() { .withArguments(new PlayerArgument("player")) .withArguments(new ChatComponentArgument("contents")) .executes((sender, args) -> { - Player player = (Player) args.get(0); - BaseComponent[] arr = (BaseComponent[]) args.get(1); + Player player = (Player) args.get("player"); + BaseComponent[] arr = (BaseComponent[]) args.get("contents"); // Create book ItemStack is = new ItemStack(Material.WRITTEN_BOOK); @@ -305,7 +305,7 @@ void argument_chatSpigot() { new CommandAPICommand("pbroadcast") .withArguments(new ChatArgument("message")) .executes((sender, args) -> { - BaseComponent[] message = (BaseComponent[]) args.get(0); + BaseComponent[] message = (BaseComponent[]) args.get("message"); // Broadcast the message to everyone on the server Bukkit.getServer().spigot().broadcast(message); @@ -320,8 +320,8 @@ void argument_command() { .withArguments(new PlayerArgument("target")) .withArguments(new CommandArgument("command")) .executes((sender, args) -> { - Player target = (Player) args.get(0); - CommandResult command = (CommandResult) args.get(1); + Player target = (Player) args.get("target"); + CommandResult command = (CommandResult) args.get("command"); command.execute(target); }) @@ -408,7 +408,7 @@ public Argument customWorldArgument(String nodeName) { new CommandAPICommand("tpworld") .withArguments(customWorldArgument("world")) .executesPlayer((player, args) -> { - player.teleport(((World) args.get(0)).getSpawnLocation()); + player.teleport(((World) args.get("world")).getSpawnLocation()); }) .register(); /* ANCHOR_END: argumentCustom2 */ @@ -421,8 +421,8 @@ void argument_enchantment() { .withArguments(new EnchantmentArgument("enchantment")) .withArguments(new IntegerArgument("level", 1, 5)) .executesPlayer((player, args) -> { - Enchantment enchantment = (Enchantment) args.get(0); - int level = (int) args.get(1); + Enchantment enchantment = (Enchantment) args.get("enchantment"); + int level = (int) args.get("level"); // Add the enchantment player.getInventory().getItemInMainHand().addEnchantment(enchantment, level); @@ -439,7 +439,7 @@ void argument_entities() { .executes((sender, args) -> { // Parse the argument as a collection of entities (as stated above in the documentation) @SuppressWarnings("unchecked") - Collection entities = (Collection) args.get(0); + Collection entities = (Collection) args.get("entities"); sender.sendMessage("Removed " + entities.size() + " entities"); for (Entity e : entities) { @@ -454,8 +454,8 @@ void argument_entities() { .withArguments(new EntityTypeArgument("entity")) .withArguments(new IntegerArgument("amount", 1, 100)) // Prevent spawning too many entities .executesPlayer((Player player, CommandArguments args) -> { - for (int i = 0; i < (int) args.get(1); i++) { - player.getWorld().spawnEntity(player.getLocation(), (EntityType) args.get(0)); + for (int i = 0; i < (int) args.get("amount"); i++) { + player.getWorld().spawnEntity(player.getLocation(), (EntityType) args.get("entity")); } }) .register(); @@ -467,7 +467,7 @@ void argument_function() { new CommandAPICommand("runfunction") .withArguments(new FunctionArgument("function")) .executes((sender, args) -> { - FunctionWrapper[] functions = (FunctionWrapper[]) args.get(0); + FunctionWrapper[] functions = (FunctionWrapper[]) args.get("function"); // Run all functions in our FunctionWrapper[] for (FunctionWrapper function : functions) { @@ -481,9 +481,9 @@ void argument_function() { void argument_itemStack() { /* ANCHOR: argumentItemStack1 */ new CommandAPICommand("item") - .withArguments(new ItemStackArgument("itemstack")) + .withArguments(new ItemStackArgument("itemStack")) .executesPlayer((player, args) -> { - player.getInventory().addItem((ItemStack) args.get(0)); + player.getInventory().addItem((ItemStack) args.get("itemStack")); }) .register(); /* ANCHOR_END: argumentItemStack1 */ @@ -498,7 +498,7 @@ void argument_itemStackPredicate() { // Get our predicate @SuppressWarnings("unchecked") - Predicate predicate = (Predicate) args.get(0); + Predicate predicate = (Predicate) args.get("items"); for (ItemStack item : player.getInventory()) { if (predicate.test(item)) { @@ -520,8 +520,8 @@ void argument_list() { .buildGreedy() ) .executesPlayer((player, args) -> { - int amount = (int) args.get(0); - List theList = (List) args.get(1); + int amount = (int) args.get("amount"); + List theList = (List) args.get("materials"); for (Material item : theList) { player.getInventory().addItem(new ItemStack(item, amount)); @@ -592,7 +592,7 @@ void argument_locations() { // We want to target blocks in particular, so use BLOCK_POSITION .withArguments(new LocationArgument("block", LocationType.BLOCK_POSITION)) .executesPlayer((player, args) -> { - Location location = (Location) args.get(0); + Location location = (Location) args.get("block"); location.getBlock().setType(Material.AIR); }) .register(); @@ -602,11 +602,11 @@ void argument_locations() { void argument_lootTable() { /* ANCHOR: argumentLootTable1 */ new CommandAPICommand("giveloottable") - .withArguments(new LootTableArgument("loottable")) + .withArguments(new LootTableArgument("lootTable")) .withArguments(new LocationArgument("location", LocationType.BLOCK_POSITION)) .executes((sender, args) -> { - LootTable lootTable = (LootTable) args.get(0); - Location location = (Location) args.get(1); + LootTable lootTable = (LootTable) args.get("lootTable"); + Location location = (Location) args.get("location"); BlockState state = location.getBlock().getState(); @@ -666,9 +666,9 @@ void argument_mathOperation() { .withArguments(new MathOperationArgument("operation")) .withArguments(new IntegerArgument("value")) .executes((sender, args) -> { - Player target = (Player) args.get(0); - MathOperation op = (MathOperation) args.get(1); - int value = (int) args.get(2); + Player target = (Player) args.get("player"); + MathOperation op = (MathOperation) args.get("operation"); + int value = (int) args.get("value"); target.setLevel(op.apply(target.getLevel(), value)); }) @@ -683,7 +683,7 @@ void argument_multiLiteral() { .withArguments(new MultiLiteralArgument("gamemodes", "adventure", "creative", "spectator", "survival")) .executesPlayer((player, args) -> { // The literal string that the player enters IS available in the args[] - switch((String) args.get(0)) { + switch ((String) args.get("gamemodes")) { case "adventure": player.setGameMode(GameMode.ADVENTURE); break; @@ -697,7 +697,7 @@ void argument_multiLiteral() { player.setGameMode(GameMode.SURVIVAL); break; default: - player.sendMessage("Invalid gamemode: " + args.get(0)); + player.sendMessage("Invalid gamemode: " + args.get("gamemodes")); break; } }) @@ -720,7 +720,7 @@ void argument_nbt2() { new CommandAPICommand("award") .withArguments(new NBTCompoundArgument("nbt")) .executes((sender, args) -> { - NBTContainer nbt = (NBTContainer) args.get(0); + NBTContainer nbt = (NBTContainer) args.get("nbt"); // Do something with "nbt" here... }) @@ -734,7 +734,7 @@ void argument_objectives() { new CommandAPICommand("sidebar") .withArguments(new ObjectiveArgument("objective")) .executes((sender, args) -> { - Objective objective = (Objective) args.get(0); + Objective objective = (Objective) args.get("objective"); // Set display slot objective.setDisplaySlot(DisplaySlot.SIDEBAR); @@ -746,7 +746,7 @@ void argument_objectives() { new CommandAPICommand("unregisterall") .withArguments(new ObjectiveCriteriaArgument("objective criteria")) .executes((sender, args) -> { - String objectiveCriteria = (String) args.get(0); + String objectiveCriteria = (String) args.get("objective criteria"); Set objectives = Bukkit.getScoreboardManager().getMainScoreboard().getObjectivesByCriteria(objectiveCriteria); // Unregister the objectives @@ -764,7 +764,7 @@ void argument_particle() { new CommandAPICommand("showparticle") .withArguments(new ParticleArgument("particle")) .executesPlayer((player, args) -> { - ParticleData particleData = (ParticleData) args.get(0); + ParticleData particleData = (ParticleData) args.get("particle"); player.getWorld().spawnParticle(particleData.particle(), player.getLocation(), 1); }) .register(); @@ -774,7 +774,7 @@ void argument_particle() { new CommandAPICommand("showparticle") .withArguments(new ParticleArgument("particle")) .executesPlayer((player, args) -> { - ParticleData particleData = (ParticleData) args.get(0); + ParticleData particleData = (ParticleData) args.get("particle"); player.getWorld().spawnParticle(particleData.particle(), player.getLocation(), 1, particleData.data()); }) .register(); @@ -790,10 +790,10 @@ void argument_potion() { .withArguments(new TimeArgument("duration")) .withArguments(new IntegerArgument("strength")) .executes((sender, args) -> { - Player target = (Player) args.get(0); - PotionEffectType potion = (PotionEffectType) args.get(1); - int duration = (int) args.get(2); - int strength = (int) args.get(3); + Player target = (Player) args.get("target"); + PotionEffectType potion = (PotionEffectType) args.get("potion"); + int duration = (int) args.get("duration"); + int strength = (int) args.get("strength"); // Add the potion effect to the target player target.addPotionEffect(new PotionEffect(potion, duration, strength)); @@ -814,7 +814,7 @@ void argument_primitives() { .withArguments(new BooleanArgument("value")) .executes((sender, args) -> { // Update the config with the boolean argument - getConfig().set((String) args.get(0), (boolean) args.get(1)); + getConfig().set((String) args.get("config-key"), (boolean) args.get("value")); }) .register(); /* ANCHOR_END: argumentPrimitives1 */ @@ -827,8 +827,8 @@ void argument_range() { .withArguments(new ItemStackArgument("item")) // The item to search for .executesPlayer((player, args) -> { // Retrieve the range from the arguments - IntegerRange range = (IntegerRange) args.get(0); - ItemStack itemStack = (ItemStack) args.get(1); + IntegerRange range = (IntegerRange) args.get("range"); + ItemStack itemStack = (ItemStack) args.get("item"); // Store the locations of chests with certain items List locations = new ArrayList<>(); @@ -878,7 +878,7 @@ void argument_recipe() { new CommandAPICommand("giverecipe") .withArguments(new RecipeArgument("recipe")) .executesPlayer((player, args) -> { - ComplexRecipe recipe = (ComplexRecipe) args.get(0); + ComplexRecipe recipe = (ComplexRecipe) args.get("recipe"); player.getInventory().addItem(recipe.getResult()); }) .register(); @@ -889,8 +889,8 @@ void argument_recipe() { .withArguments(new PlayerArgument("player")) .withArguments(new RecipeArgument("recipe")) .executes((sender, args) -> { - Player target = (Player) args.get(0); - ComplexRecipe recipe = (ComplexRecipe) args.get(1); + Player target = (Player) args.get("player"); + ComplexRecipe recipe = (ComplexRecipe) args.get("recipe"); target.discoverRecipe(recipe.getKey()); }) @@ -904,8 +904,8 @@ void argument_rotation() { .withArguments(new RotationArgument("rotation")) .withArguments(new EntitySelectorArgument.OneEntity("target")) .executes((sender, args) -> { - Rotation rotation = (Rotation) args.get(0); - Entity target = (Entity) args.get(1); + Rotation rotation = (Rotation) args.get("rotation"); + Entity target = (Entity) args.get("target"); if (target instanceof ArmorStand armorStand) { armorStand.setHeadPose(new EulerAngle(Math.toRadians(rotation.getPitch()), Math.toRadians(rotation.getYaw() - 90), 0)); @@ -923,7 +923,7 @@ void argument_scoreboards() { .executes((sender, args) -> { // Get player names by casting to Collection @SuppressWarnings("unchecked") - Collection players = (Collection) args.get(0); + Collection players = (Collection) args.get("players"); for (String playerName : players) { Bukkit.getPlayer(playerName).getInventory().addItem(new ItemStack(Material.DIAMOND, 3)); @@ -937,7 +937,7 @@ void argument_scoreboards() { .withArguments(new ScoreboardSlotArgument("slot")) .executes((sender, args) -> { Scoreboard scoreboard = Bukkit.getScoreboardManager().getMainScoreboard(); - DisplaySlot slot = ((ScoreboardSlot) args.get(0)).getDisplaySlot(); + DisplaySlot slot = ((ScoreboardSlot) args.get("slot")).getDisplaySlot(); scoreboard.clearSlot(slot); }) .register(); @@ -949,7 +949,7 @@ void argument_sound() { new CommandAPICommand("sound") .withArguments(new SoundArgument("sound")) .executesPlayer((player, args) -> { - player.getWorld().playSound(player.getLocation(), (Sound) args.get(0), 100.0f, 1.0f); + player.getWorld().playSound(player.getLocation(), (Sound) args.get("sound"), 100.0f, 1.0f); }) .register(); /* ANCHOR_END: argumentSound1 */ @@ -958,7 +958,7 @@ void argument_sound() { new CommandAPICommand("sound") .withArguments(new SoundArgument.NamespacedKey("sound")) .executesPlayer((player, args) -> { - player.getWorld().playSound(player.getLocation(), ((NamespacedKey) args.get(0)).asString(), 100.0f, 1.0f); + player.getWorld().playSound(player.getLocation(), ((NamespacedKey) args.get("sound")).asString(), 100.0f, 1.0f); }) .register(); /* ANCHOR_END: argumentSound2 */ @@ -970,7 +970,7 @@ void argument_strings() { .withArguments(new PlayerArgument("target")) .withArguments(new GreedyStringArgument("message")) .executes((sender, args) -> { - ((Player) args.get(0)).sendMessage((String) args.get(1)); + ((Player) args.get("target")).sendMessage((String) args.get("message")); }) .register(); /* ANCHOR_END: argumentStrings1 */ @@ -981,7 +981,7 @@ void argument_team() { new CommandAPICommand("togglepvp") .withArguments(new TeamArgument("team")) .executes((sender, args) -> { - Team team = (Team) args.get(0); + Team team = (Team) args.get("team"); // Toggle pvp team.setAllowFriendlyFire(team.allowFriendlyFire()); @@ -998,8 +998,8 @@ void argument_time() { .withArguments(new GreedyStringArgument("message")) .executes((sender, args) -> { // Duration in ticks - int duration = (int) args.get(0); - String message = (String) args.get(1); + int duration = (int) args.get("duration"); + String message = (String) args.get("message"); for (Player player : Bukkit.getOnlinePlayers()) { // Display the message to all players, with the default fade in/out times (10 and 20). @@ -1015,7 +1015,7 @@ void argument_world() { new CommandAPICommand("unloadworld") .withArguments(new WorldArgument("world")) .executes((sender, args) -> { - World world = (World) args.get(0); + World world = (World) args.get("world"); // Unload the world (and save the world's chunks) Bukkit.getServer().unloadWorld(world, true); @@ -1062,9 +1062,9 @@ void arguments() { new CommandAPICommand("cmd") .withArguments(commandArguments) .executes((sender, args) -> { - String stringArg = (String) args.get(0); - PotionEffectType potionArg = (PotionEffectType) args.get(1); - Location locationArg = (Location) args.get(2); + String stringArg = (String) args.get("arg0"); + PotionEffectType potionArg = (PotionEffectType) args.get("arg1"); + Location locationArg = (Location) args.get("arg2"); }) .register(); /* ANCHOR_END: arguments4 */ @@ -1081,8 +1081,8 @@ void asyncSuggestions() { }))) .withArguments(new TextArgument("value")) .executes((sender, args) -> { - String key = (String) args.get(0); - String value = (String) args.get(1); + String key = (String) args.get("key"); + String value = (String) args.get("value"); plugin.getConfig().set(key, value); }) .register(); @@ -1181,7 +1181,7 @@ void brigadierSuggestions() { new CommandAPICommand("emoji") .withArguments(messageArgument) .executes((sender, args) -> { - Bukkit.broadcastMessage((String) args.get(0)); + Bukkit.broadcastMessage((String) args.get("message")); }) .register(); /* ANCHOR_END: brigadierSuggestions1 */ @@ -1234,7 +1234,7 @@ void brigadierSuggestions() { .withArguments(new GreedyStringArgument("command").replaceSuggestions(commandSuggestions)) .executes((sender, args) -> { // Run the command using Bukkit.dispatchCommand() - Bukkit.dispatchCommand(sender, (String) args.get(0)); + Bukkit.dispatchCommand(sender, (String) args.get("command")); }).register(); /* ANCHOR_END: brigadierSuggestions3 */ } @@ -1252,7 +1252,7 @@ void chatPreview() { .executesPlayer((player, args) -> { // The user still entered legacy text. We need to properly convert this // to a BaseComponent[] by converting to plain text then to BaseComponent[] - String plainText = BaseComponent.toPlainText((BaseComponent[]) args.get(0)); + String plainText = BaseComponent.toPlainText((BaseComponent[]) args.get("message")); Bukkit.spigot().broadcast(TextComponent.fromLegacyText(ChatColor.translateAlternateColorCodes('&', plainText))); }) .register(); @@ -1270,7 +1270,7 @@ void chatPreview() { .executesPlayer((player, args) -> { // The user still entered legacy text. We need to properly convert this // to a Component by converting to plain text then to Component - String plainText = PlainTextComponentSerializer.plainText().serialize((Component) args.get(0)); + String plainText = PlainTextComponentSerializer.plainText().serialize((Component) args.get("broadcast")); Bukkit.broadcast(LegacyComponentSerializer.legacyAmpersand().deserialize(plainText)); }) .register(); @@ -1286,7 +1286,7 @@ void chatPreview() { return TextComponent.fromLegacyText(ChatColor.translateAlternateColorCodes('&', plainText)); })) .executesPlayer((player, args) -> { - Bukkit.spigot().broadcast((BaseComponent[]) args.get(0)); + Bukkit.spigot().broadcast((BaseComponent[]) args.get("message")); }) .register(); /* ANCHOR_END: chatPreview3 */ @@ -1301,12 +1301,55 @@ void chatPreview() { return LegacyComponentSerializer.legacyAmpersand().deserialize(plainText); })) .executesPlayer((player, args) -> { - Bukkit.broadcast((Component) args.get(0)); + Bukkit.broadcast((Component) args.get("message")); }) .register(); /* ANCHOR_END: chatPreview4 */ } +void commandArguments() { +/* ANCHOR: commandArguments1 */ +new CommandAPICommand("mycommand") + .withArguments(new StringArgument("name")) + .withArguments(new IntegerArgument("amount")) + .withOptionalArguments(new PlayerArgument("player")) + .withOptionalArguments(new PlayerArgument("target")) + .withOptionalArguments(new GreedyStringArgument("message")) + .executesPlayer((player, args) -> { + String name = (String) args.get(0); // Access arguments by index + int amount = (int) args.get("amount"); // Access arguments by node name + Player p = (Player) args.getOrDefault("player", player); // Access arguments using the getOrDefault(String, Object) method + Player target = (Player) args.getOrDefault("target", () -> player); // Access arguments using the getOrDefault(String, Supplier) method + String message = (String) args.getOptional("message").orElse("Hello!"); // Access arguments using the getOptional(String) method + + // Do whatever with these values + }) + .register(); +/* ANCHOR_END: commandArguments1 */ + +/* ANCHOR: commandArguments2 */ +new CommandAPICommand("mycommand") + .withArguments(new EntitySelectorArgument.ManyEntities("entities")) + .executesPlayer((player, args) -> { + String entitySelector = args.getRaw("entities"); // Access the raw argument with getRaw(String) + + // Do whatever with the entity selector + }) + .register(); +/* ANCHOR_END: commandArguments2 */ + +/* ANCHOR: commandArguments3 */ +new CommandAPICommand("mycommand") + .withArguments(new PlayerArgument("player")) + .executesPlayer((player, args) -> { + Player p = args.getUnchecked("player"); + + // Do whatever with the player + }) + .register(); +/* ANCHOR_END: commandArguments3 */ +} + void commandFailures() { /* ANCHOR: commandFailures1 */ // Array of fruit @@ -1316,7 +1359,7 @@ void commandFailures() { new CommandAPICommand("getfruit") .withArguments(new StringArgument("item").replaceSuggestions(ArgumentSuggestions.strings(fruit))) .executes((sender, args) -> { - String inputFruit = (String) args.get(0); + String inputFruit = (String) args.get("item"); if (Arrays.stream(fruit).anyMatch(inputFruit::equals)) { // Do something with inputFruit @@ -1337,7 +1380,7 @@ void commandRegistration() { .withAliases("broadcast", "broadcastmessage") // Command aliases .withPermission(CommandPermission.OP) // Required permissions .executes((sender, args) -> { - String message = (String) args.get(0); + String message = (String) args.get("message"); Bukkit.getServer().broadcastMessage(message); }) .register(); @@ -1366,7 +1409,7 @@ class commandTrees extends JavaPlugin { }) .then(new PlayerArgument("target") .executes((sender, args) -> { - Player target = (Player) args.get(0); + Player target = (Player) args.get("target"); target.sendMessage("Hi"); })) .register(); @@ -1380,8 +1423,8 @@ class commandTrees extends JavaPlugin { .executesPlayer((player, args) -> { // /signedit set Sign sign = getTargetSign(player); - int lineNumber = (int) args.get(0); - String text = (String) args.get(1); + int lineNumber = (int) args.get("line_number"); + String text = (String) args.get("text"); sign.setLine(lineNumber - 1, text); sign.update(true); })))) @@ -1390,7 +1433,7 @@ class commandTrees extends JavaPlugin { .executesPlayer((player, args) -> { // /signedit clear Sign sign = getTargetSign(player); - int lineNumber = (int) args.get(0); + int lineNumber = (int) args.get("line_number"); sign.setLine(lineNumber - 1, ""); sign.update(true); }))) @@ -1399,7 +1442,7 @@ class commandTrees extends JavaPlugin { .executesPlayer((player, args) -> { // /signedit copy Sign sign = getTargetSign(player); - int lineNumber = (int) args.get(0); + int lineNumber = (int) args.get("line_number"); player.setMetadata("copied_sign_text", new FixedMetadataValue(this, sign.getLine(lineNumber - 1))); }))) .then(new LiteralArgument("paste") @@ -1407,7 +1450,7 @@ class commandTrees extends JavaPlugin { .executesPlayer((player, args) -> { // /signedit copy Sign sign = getTargetSign(player); - int lineNumber = (int) args.get(0); + int lineNumber = (int) args.get("line_number"); sign.setLine(lineNumber - 1, player.getMetadata("copied_sign_text").get(0).asString()); sign.update(true); }))) @@ -1493,7 +1536,7 @@ void functionWrapper() { new CommandAPICommand("runfunc") .withArguments(new FunctionArgument("function")) .executes((sender, args) -> { - FunctionWrapper[] functions = (FunctionWrapper[]) args.get(0); + FunctionWrapper[] functions = (FunctionWrapper[]) args.get("function"); for (FunctionWrapper function : functions) { function.run(); // The command executor in this case is 'sender' } @@ -1531,8 +1574,8 @@ void listed() { .withArguments(new GreedyStringArgument("message")) .executes((sender, args) -> { // args == [player, message] - Player player = (Player) args.get(0); - String message = (String) args.get(1); // Note that this is args.get(1) and NOT args.get(2) + Player player = (Player) args.get("player"); + String message = (String) args.get("message"); // Note that the IntegerArgument is not available in the CommandArguments player.sendMessage(message); }) .register(); @@ -1560,7 +1603,7 @@ void normalExecutors() { .withAliases("broadcast", "broadcastmessage") // Command aliases .withPermission(CommandPermission.OP) // Required permissions .executes((sender, args) -> { - String message = (String) args.get(0); + String message = (String) args.get("message"); Bukkit.getServer().broadcastMessage(message); }) .register(); @@ -1690,7 +1733,7 @@ void permissions() { new CommandAPICommand("kill") .withArguments(new PlayerArgument("target").withPermission(CommandPermission.OP)) .executesPlayer((player, args) -> { - ((Player) args.get(0)).setHealth(0); + ((Player) args.get("target")).setHealth(0); }) .register(); /* ANCHOR_END: permissions4 */ @@ -1709,9 +1752,9 @@ void permissions() { .withPermission("economy.other") // The important part of this example .withArguments(new PlayerArgument("target")) .executesPlayer((player, args) -> { - Player target = (Player) args.get(0); + Player target = (Player) args.get("target"); - // Send a message to the executor with the the target's balance + // Send a message to the executor with the target's balance player.sendMessage(target.getName() + "'s balance: " + Economy.getBalance(target)); }) .register(); @@ -1722,8 +1765,8 @@ void permissions() { .withArguments(new PlayerArgument("target")) .withArguments(new DoubleArgument("amount")) .executesPlayer((player, args) -> { - Player target = (Player) args.get(0); - double amount = (Double) args.get(1); + Player target = (Player) args.get("target"); + double amount = (Double) args.get("amount"); // Update the target player's balance Economy.updateBalance(target, amount); @@ -1735,7 +1778,7 @@ void permissions() { .withPermission("economy.admin.reset") // The important part of this example .withArguments(new PlayerArgument("target")) .executesPlayer((player, args) -> { - Player target = (Player) args.get(0); + Player target = (Player) args.get("target"); // Reset target balance here Economy.resetBalance(target); @@ -1847,7 +1890,7 @@ void requirements() { .executesPlayer((player, args) -> { // Get the name of the party to create - String partyName = (String) args.get(0); + String partyName = (String) args.get("partyName"); partyMembers.put(player.getUniqueId(), partyName); }) @@ -1894,7 +1937,7 @@ void requirements() { new CommandAPICommand("party") .withArguments(arguments) .executesPlayer((player, args) -> { - Player target = (Player) args.get(0); + Player target = (Player) args.get("player"); player.teleport(target); }) .register(); @@ -1906,7 +1949,7 @@ void requirements() { .executesPlayer((player, args) -> { // Get the name of the party to create - String partyName = (String) args.get(0); + String partyName = (String) args.get("partyName"); partyMembers.put(player.getUniqueId(), partyName); @@ -1950,7 +1993,7 @@ void resultingCommandExecutors() { new CommandAPICommand("givereward") .withArguments(new EntitySelectorArgument.OnePlayer("target")) .executes((sender, args) -> { - Player player = (Player) args.get(0); + Player player = (Player) args.get("target"); player.getInventory().addItem(new ItemStack(Material.DIAMOND, 64)); Bukkit.broadcastMessage(player.getName() + " won a rare 64 diamonds from a loot box!"); }) @@ -1993,7 +2036,7 @@ void safeArgumentSuggestions() { new CommandAPICommand("giverecipe") .withArguments(arguments) .executesPlayer((player, args) -> { - Recipe recipe = (Recipe) args.get(0); + Recipe recipe = (Recipe) args.get("recipe"); player.getInventory().addItem(recipe.getResult()); }) .register(); @@ -2024,7 +2067,7 @@ void safeArgumentSuggestions() { new CommandAPICommand("spawnmob") .withArguments(safeArguments) .executesPlayer((player, args) -> { - EntityType entityType = (EntityType) args.get(0); + EntityType entityType = (EntityType) args.get("mob"); player.getWorld().spawnEntity(player.getLocation(), entityType); }) .register(); @@ -2049,8 +2092,8 @@ void safeArgumentSuggestions() { new CommandAPICommand("removeeffect") .withArguments(safeArgs) .executesPlayer((player, args) -> { - Player target = (Player) args.get(0); - PotionEffectType potionEffect = (PotionEffectType) args.get(1); + Player target = (Player) args.get("target"); + PotionEffectType potionEffect = (PotionEffectType) args.get("potioneffect"); target.removePotionEffect(potionEffect); }) .register(); @@ -2108,7 +2151,7 @@ class stringArgumentSuggestions { new CommandAPICommand("warp") .withArguments(arguments) .executesPlayer((player, args) -> { - String warp = (String) args.get(0); + String warp = (String) args.get("world"); player.teleport(warps.get(warp)); // Look up the warp in a map, for example }) .register(); @@ -2141,7 +2184,7 @@ public static String[] getFriends(CommandSender sender) { new CommandAPICommand("friendtp") .withArguments(arguments) .executesPlayer((player, args) -> { - Player target = (Player) args.get(0); + Player target = (Player) args.get("friend"); player.teleport(target); }) .register(); @@ -2158,7 +2201,7 @@ public static String[] getFriends(CommandSender sender) { commandArgs.add(new PlayerArgument("target").replaceSuggestions(ArgumentSuggestions.strings(info -> { // Cast the first argument (radius, which is an IntegerArgument) to get its value - int radius = (int) info.previousArgs().get(0); + int radius = (int) info.previousArgs().get("radius"); // Get nearby entities within the provided radius Player player = (Player) info.sender(); @@ -2176,8 +2219,8 @@ public static String[] getFriends(CommandSender sender) { new CommandAPICommand("localmsg") .withArguments(commandArgs) .executesPlayer((player, args) -> { - Player target = (Player) args.get(1); - String message = (String) args.get(2); + Player target = (Player) args.get("target"); + String message = (String) args.get("message"); target.sendMessage(message); }) .register(); @@ -2272,10 +2315,10 @@ class tooltips { new CommandAPICommand("emote") .withArguments(arguments) .executesPlayer((player, args) -> { - String emote = (String) args.get(0); - Player target = (Player) args.get(1); + String emote = (String) args.get("emote"); + Player target = (Player) args.get("target"); - switch(emote) { + switch (emote) { case "wave": target.sendMessage(player.getName() + " waves at you!"); break; @@ -2341,7 +2384,7 @@ public Message getTooltip() { new CommandAPICommand("giveitem") .withArguments(new StringArgument("item").replaceSuggestions(ArgumentSuggestions.stringsWithTooltips(customItems))) // We use customItems[] as the input for our suggestions with tooltips .executesPlayer((player, args) -> { - String itemName = (String) args.get(0); + String itemName = (String) args.get("item"); // Give them the item for (CustomItem item : customItems) { @@ -2372,7 +2415,7 @@ public Message getTooltip() { new CommandAPICommand("warp") .withArguments(arguments) .executesPlayer((player, args) -> { - player.teleport((Location) args.get(0)); + player.teleport((Location) args.get("location")); }) .register(); /* ANCHOR_END: tooltips6 */ diff --git a/commandapi-documentation-code/src/main/kotlin/dev/jorel/commandapi/examples/kotlin/Examples.kt b/commandapi-documentation-code/src/main/kotlin/dev/jorel/commandapi/examples/kotlin/Examples.kt index 8e87a3bb85..670f0ff2ad 100644 --- a/commandapi-documentation-code/src/main/kotlin/dev/jorel/commandapi/examples/kotlin/Examples.kt +++ b/commandapi-documentation-code/src/main/kotlin/dev/jorel/commandapi/examples/kotlin/Examples.kt @@ -49,6 +49,7 @@ import org.bukkit.util.EulerAngle import java.util.* import java.util.concurrent.CompletableFuture import java.util.function.Predicate +import java.util.function.Supplier import kotlin.collections.LinkedHashMap import kotlin.random.Random @@ -60,8 +61,8 @@ CommandAPICommand("award") .withArguments(PlayerArgument("player")) .withArguments(AdvancementArgument("advancement")) .executes(CommandExecutor { _, args -> - val target = args[0] as Player - val advancement = args[1] as Advancement + val target = args["player"] as Player + val advancement = args["advancement"] as Advancement // Award all criteria for the advancement val progress = target.getAdvancementProgress(advancement) @@ -101,7 +102,7 @@ CommandAPICommand("yaw") .withArguments(AngleArgument("amount")) .executesPlayer(PlayerCommandExecutor { player, args -> val newLocation = player.location - newLocation.yaw = args[0] as Float + newLocation.yaw = args["amount"] as Float player.teleport(newLocation) }) .register() @@ -113,7 +114,7 @@ fun argument_biome() { CommandAPICommand("setbiome") .withArguments(BiomeArgument("biome")) .executesPlayer(PlayerCommandExecutor { player, args -> - val biome = args[0] as Biome + val biome = args["biome"] as Biome val chunk = player.location.chunk player.world.setBiome(chunk.x, player.location.blockY, chunk.z, biome) @@ -137,9 +138,9 @@ CommandAPICommand("replace") .executesPlayer(PlayerCommandExecutor { player, args -> // Parse the arguments - val radius = args[0] as Int - val predicate = args[1] as Predicate - val blockData = args[2] as BlockData + val radius = args["radius"] as Int + val predicate = args["fromBlock"] as Predicate + val blockData = args["toBlock"] as BlockData // Find a (solid) sphere of blocks around the player with a given radius val center = player.location // for (i in 1 until 11) { } @@ -168,7 +169,7 @@ fun argument_blockState() { CommandAPICommand("set") .withArguments(BlockStateArgument("block")) .executesPlayer(PlayerCommandExecutor { player, args -> - val blockdata = args[0] as BlockData + val blockdata = args["block"] as BlockData val targetBlock = player.getTargetBlockExact(256) // Set the block, along with its data @@ -187,10 +188,10 @@ CommandAPICommand("showbook") .withArguments(StringArgument("author")) .withArguments(AdventureChatComponentArgument("contents")) .executes(CommandExecutor { _, args -> - val target = args[0] as Player - val title = args[1] as String - val author = args[2] as String - val content = args[3] as Component + val target = args["target"] as Player + val title = args["title"] as String + val author = args["author"] as String + val content = args["contents"] as Component // Create a book and show it to the user (Requires Paper) val mybook = Book.book(Component.text(title), Component.text(author), content) @@ -203,7 +204,7 @@ CommandAPICommand("showbook") CommandAPICommand("pbroadcast") .withArguments(AdventureChatArgument("message")) .executes(CommandExecutor { _, args -> - val message = args[0] as Component + val message = args["message"] as Component // Broadcast the message to everyone with broadcast permissions. Bukkit.getServer().broadcast(message, Server.BROADCAST_CHANNEL_USERS) @@ -216,9 +217,9 @@ CommandAPICommand("pbroadcast") fun argument_chats() { /* ANCHOR: argumentChats1 */ CommandAPICommand("namecolor") - .withArguments(ChatColorArgument("chatcolor")) + .withArguments(ChatColorArgument("chatColor")) .executesPlayer(PlayerCommandExecutor { player, args -> - val color = args[0] as ChatColor + val color = args["chatColor"] as ChatColor player.setDisplayName("$color${player.name}") }) .register() @@ -231,8 +232,8 @@ CommandAPICommand("makebook") .withArguments(PlayerArgument("player")) .withArguments(ChatComponentArgument("contents")) .executes(CommandExecutor { _, args -> - val player = args[0] as Player - val arr = args[1] as Array + val player = args["player"] as Player + val arr = args["contents"] as Array // Create book val item = ItemStack(Material.WRITTEN_BOOK) @@ -252,7 +253,7 @@ CommandAPICommand("makebook") CommandAPICommand("pbroadcast") .withArguments(ChatArgument("message")) .executes(CommandExecutor { _, args -> - val message = args[0] as Array + val message = args["message"] as Array // Broadcast the message to everyone on the server Bukkit.getServer().spigot().broadcast(*message) @@ -267,8 +268,8 @@ CommandAPICommand("sudo") .withArguments(PlayerArgument("target")) .withArguments(CommandArgument("command")) .executes(CommandExecutor { _, args -> - val target = args[0] as Player - val command = args[1] as CommandResult + val target = args["target"] as Player + val command = args["command"] as CommandResult command.execute(target) }) @@ -353,7 +354,7 @@ fun argumentCustom2() { CommandAPICommand("tpworld") .withArguments(worldArgument("world")) .executesPlayer(PlayerCommandExecutor { player, args -> - player.teleport((args[0] as World).spawnLocation) + player.teleport((args["world"] as World).spawnLocation) }) .register() /* ANCHOR_END: argumentCustom2 */ @@ -366,8 +367,8 @@ CommandAPICommand("enchantitem") .withArguments(EnchantmentArgument("enchantment")) .withArguments(IntegerArgument("level", 1, 5)) .executesPlayer(PlayerCommandExecutor { player, args -> - val enchantment = args[0] as Enchantment - val level = args[1] as Int + val enchantment = args["enchantment"] as Enchantment + val level = args["level"] as Int // Add the enchantment player.inventory.itemInMainHand.addEnchantment(enchantment, level) @@ -383,7 +384,7 @@ CommandAPICommand("remove") .withArguments(EntitySelectorArgument.ManyEntities("entities")) .executes(CommandExecutor { sender, args -> // Parse the argument as a collection of entities (as stated above in the documentation) - val entities = args[0] as Collection + val entities = args["entities"] as Collection sender.sendMessage("Removed ${entities.size} entities") for (e in entities) { @@ -398,8 +399,8 @@ CommandAPICommand("spawnmob") .withArguments(EntityTypeArgument("entity")) .withArguments(IntegerArgument("amount", 1, 100)) // Prevent spawning too many entities .executesPlayer(PlayerCommandExecutor { player, args -> - for (i in 0 until args[1] as Int) { - player.world.spawnEntity(player.location, args[0] as EntityType) + for (i in 0 until args["amount"] as Int) { + player.world.spawnEntity(player.location, args["entity"] as EntityType) } }) .register() @@ -411,7 +412,7 @@ fun argument_function() { CommandAPICommand("runfunction") .withArguments(FunctionArgument("function")) .executes(CommandExecutor { _, args -> - val functions = args[0] as Array + val functions = args["function"] as Array // Run all functions in our FunctionWrapper[] for (function in functions) { @@ -425,9 +426,9 @@ CommandAPICommand("runfunction") fun argument_itemStack() { /* ANCHOR: argumentItemStack1 */ CommandAPICommand("item") - .withArguments(ItemStackArgument("itemstack")) + .withArguments(ItemStackArgument("itemStack")) .executesPlayer(PlayerCommandExecutor { player, args -> - player.inventory.addItem(args[0] as ItemStack) + player.inventory.addItem(args["itemStack"] as ItemStack) }) .register() /* ANCHOR_END: argumentItemStack1 */ @@ -441,7 +442,7 @@ CommandAPICommand("rem") .executesPlayer(PlayerCommandExecutor { player, args -> // Get our predicate - val predicate = args[0] as Predicate + val predicate = args["items"] as Predicate for (item in player.inventory) { if (predicate.test(item)) { @@ -463,8 +464,8 @@ CommandAPICommand("multigive") .buildGreedy() ) .executesPlayer(PlayerCommandExecutor { player, args -> - val amount = args[0] as Int - val theList = args[1] as List + val amount = args["amount"] as Int + val theList = args["materials"] as List for (item in theList) { player.inventory.addItem(ItemStack(item, amount)) @@ -534,7 +535,7 @@ CommandAPICommand("break") // We want to target blocks in particular, so use BLOCK_POSITION .withArguments(LocationArgument("block", LocationType.BLOCK_POSITION)) .executesPlayer(PlayerCommandExecutor { _, args -> - (args[0] as Location).block.type = Material.AIR + (args["block"] as Location).block.type = Material.AIR }) .register() /* ANCHOR_END: argumentLocations1 */ @@ -543,11 +544,11 @@ CommandAPICommand("break") fun argument_lootTable() { /* ANCHOR: argumentLootTable1 */ CommandAPICommand("giveloottable") - .withArguments(LootTableArgument("loottable")) + .withArguments(LootTableArgument("lootTable")) .withArguments(LocationArgument("location", LocationType.BLOCK_POSITION)) .executes(CommandExecutor { _, args -> - val lootTable = args[0] as LootTable - val location = args[1] as Location + val lootTable = args["lootTable"] as LootTable + val location = args["location"] as Location val state = location.block.state @@ -605,9 +606,9 @@ CommandAPICommand("changelevel") .withArguments(MathOperationArgument("operation")) .withArguments(IntegerArgument("value")) .executes(CommandExecutor { _, args -> - val target = args[0] as Player - val op = args[1] as MathOperation - val value = args[2] as Int + val target = args["player"] as Player + val op = args["operation"] as MathOperation + val value = args["value"] as Int target.level = op.apply(target.level, value) }) @@ -621,7 +622,7 @@ CommandAPICommand("gamemode") .withArguments(MultiLiteralArgument("gamemodes", "adventure", "creative", "spectator", "survival")) .executesPlayer(PlayerCommandExecutor { player, args -> // The literal string that the player enters IS available in the args[] - when (args[0] as String) { + when (args["gamemodes"] as String) { "adventure" -> player.gameMode = GameMode.ADVENTURE "creative" -> player.gameMode = GameMode.CREATIVE "spectator" -> player.gameMode = GameMode.SPECTATOR @@ -647,7 +648,7 @@ fun argument_nbt2() { CommandAPICommand("award") .withArguments(NBTCompoundArgument("nbt")) .executes(CommandExecutor { _, args -> - val nbt = args[0] as NBTContainer + val nbt = args["nbt"] as NBTContainer // Do something with "nbt" here... }) @@ -662,10 +663,10 @@ fun argument_objectives() { CommandAPICommand("sidebar") .withArguments(ObjectiveArgument("objective")) .executes(CommandExecutor { _, args -> - val objective = args[0] as Objective + val objective = args["objective"] as Objective // Set display slot - objective?.displaySlot = DisplaySlot.SIDEBAR + objective.displaySlot = DisplaySlot.SIDEBAR }) .register() /* ANCHOR_END: argumentObjectives1 */ @@ -674,7 +675,7 @@ CommandAPICommand("sidebar") CommandAPICommand("unregisterall") .withArguments(ObjectiveCriteriaArgument("objective criteria")) .executes(CommandExecutor { _, args -> - val objectiveCriteria = args[0] as String + val objectiveCriteria = args["objective criteria"] as String val objectives = Bukkit.getScoreboardManager().mainScoreboard.getObjectivesByCriteria(objectiveCriteria) // Unregister the objectives @@ -691,7 +692,7 @@ fun argument_particle() { CommandAPICommand("showparticle") .withArguments(ParticleArgument("particle")) .executesPlayer(PlayerCommandExecutor { player, args -> - val particleData = args[0] as ParticleData + val particleData = args["particle"] as ParticleData player.world.spawnParticle(particleData.particle(), player.location, 1) }) .register() @@ -701,7 +702,7 @@ CommandAPICommand("showparticle") CommandAPICommand("showparticle") .withArguments(ParticleArgument("particle")) .executesPlayer(PlayerCommandExecutor { player, args -> - val particleData = args[0] as ParticleData + val particleData = args["particle"] as ParticleData player.world.spawnParticle(particleData.particle(), player.location, 1, particleData.data()) }) .register() @@ -716,10 +717,10 @@ CommandAPICommand("potion") .withArguments(TimeArgument("duration")) .withArguments(IntegerArgument("strength")) .executes(CommandExecutor { _, args -> - val target = args[0] as Player - val potion = args[1] as PotionEffectType - val duration = args[2] as Int - val strength = args[3] as Int + val target = args["target"] as Player + val potion = args["potion"] as PotionEffectType + val duration = args["duration"] as Int + val strength = args["strength"] as Int // Add the potion effect to the target player target.addPotionEffect(PotionEffect(potion, duration, strength)) @@ -739,7 +740,7 @@ CommandAPICommand("editconfig") .withArguments(BooleanArgument("value")) .executes(CommandExecutor { _, args -> // Update the config with the boolean argument - config.set(args[0] as String, args[1] as Boolean) + config.set(args["config-key"] as String, args["value"] as Boolean) }) .register() /* ANCHOR_END: argumentPrimitives1 */ @@ -752,8 +753,8 @@ CommandAPICommand("searchrange") .withArguments(ItemStackArgument("item")) // The item to search for .executesPlayer(PlayerCommandExecutor { player, args -> // Retrieve the range from the arguments - val range = args[0] as IntegerRange - val itemStack = args[1] as ItemStack + val range = args["range"] as IntegerRange + val itemStack = args["item"] as ItemStack // Store the locations of chests with certain items val locations = mutableListOf() @@ -800,7 +801,7 @@ fun argument_recipe() { CommandAPICommand("giverecipe") .withArguments(RecipeArgument("recipe")) .executesPlayer(PlayerCommandExecutor { player, args -> - val recipe = args[0] as ComplexRecipe + val recipe = args["recipe"] as ComplexRecipe player.inventory.addItem(recipe.result) }) .register() @@ -811,8 +812,8 @@ CommandAPICommand("unlockrecipe") .withArguments(PlayerArgument("player")) .withArguments(RecipeArgument("recipe")) .executes(CommandExecutor { _, args -> - val target = args[0] as Player - val recipe = args[1] as ComplexRecipe + val target = args["player"] as Player + val recipe = args["recipe"] as ComplexRecipe target.discoverRecipe(recipe.key) }) @@ -826,8 +827,8 @@ CommandAPICommand("rotate") .withArguments(RotationArgument("rotation")) .withArguments(EntitySelectorArgument.OneEntity("target")) .executes(CommandExecutor { _, args -> - val rotation = args[0] as Rotation - val target = args[1] as Entity + val rotation = args["rotation"] as Rotation + val target = args["target"] as Entity if (target is ArmorStand) { target.headPose = EulerAngle(Math.toRadians(rotation.pitch.toDouble()), Math.toRadians(rotation.yaw.toDouble() - 90), 0.0) @@ -844,7 +845,7 @@ CommandAPICommand("reward") .withArguments(ScoreHolderArgument.Multiple("players")) .executes(CommandExecutor { _, args -> // Get player names by casting to Collection - val players = args[0] as Collection + val players = args["players"] as Collection for (playerName in players) { Bukkit.getPlayer(playerName)?.inventory!!.addItem(ItemStack(Material.DIAMOND, 3)) @@ -858,7 +859,7 @@ CommandAPICommand("clearobjectives") .withArguments(ScoreboardSlotArgument("slot")) .executes(CommandExecutor { _, args -> val scoreboard = Bukkit.getScoreboardManager().mainScoreboard - val slot = (args[0] as ScoreboardSlot).displaySlot + val slot = (args["slot"] as ScoreboardSlot).displaySlot scoreboard.clearSlot(slot) }) .register() @@ -870,7 +871,7 @@ fun argument_sound() { CommandAPICommand("sound") .withArguments(SoundArgument("sound")) .executesPlayer(PlayerCommandExecutor { player, args -> - player.world.playSound(player.location, args[0] as Sound, 100.0f, 1.0f) + player.world.playSound(player.location, args["sound"] as Sound, 100.0f, 1.0f) }) .register() /* ANCHOR_END: argumentSound1 */ @@ -879,7 +880,7 @@ CommandAPICommand("sound") CommandAPICommand("sound") .withArguments(SoundArgument.NamespacedKey("sound")) .executesPlayer(PlayerCommandExecutor { player, args -> - player.world.playSound(player.location, (args[0] as NamespacedKey).asString(), 100.0f, 1.0f) + player.world.playSound(player.location, (args["sound"] as NamespacedKey).asString(), 100.0f, 1.0f) }) .register() /* ANCHOR_END: argumentSound2 */ @@ -891,7 +892,7 @@ CommandAPICommand("message") .withArguments(PlayerArgument("target")) .withArguments(GreedyStringArgument("message")) .executes(CommandExecutor { _, args -> - (args[0] as Player).sendMessage(args[1] as String) + (args["target"] as Player).sendMessage(args["message"] as String) }) .register() /* ANCHOR_END: argumentStrings1 */ @@ -902,7 +903,7 @@ fun argument_team() { CommandAPICommand("togglepvp") .withArguments(TeamArgument("team")) .executes(CommandExecutor { _, args -> - val team = args[0] as Team + val team = args["team"] as Team // Toggle pvp team.setAllowFriendlyFire(team.allowFriendlyFire()) @@ -918,8 +919,8 @@ CommandAPICommand("bigmsg") .withArguments(GreedyStringArgument("message")) .executes(CommandExecutor { _, args -> // Duration in ticks - val duration = args[0] as Int - val message = args[1] as String + val duration = args["duration"] as Int + val message = args["message"] as String for (player in Bukkit.getOnlinePlayers()) { // Display the message to all players, with the default fade in/out times (10 and 20). @@ -935,7 +936,7 @@ fun argument_world() { CommandAPICommand("unloadworld") .withArguments(WorldArgument("world")) .executes(CommandExecutor { sender, args -> - val world = args[0] as World + val world = args["world"] as World // Unload the world (and save the world's chunks) Bukkit.getServer().unloadWorld(world, true) @@ -983,9 +984,9 @@ val commandArguments = listOf( CommandAPICommand("cmd") .withArguments(commandArguments) .executes(CommandExecutor { _, args -> - val stringArg = args[0] as String - val potionArg = args[1] as PotionEffectType - val locationArg = args[2] as Location + val stringArg = args["arg0"] as String + val potionArg = args["arg1"] as PotionEffectType + val locationArg = args["arg2"] as Location }) .register() /* ANCHOR_END: arguments4 */ @@ -1000,8 +1001,8 @@ CommandAPICommand("setconfig") } )) .withArguments(TextArgument("value")) .executes(CommandExecutor { _, args -> - val key = args[0] as String - val value = args[1] as String + val key = args["key"] as String + val value = args["value"] as String plugin.config.set(key, value) }) .register() @@ -1098,7 +1099,7 @@ val messageArgument = GreedyStringArgument("message") CommandAPICommand("emoji") .withArguments(messageArgument) .executes(CommandExecutor { _, args -> - Bukkit.broadcastMessage(args[0] as String) + Bukkit.broadcastMessage(args["message"] as String) }) .register() /* ANCHOR_END: brigadierSuggestions1 */ @@ -1146,7 +1147,7 @@ CommandAPICommand("commandargument") .withArguments(GreedyStringArgument("command").replaceSuggestions(commandSuggestions)) .executes(CommandExecutor { sender, args -> // Run the command using Bukkit.dispatchCommand() - Bukkit.dispatchCommand(sender, args[0] as String) + Bukkit.dispatchCommand(sender, args["command"] as String) }) .register() /* ANCHOR_END: brigadierSuggestions3 */ @@ -1165,7 +1166,7 @@ CommandAPICommand("broadcast") .executesPlayer(PlayerCommandExecutor { _, args -> // The user still entered legacy text. We need to properly convert this // to a BaseComponent[] by converting to plain text then to BaseComponent[] - val plainText: String = BaseComponent.toPlainText(*args[0] as Array) + val plainText: String = BaseComponent.toPlainText(*args["message"] as Array) val baseComponents: Array = TextComponent.fromLegacyText(ChatColor.translateAlternateColorCodes('&', plainText)) Bukkit.spigot().broadcast(*baseComponents) }) @@ -1184,7 +1185,7 @@ CommandAPICommand("broadcast") .executesPlayer(PlayerCommandExecutor { _, args -> // The user still entered legacy text. We need to properly convert this // to a Component by converting to plain text then to Component - val plainText: String = PlainTextComponentSerializer.plainText().serialize(args[0] as Component) + val plainText: String = PlainTextComponentSerializer.plainText().serialize(args["message"] as Component) Bukkit.broadcast(LegacyComponentSerializer.legacyAmpersand().deserialize(plainText)) }) .register() @@ -1200,7 +1201,7 @@ CommandAPICommand("broadcast") TextComponent.fromLegacyText(ChatColor.translateAlternateColorCodes('&', plainText)) } ) .executesPlayer(PlayerCommandExecutor { _, args -> - Bukkit.spigot().broadcast(*args[0] as Array) + Bukkit.spigot().broadcast(*args["message"] as Array) }) .register() /* ANCHOR_END: chatPreview3 */ @@ -1215,12 +1216,55 @@ CommandAPICommand("broadcast") LegacyComponentSerializer.legacyAmpersand().deserialize(plainText) } ) .executesPlayer(PlayerCommandExecutor { _, args -> - Bukkit.broadcast(args[0] as Component) + Bukkit.broadcast(args["message"] as Component) }) .register() /* ANCHOR_END: chatPreview4 */ } +fun commandArguments() { +/* ANCHOR: commandArguments1 */ +CommandAPICommand("mycommand") + .withArguments(StringArgument("name")) + .withArguments(IntegerArgument("amount")) + .withOptionalArguments(PlayerArgument("player")) + .withOptionalArguments(PlayerArgument("target")) + .withOptionalArguments(GreedyStringArgument("message")) + .executesPlayer(PlayerCommandExecutor { player, args -> + val name = args[0] as String // Access arguments by index + val amount = args["amount"] as Int // Access arguments by node name + val p = args.getOrDefault("player", player) as Player // Access arguments using the getOrDefault(String, Object) method + val target = args.getOrDefault("target") { player } as Player // Access arguments using the getOrDefault(String, Supplier) method + val message = args.getOptional("message").orElse("Hello!") as String // Access arguments using the getOptional(String) method + + // Do whatever with these values + }) + .register(); +/* ANCHOR_END: commandArguments1 */ + +/* ANCHOR: commandArguments2 */ +CommandAPICommand("mycommand") + .withArguments(EntitySelectorArgument.ManyEntities("entities")) + .executesPlayer(PlayerCommandExecutor { player, args -> + val entitySelector = args.getRaw("entities")!! // Access the raw argument with getRaw(String) + + // Do whatever with the entity selector + }) + .register(); +/* ANCHOR_END: commandArguments2 */ + +/* ANCHOR: commandArguments3 */ +CommandAPICommand("mycommand") + .withArguments(PlayerArgument("player")) + .executesPlayer(PlayerCommandExecutor { player, args -> + val p: Player = args.getUnchecked("player")!! + + // Do whatever with the player + }) + .register(); +/* ANCHOR_END: commandArguments3 */ +} + fun commandFailures() { /* ANCHOR: commandFailures1 */ // List of fruit @@ -1230,7 +1274,7 @@ val fruit = listOf("banana", "apple", "orange") CommandAPICommand("getfruit") .withArguments(StringArgument("item").replaceSuggestions(ArgumentSuggestions.strings(fruit))) .executes(CommandExecutor { _, args -> - val inputFruit = args[0] as String + val inputFruit = args["item"] as String if(fruit.any { it == inputFruit }) { // Do something with inputFruit @@ -1251,7 +1295,7 @@ CommandAPICommand("broadcastmsg") .withAliases("broadcast", "broadcastmessage") // Command aliases .withPermission(CommandPermission.OP) // Required permissions .executes(CommandExecutor { sender, args -> - val message = args[0] as String + val message = args["message"] as String Bukkit.getServer().broadcastMessage(message) }) .register() @@ -1280,7 +1324,7 @@ CommandTree("sayhi") }) .then(PlayerArgument("target") .executes(CommandExecutor { _, args -> - val target = args[0] as Player + val target = args["target"] as Player target.sendMessage("Hi") })) .register() @@ -1294,8 +1338,8 @@ CommandTree("signedit") .executesPlayer(PlayerCommandExecutor { player, args -> // /signedit set val sign: Sign = getTargetSign(player) - val line_number = args[0] as Int - val text = args[1] as String + val line_number = args["line_number"] as Int + val text = args["text"] as String sign.setLine(line_number - 1, text) sign.update(true) })))) @@ -1304,7 +1348,7 @@ CommandTree("signedit") .executesPlayer(PlayerCommandExecutor { player, args -> // /signedit clear val sign: Sign = getTargetSign(player) - val line_number = args[0] as Int + val line_number = args["line_number"] as Int sign.setLine(line_number - 1, "") sign.update(true) }))) @@ -1313,7 +1357,7 @@ CommandTree("signedit") .executesPlayer(PlayerCommandExecutor { player, args -> // /signedit copy val sign: Sign = getTargetSign(player) - val line_number = args[0] as Int + val line_number = args["line_number"] as Int player.setMetadata("copied_sign_text", FixedMetadataValue(this, sign.getLine(line_number - 1))) }))) .then(LiteralArgument("paste") @@ -1321,7 +1365,7 @@ CommandTree("signedit") .executesPlayer(PlayerCommandExecutor { player, args -> // /signedit copy val sign: Sign = getTargetSign(player) - val line_number = args[0] as Int + val line_number = args["line_number"] as Int sign.setLine(line_number - 1, player.getMetadata("copied_sign_text")[0].asString()) sign.update(true) }))) @@ -1406,7 +1450,7 @@ fun functionWrapper() { CommandAPICommand("runfunc") .withArguments(FunctionArgument("function")) .executes(CommandExecutor { _, args -> - val functions = args[0] as Array + val functions = args["function"] as Array for (function in functions) { function.run() // The command executor in this case is 'sender' } @@ -1444,8 +1488,8 @@ CommandAPICommand("mycommand") .withArguments(GreedyStringArgument("message")) .executes(CommandExecutor { _, args -> // args == [player, message] - val player = args[0] as Player - val message = args[1] as String // Note that this is args[1] and NOT args[2] + val player = args["player"] as Player + val message = args["message"] as String // Note that the IntegerArgument is not available in the CommandArguments player.sendMessage(message) }) .register() @@ -1471,7 +1515,7 @@ CommandAPICommand("broadcastmsg") .withAliases("broadcast", "broadcastmessage") // Command aliases .withPermission(CommandPermission.OP) // Required permissions .executes(CommandExecutor { _, args -> - val message = args[0] as String + val message = args["message"] as String Bukkit.getServer().broadcastMessage(message) }) .register() @@ -1594,7 +1638,7 @@ CommandAPICommand("kill") CommandAPICommand("kill") .withArguments(PlayerArgument("target").withPermission(CommandPermission.OP)) .executesPlayer(PlayerCommandExecutor { _, args -> - (args[0] as Player).health = 0.0 + (args["target"] as Player).health = 0.0 }) .register() /* ANCHOR_END: permissions4 */ @@ -1613,7 +1657,7 @@ CommandAPICommand("economy") .withPermission("economy.other") // The important part of this example .withArguments(PlayerArgument("target")) .executesPlayer(PlayerCommandExecutor { player, args -> - val target = args[0] as Player + val target = args["target"] as Player // send the executor the targets balance here. }) .register() @@ -1624,8 +1668,8 @@ CommandAPICommand("economy") .withArguments(PlayerArgument("target")) .withArguments(DoubleArgument("amount")) .executesPlayer(PlayerCommandExecutor { player, args -> - val target = args[0] as Player - val amount = args[1] as Double + val target = args["target"] as Player + val amount = args["amount"] as Double // update the targets balance here }) .register() @@ -1635,7 +1679,7 @@ CommandAPICommand("economy") .withPermission("economy.admin.reset") // The important part of this example .withArguments(PlayerArgument("target")) .executesPlayer(PlayerCommandExecutor { player, args -> - val target = args[0] as Player + val target = args["target"] as Player // reset the targets balance here }) .register() @@ -1745,7 +1789,7 @@ CommandAPICommand("party") .executesPlayer(PlayerCommandExecutor { player, args -> // Get the name of the party to create - val partyName = args[0] as String + val partyName = args["partyName"] as String partyMembers[player.uniqueId] = partyName }) @@ -1792,7 +1836,7 @@ arguments.add(PlayerArgument("player") CommandAPICommand("party") .withArguments(arguments) .executesPlayer(PlayerCommandExecutor { player, args -> - val target = args[0] as Player + val target = args["player"] as Player player.teleport(target) }) .register() @@ -1804,7 +1848,7 @@ CommandAPICommand("party") .executesPlayer(PlayerCommandExecutor { player, args -> // Get the name of the party to create - val partyName = args[0] as String + val partyName = args["partyName"] as String partyMembers[player.uniqueId] = partyName @@ -1848,7 +1892,7 @@ CommandAPICommand("randomnumber") CommandAPICommand("givereward") .withArguments(EntitySelectorArgument.OnePlayer("target")) .executes(CommandExecutor { _, args -> - val player = args[0] as Player + val player = args["target"] as Player player.inventory.addItem(ItemStack(Material.DIAMOND, 64)) Bukkit.broadcastMessage("${player.name} won a rare 64 diamonds from a loot box!") }) @@ -1892,7 +1936,7 @@ val arguments = listOf>( CommandAPICommand("giverecipe") .withArguments(arguments) .executesPlayer(PlayerCommandExecutor { player, args -> - val recipe = args[0] as Recipe + val recipe = args["recipe"] as Recipe player.inventory.addItem(recipe.result) }) .register() @@ -1924,7 +1968,7 @@ val safeArguments = listOf>( CommandAPICommand("spawnmob") .withArguments(safeArguments) .executesPlayer(PlayerCommandExecutor { player, args -> - val entityType = args[0] as EntityType + val entityType = args["mob"] as EntityType player.world.spawnEntity(player.location, entityType) }) .register() @@ -1935,7 +1979,7 @@ val safeArgs = mutableListOf>() safeArgs.add(EntitySelectorArgument.OnePlayer("target")) safeArgs.add(PotionEffectArgument("potioneffect").replaceSafeSuggestions(SafeSuggestions.suggest { info -> - val target = info.previousArgs()[0] as Player + val target = info.previousArgs()["target"] as Player // Convert PotionEffect[] into PotionEffectType[] target.activePotionEffects.map{ it.type }.toTypedArray() @@ -1947,8 +1991,8 @@ safeArgs.add(PotionEffectArgument("potioneffect").replaceSafeSuggestions(SafeSug CommandAPICommand("removeeffect") .withArguments(safeArgs) .executesPlayer(PlayerCommandExecutor { _, args -> - val target = args[0] as Player - val potionEffect = args[1] as PotionEffectType + val target = args["target"] as Player + val potionEffect = args["potioneffect"] as PotionEffectType target.removePotionEffect(potionEffect) }) .register() @@ -2004,7 +2048,7 @@ val arguments = listOf>( CommandAPICommand("warp") .withArguments(arguments) .executesPlayer(PlayerCommandExecutor { player, args -> - val warp = args[0] as String + val warp = args["world"] as String player.teleport(warps[warp]!!) // Look up the warp in a map, for example }) .register() @@ -2043,7 +2087,7 @@ val arguments = listOf>( CommandAPICommand("friendtp") .withArguments(arguments) .executesPlayer(PlayerCommandExecutor { player, args -> - val target = args[0] as Player + val target = args["friend"] as Player player.teleport(target) }) .register() @@ -2060,7 +2104,7 @@ commandArgs.add(IntegerArgument("radius")) commandArgs.add(PlayerArgument("target").replaceSuggestions(ArgumentSuggestions.strings { info: SuggestionInfo -> // Cast the first argument (radius, which is an IntegerArgument) to get its value - val radius = (info.previousArgs()[0] as Int).toDouble() + val radius = (info.previousArgs()["radius"] as Int).toDouble() // Get nearby entities within the provided radius val player = info.sender() as Player @@ -2078,8 +2122,8 @@ commandArgs.add(GreedyStringArgument("message")) CommandAPICommand("localmsg") .withArguments(*commandArgs.toTypedArray()) .executesPlayer(PlayerCommandExecutor { _, args -> - val target = args[1] as Player - val message = args[2] as String + val target = args["target"] as Player + val message = args["message"] as String target.sendMessage(message) }) .register() @@ -2175,8 +2219,8 @@ arguments.add(PlayerArgument("target")) CommandAPICommand("emote") .withArguments(*arguments.toTypedArray()) .executesPlayer(PlayerCommandExecutor { player, args -> - val emote = args[0] as String - val target = args[1] as Player + val emote = args["emote"] as String + val target = args["target"] as Player when (emote) { "wave" -> target.sendMessage("${player.name} waves at you!") @@ -2215,7 +2259,7 @@ val customItems = arrayOf( CommandAPICommand("giveitem") .withArguments(StringArgument("item").replaceSuggestions(ArgumentSuggestions.stringsWithTooltips(*customItems))) // We use customItems[] as the input for our suggestions with tooltips .executesPlayer(PlayerCommandExecutor { player, args -> - val itemName = args[0] as String + val itemName = args["item"] as String // Give them the item for (item in customItems) { @@ -2247,7 +2291,7 @@ val arguments = listOf>( CommandAPICommand("warp") .withArguments(arguments) .executesPlayer(PlayerCommandExecutor { player, args -> - player.teleport(args[0] as Location) + player.teleport(args["location"] as Location) }) .register() /* ANCHOR_END: tooltips6 */ diff --git a/commandapi-documentation-code/src/main/kotlin/dev/jorel/commandapi/examples/kotlin/ExamplesKotlinDSL.kt b/commandapi-documentation-code/src/main/kotlin/dev/jorel/commandapi/examples/kotlin/ExamplesKotlinDSL.kt index f350a8b441..aa9db80d96 100644 --- a/commandapi-documentation-code/src/main/kotlin/dev/jorel/commandapi/examples/kotlin/ExamplesKotlinDSL.kt +++ b/commandapi-documentation-code/src/main/kotlin/dev/jorel/commandapi/examples/kotlin/ExamplesKotlinDSL.kt @@ -42,8 +42,8 @@ commandAPICommand("award") { playerArgument("player") advancementArgument("advancement") anyExecutor { _, args -> - val target = args[0] as Player - val advancement = args[1] as Advancement + val target = args["player"] as Player + val advancement = args["advancement"] as Advancement // Award all criteria for the advancement val progress = target.getAdvancementProgress(advancement) @@ -81,7 +81,7 @@ commandAPICommand("yaw") { angleArgument("amount") playerExecutor { player, args -> val newLocation = player.location - newLocation.yaw = args[0] as Float + newLocation.yaw = args["amount"] as Float player.teleport(newLocation) } } @@ -93,7 +93,7 @@ fun argument_biome() { commandAPICommand("setbiome") { biomeArgument("biome") playerExecutor { player, args -> - val biome = args[0] as Biome + val biome = args["biome"] as Biome val chunk = player.location.chunk player.world.setBiome(chunk.x, player.location.blockY, chunk.z, biome) @@ -114,9 +114,9 @@ commandAPICommand("replace") { arguments(*arguments) playerExecutor { player, args -> // Parse the arguments - val radius = args[0] as Int - val predicate = args[1] as Predicate - val blockData = args[2] as BlockData + val radius = args["radius"] as Int + val predicate = args["fromBlock"] as Predicate + val blockData = args["toBlock"] as BlockData // Find a (solid) sphere of blocks around the player with a given radius val center = player.location // for (i in 1 until 11) { } @@ -145,7 +145,7 @@ fun argument_blockState() { commandAPICommand("set") { blockStateArgument("block") playerExecutor { player, args -> - val blockdata = args[0] as BlockData + val blockdata = args["block"] as BlockData val targetBlock = player.getTargetBlockExact(256) // Set the block, along with its data @@ -164,10 +164,10 @@ commandAPICommand("showbook") { stringArgument("author") adventureChatComponentArgument("contents") anyExecutor { _, args -> - val target = args[0] as Player - val title = args[1] as String - val author = args[2] as String - val content = args[3] as Component + val target = args["target"] as Player + val title = args["title"] as String + val author = args["author"] as String + val content = args["contents"] as Component // Create a book and show it to the user (Requires Paper) val mybook = Book.book(Component.text(title), Component.text(author), content) @@ -180,7 +180,7 @@ commandAPICommand("showbook") { commandAPICommand("pbroadcast") { adventureChatArgument("message") anyExecutor { _, args -> - val message = args[0] as Component + val message = args["message"] as Component // Broadcast the message to everyone with broadcast permissions. Bukkit.getServer().broadcast(message, Server.BROADCAST_CHANNEL_USERS) @@ -195,7 +195,7 @@ fun argument_chats() { commandAPICommand("namecolor") { chatColorArgument("chatcolor") playerExecutor { player, args -> - val color = args[0] as ChatColor + val color = args["chatcolor"] as ChatColor player.setDisplayName("$color${player.name}") } } @@ -208,8 +208,8 @@ commandAPICommand("makebook") { playerArgument("player") chatComponentArgument("contents") anyExecutor { _, args -> - val player = args[0] as Player - val array = args[1] as Array + val player = args["player"] as Player + val array = args["contents"] as Array // Create book val item = ItemStack(Material.WRITTEN_BOOK) @@ -229,7 +229,7 @@ commandAPICommand("makebook") { commandAPICommand("pbroadcast") { chatArgument("message") anyExecutor { _, args -> - val message = args[0] as Array + val message = args["message"] as Array // Broadcast the message to everyone on the server Bukkit.getServer().spigot().broadcast(*message) @@ -244,8 +244,8 @@ commandAPICommand("sudo") { playerArgument("target") commandArgument("command") anyExecutor { _, args -> - val target = args[0] as Player - val command = args[1] as CommandResult + val target = args["target"] as Player + val command = args["command"] as CommandResult command.execute(target) } @@ -258,7 +258,7 @@ fun argument_custom() { commandAPICommand("tpworld") { worldArgument("world") // This method is actually also built into the Kotlin DSL playerExecutor { player, args -> - player.teleport((args[0] as World).spawnLocation) + player.teleport((args["world"] as World).spawnLocation) } } /* ANCHOR_END: argumentCustom2 */ @@ -270,8 +270,8 @@ commandAPICommand("enchantitem") { enchantmentArgument("enchantment") integerArgument("level", 1, 5) playerExecutor { player, args -> - val enchantment = args[0] as Enchantment - val level = args[1] as Int + val enchantment = args["enchantment"] as Enchantment + val level = args["level"] as Int // Add the enchantment player.inventory.itemInMainHand.addEnchantment(enchantment, level) @@ -287,7 +287,7 @@ commandAPICommand("remove") { entitySelectorArgumentManyEntities("entities") anyExecutor { sender, args -> // Parse the argument as a collection of entities (as stated above in the documentation) - val entities = args[0] as Collection + val entities = args["entities"] as Collection sender.sendMessage("Removed ${entities.size} entities") for (e in entities) { @@ -302,8 +302,8 @@ commandAPICommand("spawnmob") { entityTypeArgument("entity") integerArgument("amount", 1, 100) // Prevent spawning too many entities playerExecutor { player, args -> - for (i in 0 until args[1] as Int) { - player.world.spawnEntity(player.location, args[0] as EntityType) + for (i in 0 until args["amount"] as Int) { + player.world.spawnEntity(player.location, args["entity"] as EntityType) } } } @@ -315,7 +315,7 @@ fun argument_function() { commandAPICommand("runfunction") { functionArgument("function") anyExecutor { _, args -> - val functions = args[0] as Array + val functions = args["function"] as Array // Run all functions in our FunctionWrapper[] for (function in functions) { @@ -331,7 +331,7 @@ fun argument_itemStack() { commandAPICommand("item") { itemStackArgument("itemstack") playerExecutor { player, args -> - player.inventory.addItem(args[0] as ItemStack) + player.inventory.addItem(args["itemstack"] as ItemStack) } } /* ANCHOR_END: argumentItemStack1 */ @@ -344,7 +344,7 @@ commandAPICommand("rem") { itemStackPredicateArgument("items") playerExecutor { player, args -> // Get our predicate - val predicate = args[0] as Predicate + val predicate = args["items"] as Predicate for (item in player.inventory) { if (predicate.test(item)) { @@ -366,8 +366,8 @@ commandAPICommand("multigive") { .buildGreedy() ) playerExecutor { player, args -> - val amount = args[0] as Int - val theList = args[1] as List + val amount = args["amount"] as Int + val theList = args["materials"] as List for (item in theList) { player.inventory.addItem(ItemStack(item, amount)) @@ -438,7 +438,7 @@ commandAPICommand("break") { // We want to target blocks in particular, so use BLOCK_POSITION locationArgument("block", LocationType.BLOCK_POSITION) playerExecutor { _, args -> - (args[0] as Location).block.type = Material.AIR + (args["block"] as Location).block.type = Material.AIR } } /* ANCHOR_END: argumentLocations1 */ @@ -450,8 +450,8 @@ commandAPICommand("giveloottable") { lootTableArgument("loottable") locationArgument("location", LocationType.BLOCK_POSITION) anyExecutor { _, args -> - val lootTable = args[0] as LootTable - val location = args[1] as Location + val lootTable = args["loottable"] as LootTable + val location = args["location"] as Location val state = location.block.state @@ -509,9 +509,9 @@ commandAPICommand("changelevel") { mathOperationArgument("operation") integerArgument("value") anyExecutor { _, args -> - val target = args[0] as Player - val op = args[1] as MathOperation - val value = args[2] as Int + val target = args["player"] as Player + val op = args["operation"] as MathOperation + val value = args["value"] as Int target.level = op.apply(target.level, value) } @@ -525,7 +525,7 @@ commandAPICommand("gamemode") { multiLiteralArgument(nodeName = "gamemodes", "adventure", "creative", "spectator", "survival") // Adding this for now, needed because ambiguous methods exist playerExecutor { player, args -> // The literal string that the player enters IS available in the args[] - when (args[0] as String) { + when (args["gamemodes"] as String) { "adventure" -> player.gameMode = GameMode.ADVENTURE "creative" -> player.gameMode = GameMode.CREATIVE "spectator" -> player.gameMode = GameMode.SPECTATOR @@ -541,7 +541,7 @@ fun argument_nbt() { commandAPICommand("award") { nbtCompoundArgument("nbt") anyExecutor { _, args -> - val nbt = args[0] as NBTContainer + val nbt = args["nbt"] as NBTContainer // Do something with "nbt" here... } @@ -554,10 +554,10 @@ fun argument_objectives() { commandAPICommand("sidebar") { objectiveArgument("objective") anyExecutor { _, args -> - val objective = args[0] as Objective + val objective = args["objective"] as Objective // Set display slot - objective?.displaySlot = DisplaySlot.SIDEBAR + objective.displaySlot = DisplaySlot.SIDEBAR } } /* ANCHOR_END: argumentObjectives1 */ @@ -566,7 +566,7 @@ commandAPICommand("sidebar") { commandAPICommand("unregisterall") { objectiveCriteriaArgument("objective criteria") anyExecutor { _, args -> - val objectiveCriteria = args[0] as String + val objectiveCriteria = args["objective criteria"] as String val objectives = Bukkit.getScoreboardManager().mainScoreboard.getObjectivesByCriteria(objectiveCriteria) // Unregister the objectives @@ -583,7 +583,7 @@ fun argument_particle() { commandAPICommand("showparticle") { particleArgument("particle") playerExecutor { player, args -> - val particleData = args[0] as ParticleData + val particleData = args["particle"] as ParticleData player.world.spawnParticle(particleData.particle(), player.location, 1) } } @@ -593,7 +593,7 @@ commandAPICommand("showparticle") { commandAPICommand("showparticle") { particleArgument("particle") playerExecutor { player, args -> - val particleData = args[0] as ParticleData + val particleData = args["particle"] as ParticleData player.world.spawnParticle(particleData.particle(), player.location, 1, particleData.data()) } } @@ -608,10 +608,10 @@ commandAPICommand("potion") { timeArgument("duration") integerArgument("strength") anyExecutor { _, args -> - val target = args[0] as Player - val potion = args[1] as PotionEffectType - val duration = args[2] as Int - val strength = args[3] as Int + val target = args["target"] as Player + val potion = args["potion"] as PotionEffectType + val duration = args["duration"] as Int + val strength = args["strength"] as Int // Add the potion effect to the target player target.addPotionEffect(PotionEffect(potion, duration, strength)) @@ -631,7 +631,7 @@ commandAPICommand("editconfig") { booleanArgument("value") anyExecutor { _, args -> // Update the config with the boolean argument - getConfig().set(args[0] as String, args[1] as Boolean) + getConfig().set(args["config-key"] as String, args["value"] as Boolean) } } /* ANCHOR_END: argumentPrimitives1 */ @@ -644,8 +644,8 @@ commandAPICommand("searchrange") { itemStackArgument("item") // The item to search for playerExecutor { player, args -> // Retrieve the range from the arguments - val range = args[0] as IntegerRange - val itemStack = args[1] as ItemStack + val range = args["range"] as IntegerRange + val itemStack = args["item"] as ItemStack // Store the locations of chests with certain items val locations = mutableListOf() @@ -692,7 +692,7 @@ fun argument_recipe() { commandAPICommand("giverecipe") { recipeArgument("recipe") playerExecutor { player, args -> - val recipe = args[0] as ComplexRecipe + val recipe = args["recipe"] as ComplexRecipe player.inventory.addItem(recipe.result) } } @@ -703,8 +703,8 @@ commandAPICommand("unlockrecipe") { playerArgument("player") recipeArgument("recipe") anyExecutor { _, args -> - val target = args[0] as Player - val recipe = args[1] as ComplexRecipe + val target = args["player"] as Player + val recipe = args["recipe"] as ComplexRecipe target.discoverRecipe(recipe.key) } @@ -718,8 +718,8 @@ commandAPICommand("rotate") { rotationArgument("rotation") entitySelectorArgumentOneEntity("target") anyExecutor { _, args -> - val rotation = args[0] as Rotation - val target = args[1] as Entity + val rotation = args["rotation"] as Rotation + val target = args["target"] as Entity if (target is ArmorStand) { target.headPose = EulerAngle(Math.toRadians(rotation.pitch.toDouble()), Math.toRadians(rotation.yaw.toDouble() - 90), 0.0) @@ -736,7 +736,7 @@ commandAPICommand("reward") { scoreHolderArgumentMultiple("player") anyExecutor { _, args -> // Get player names by casting to Collection - val players = args[0] as Collection + val players = args["player"] as Collection for (playerName in players) { Bukkit.getPlayer(playerName)?.inventory!!.addItem(ItemStack(Material.DIAMOND, 3)) @@ -750,7 +750,7 @@ commandAPICommand("clearobjectives") { scoreboardSlotArgument("slot") anyExecutor { _, args -> val scoreboard = Bukkit.getScoreboardManager().mainScoreboard - val slot = (args[0] as ScoreboardSlot).displaySlot + val slot = (args["slot"] as ScoreboardSlot).displaySlot scoreboard.clearSlot(slot) } } @@ -762,7 +762,7 @@ fun argument_sound() { commandAPICommand("sound") { soundArgument("sound") playerExecutor { player, args -> - player.world.playSound(player.location, args[0] as Sound, 100.0f, 1.0f) + player.world.playSound(player.location, args["sound"] as Sound, 100.0f, 1.0f) } } /* ANCHOR_END: argumentSound1 */ @@ -771,7 +771,7 @@ commandAPICommand("sound") { commandAPICommand("sound") { soundArgument("sound", true) playerExecutor { player, args -> - player.world.playSound(player.location, (args[0] as NamespacedKey).asString(), 100.0f, 1.0f) + player.world.playSound(player.location, (args["sound"] as NamespacedKey).asString(), 100.0f, 1.0f) } } /* ANCHOR_END: argumentSound2 */ @@ -783,7 +783,7 @@ commandAPICommand("message") { playerArgument("target") greedyStringArgument("message") anyExecutor { _, args -> - (args[0] as Player).sendMessage(args[1] as String) + (args["target"] as Player).sendMessage(args["message"] as String) } } /* ANCHOR_END: argumentStrings1 */ @@ -794,7 +794,7 @@ fun argument_team() { commandAPICommand("togglepvp") { teamArgument("team") anyExecutor { _, args -> - val team = args[0] as Team + val team = args["team"] as Team // Toggle pvp team.setAllowFriendlyFire(team.allowFriendlyFire()) @@ -810,8 +810,8 @@ commandAPICommand("bigmsg") { greedyStringArgument("message") anyExecutor { _, args -> // Duration in ticks - val duration = args[0] as Int - val message = args[1] as String + val duration = args["duration"] as Int + val message = args["message"] as String for (player in Bukkit.getOnlinePlayers()) { // Display the message to all players, with the default fade in/out times (10 and 20). @@ -827,7 +827,7 @@ fun argument_world() { commandAPICommand("unloadworld") { worldArgument("world") anyExecutor { sender, args -> - val world = args[0] as World + val world = args["world"] as World // Unload the world (and save the world's chunks) Bukkit.getServer().unloadWorld(world, true) @@ -878,9 +878,9 @@ val args = listOf( commandAPICommand("cmd") { arguments(*args.toTypedArray()) anyExecutor { _, args -> - val stringArg = args[0] as String - val potionArg = args[1] as PotionEffectType - val locationArg = args[2] as Location + val stringArg = args["arg0"] as String + val potionArg = args["arg1"] as PotionEffectType + val locationArg = args["arg2"] as Location } } /* ANCHOR_END: arguments4 */ @@ -914,8 +914,8 @@ commandTree("sendmessageto") { playerArgument("player") { // Defines a new PlayerArgument("player") greedyStringArgument("msg") { // Defines a new GreedyStringArgument("msg") anyExecutor { _, args -> // Command can be executed by anyone and anything (such as entities, the console, etc.) - val player: Player = args[0] as Player - val message: String = args[1] as String + val player: Player = args["player"] as Player + val message: String = args["msg"] as String player.sendMessage(message) } } @@ -928,8 +928,8 @@ commandAPICommand("sendmessageto") { playerArgument("player") // Defines a new PlayerArgument("player") greedyStringArgument("msg") // Defines a new GreedyStringArgument("msg") anyExecutor { _, args -> // Command can be executed by anyone and anything (such as entities, the console, etc.) - val player: Player = args[0] as Player - val message: String = args[1] as String + val player: Player = args["player"] as Player + val message: String = args["msg"] as String player.sendMessage(message) } } @@ -940,8 +940,8 @@ commandTree("sendMessageTo") { playerArgument("player") { greedyStringArgument("msg") { playerExecutor { _, args -> - val player: Player = args[0] as Player - val message: String = args[1] as String + val player: Player = args["player"] as Player + val message: String = args["msg"] as String player.sendMessage(message) } } @@ -949,7 +949,7 @@ commandTree("sendMessageTo") { requirement(of("broadcast"), { sender: CommandSender -> sender.isOp }) { // Define a new LiteralArgument("broadcast") that requires the CommandSender to be a player who is a server operator greedyStringArgument("msg") { playerExecutor { _, args -> - val message: String = args[0] as String + val message: String = args["msg"] as String Bukkit.broadcastMessage(message) } } @@ -962,8 +962,8 @@ commandAPICommand("sendMessageTo") { playerArgument("player") greedyStringArgument("msg") playerExecutor { _, args -> - val player: Player = args[0] as Player - val message: String = args[1] as String + val player: Player = args["player"] as Player + val message: String = args["msg"] as String player.sendMessage(message) } } @@ -972,7 +972,7 @@ commandAPICommand("sendMessageTo") { requirement(of("broadcast"), { sender: CommandSender -> sender.isOp }) // Define a new LiteralArgument("broadcast") that requires the CommandSender to be a player who is a server operator greedyStringArgument("msg") playerExecutor { _, args -> - val message: String = args[0] as String + val message: String = args["msg"] as String Bukkit.broadcastMessage(message) } } @@ -1003,7 +1003,7 @@ commandTree("optionalArgument") { // This command will let you execute: // "/optionalArgument give minecraft:stick" // "/optionalArgument give minecraft:stick 5" - val itemStack: ItemStack = args[0] as ItemStack + val itemStack: ItemStack = args["item"] as ItemStack val amount: Int = args.getOptional("amount").orElse(1) as Int itemStack.amount = amount player.inventory.addItem(itemStack) @@ -1023,7 +1023,7 @@ commandAPICommand("optionalArgument") { // This command will let you execute: // "/optionalArgument give minecraft:stick" // "/optionalArgument give minecraft:stick 5" - val itemStack: ItemStack = args[0] as ItemStack + val itemStack: ItemStack = args["item"] as ItemStack val amount: Int = args.getOptional("amount").orElse(1) as Int itemStack.amount = amount player.inventory.addItem(itemStack) @@ -1035,7 +1035,7 @@ commandAPICommand("optionalArgument") { commandTree("replaceSuggestions") { argument(StringArgument("strings").replaceSuggestions(ArgumentSuggestions.strings("one", "two", "three"))) { // Implement an argument that has suggestions playerExecutor { player, args -> - player.sendMessage("You chose option ${args[0] as String}!") + player.sendMessage("You chose option ${args["strings"] as String}!") } } } @@ -1045,7 +1045,7 @@ commandTree("replaceSuggestions") { commandAPICommand("replaceSuggestions") { argument(StringArgument("strings").replaceSuggestions(ArgumentSuggestions.strings("one", "two", "three"))) // Implement an argument that has suggestions playerExecutor { player, args -> - player.sendMessage("You chose option ${args[0] as String}!") + player.sendMessage("You chose option ${args["strings"] as String}!") } } /* ANCHOR_END: kotlindsl10 */ @@ -1161,7 +1161,7 @@ commandAPICommand("randomnumber") { commandAPICommand("givereward") { entitySelectorArgumentOnePlayer("target") anyExecutor { _, args -> - val player = args[0] as Player + val player = args["target"] as Player player.inventory.addItem(ItemStack(Material.DIAMOND, 64)) Bukkit.broadcastMessage("${player.name} won a rare 64 diamonds from a loot box!") } diff --git a/commandapi-platforms/commandapi-bukkit/commandapi-bukkit-core/src/main/java/dev/jorel/commandapi/arguments/CommandArgument.java b/commandapi-platforms/commandapi-bukkit/commandapi-bukkit-core/src/main/java/dev/jorel/commandapi/arguments/CommandArgument.java index 96ac03848d..faf0543255 100644 --- a/commandapi-platforms/commandapi-bukkit/commandapi-bukkit-core/src/main/java/dev/jorel/commandapi/arguments/CommandArgument.java +++ b/commandapi-platforms/commandapi-bukkit/commandapi-bukkit-core/src/main/java/dev/jorel/commandapi/arguments/CommandArgument.java @@ -18,6 +18,7 @@ import java.util.Arrays; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; /** @@ -55,7 +56,7 @@ private void applySuggestions() { // Suggesting command name ArgumentSuggestions replacement = replacements.getNextSuggestion(sender); if (replacement != null) { - return replacement.suggest(new SuggestionInfo<>(sender, new CommandArguments(new Object[0], new HashMap<>(), info.currentInput()), command, command), builder); + return replacement.suggest(new SuggestionInfo<>(sender, new CommandArguments(new Object[0], new LinkedHashMap<>(), new String[0], new LinkedHashMap<>(), info.currentInput()), command, command), builder); } List results = commandMap.tabComplete(sender, command); @@ -101,7 +102,7 @@ private void applySuggestions() { String[] previousArguments = Arrays.copyOf(arguments, lastIndex); ArgumentSuggestions replacement = replacements.getNextSuggestion(sender, previousArguments); if (replacement != null) { - return replacement.suggest(new SuggestionInfo<>(sender, new CommandArguments(previousArguments, new HashMap<>(), info.currentInput()), command, arguments[lastIndex]), builder); + return replacement.suggest(new SuggestionInfo<>(sender, new CommandArguments(previousArguments, new LinkedHashMap<>(), previousArguments, new LinkedHashMap<>(), info.currentInput()), command, arguments[lastIndex]), builder); } // Remove command name from arguments for normal tab-completion diff --git a/commandapi-platforms/commandapi-bukkit/commandapi-bukkit-test/commandapi-bukkit-test-tests/src/test/java/dev/jorel/commandapi/test/CommandArgumentsTests.java b/commandapi-platforms/commandapi-bukkit/commandapi-bukkit-test/commandapi-bukkit-test-tests/src/test/java/dev/jorel/commandapi/test/CommandArgumentsTests.java new file mode 100644 index 0000000000..c36ee65638 --- /dev/null +++ b/commandapi-platforms/commandapi-bukkit/commandapi-bukkit-test/commandapi-bukkit-test-tests/src/test/java/dev/jorel/commandapi/test/CommandArgumentsTests.java @@ -0,0 +1,146 @@ +package dev.jorel.commandapi.test; + +import be.seeseemelk.mockbukkit.entity.PlayerMock; +import dev.jorel.commandapi.CommandAPICommand; +import dev.jorel.commandapi.arguments.*; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class CommandArgumentsTests extends TestBase { + + /********* + * Setup * + *********/ + + @BeforeEach + public void setUp() { + super.setUp(); + } + + @AfterEach + public void tearDown() { + super.tearDown(); + } + + /********* + * Tests * + *********/ + + @Test + public void executionTestForRawArgumentsWithOnlyOneArgumentAndRequiredArgumentOnly() { + Mut results = Mut.of(); + + new CommandAPICommand("test") + .withArguments(new EntitySelectorArgument.ManyEntities("entities")) + .executesPlayer(info -> { + results.set(info.args().getRaw("entities")); + }) + .register(); + + PlayerMock player = server.addPlayer(); + + server.dispatchCommand(player, "test @e"); + assertEquals("@e", results.get()); + + server.dispatchCommand(player, "test @a"); + assertEquals("@a", results.get()); + + assertNoMoreResults(results); + } + + @Test + public void executionTestForRawArgumentsWithMultipleArgumentsAndRequiredArgumentsOnly() { + Mut results = Mut.of(); + + new CommandAPICommand("test") + .withArguments(new DoubleArgument("double")) + .withArguments(new TextArgument("text")) + .executesPlayer(info -> { + results.set(info.args().getRaw("double")); + results.set(info.args().getRaw("text")); + }) + .register(); + + PlayerMock player = server.addPlayer(); + + server.dispatchCommand(player, "test 15.34 \"This is interesting text\""); + assertEquals("15.34", results.get()); + assertEquals("\"This is interesting text\"", results.get()); + + assertNoMoreResults(results); + } + + @Test + public void executionTestForRawArgumentsWithMultipleArgumentsWithMultipleRequiredAndOneOptionalArguments() { + Mut results = Mut.of(); + + new CommandAPICommand("test") + .withArguments(new DoubleArgument("double")) + .withArguments(new TextArgument("text")) + .withOptionalArguments(new EntitySelectorArgument.ManyEntities("entities")) + .executesPlayer(info -> { + results.set(info.args().getRaw("double")); + results.set(info.args().getRaw("text")); + results.set(info.args().getRawOptional("entities").orElse("")); + }) + .register(); + + PlayerMock player = server.addPlayer(); + + server.dispatchCommand(player, "test 15.34 \"This is interesting text\""); + assertEquals("15.34", results.get()); + assertEquals("\"This is interesting text\"", results.get()); + assertEquals("", results.get()); + + server.dispatchCommand(player, "test 15.34 \"This is interesting text\" @e"); + assertEquals("15.34", results.get()); + assertEquals("\"This is interesting text\"", results.get()); + assertEquals("@e", results.get()); + + assertNoMoreResults(results); + } + + @Test + public void executionTestForRawArgumentsWithMultipleArgumentsWithMultipleRequiredAndMultipleOptionalArguments() { + Mut results = Mut.of(); + + new CommandAPICommand("test") + .withArguments(new DoubleArgument("double")) + .withArguments(new TextArgument("text")) + .withOptionalArguments(new EntitySelectorArgument.ManyEntities("entities")) + .withOptionalArguments(new GreedyStringArgument("message")) + .executesPlayer(info -> { + results.set(info.args().getRaw("double")); + results.set(info.args().getRaw("text")); + results.set(info.args().getRawOptional("entities").orElse("")); + results.set(info.args().getRawOptional("message").orElse("")); + }) + .register(); + + PlayerMock player = server.addPlayer(); + + server.dispatchCommand(player, "test 15.34 \"This is interesting text\""); + assertEquals("15.34", results.get()); + assertEquals("\"This is interesting text\"", results.get()); + assertEquals("", results.get()); + assertEquals("", results.get()); + + server.dispatchCommand(player, "test 15.34 \"This is interesting text\" @e"); + assertEquals("15.34", results.get()); + assertEquals("\"This is interesting text\"", results.get()); + assertEquals("@e", results.get()); + assertEquals("", results.get()); + + server.dispatchCommand(player, "test 15.34 \"This is interesting text\" @e Hello, everyone! This is a test which passes and doesn't throw any error!"); + assertEquals("15.34", results.get()); + assertEquals("\"This is interesting text\"", results.get()); + assertEquals("@e", results.get()); + assertEquals("Hello, everyone! This is a test which passes and doesn't throw any error!", results.get()); + + assertNoMoreResults(results); + } + +} diff --git a/docssrc/src/SUMMARY.md b/docssrc/src/SUMMARY.md index 0eaad72b37..a55be10bf1 100644 --- a/docssrc/src/SUMMARY.md +++ b/docssrc/src/SUMMARY.md @@ -32,6 +32,7 @@ - [Resulting command executors](./resultingcommandexecutors.md) - [Handling command failures](./commandfailures.md) - [Command arguments](./arguments.md) + - [CommandArguments](./commandarguments.md) - [Optional arguments](./optional_arguments.md) - [Listed arguments](./listed.md) - [Argument suggestions](./argumentsuggestions.md) diff --git a/docssrc/src/argument_entities.md b/docssrc/src/argument_entities.md index 986a6cf3d8..58fb0bd5df 100644 --- a/docssrc/src/argument_entities.md +++ b/docssrc/src/argument_entities.md @@ -13,7 +13,7 @@ There are four `EntitySelectorArgument` subclasses that determine what type of d - `EntitySelectorArgument.OnePlayer` - A single player, which returns a `Player` object. - `EntitySelectorArgument.ManyPlayers` - A collection of players, which returns a `Collection` object. -The return type is the type to be cast when retrieved from the `CommandArguments args` in the command declaration. +The return type is the type to be cast when retrieved from the [`CommandArguments args`](./commandarguments.md) in the command declaration.
diff --git a/docssrc/src/argument_literal.md b/docssrc/src/argument_literal.md index eb9d984703..2e2436068b 100644 --- a/docssrc/src/argument_literal.md +++ b/docssrc/src/argument_literal.md @@ -30,7 +30,7 @@ There is a simpler alternative to the `LiteralArgument` class! Instead of having ## Literal arguments vs regular arguments -Unlike regular arguments that are shown in this chapter, the literal argument is _technically_ not an argument. Due to this fact, literal arguments are [unlisted](./listed.md) by default. In other words, **the literal argument is not present in the `CommandArguments args` for the command declaration.** +Unlike regular arguments that are shown in this chapter, the literal argument is _technically_ not an argument. Due to this fact, literal arguments are [unlisted](./listed.md) by default. In other words, **the literal argument is not present in the [`CommandArguments args`](./commandarguments.md) for the command declaration.**
diff --git a/docssrc/src/argument_multiliteral.md b/docssrc/src/argument_multiliteral.md index f3059eea50..8ab85e6be3 100644 --- a/docssrc/src/argument_multiliteral.md +++ b/docssrc/src/argument_multiliteral.md @@ -1,8 +1,8 @@ # Multi literal arguments -So far, we've described normal arguments and literal arguments. We've described the nuances with literal arguments and how they're not really "arguments", so they don't appear in the `CommandArguments args` for commands. +So far, we've described normal arguments and literal arguments. We've described the nuances with literal arguments and how they're not really "arguments", so they don't appear in the [`CommandArguments args`](./commandarguments.md) for commands. -Now forget all of that. Multi literal arguments are the same as literal arguments but they _do_ appear in the `CommandArguments args` for commands (i.e. they are [listed](./listed.md)). Multi literal arguments are just a way better alternative to literal arguments. The multi literal argument constructor allows you to provide a `String nodeName` and a `String... literals` of possible values which you can use for your command declaration. +Now forget all of that. Multi literal arguments are the same as literal arguments but they _do_ appear in the [`CommandArguments args`](./commandarguments.md) for commands (i.e. they are [listed](./listed.md)). Multi literal arguments are just a way better alternative to literal arguments. The multi literal argument constructor allows you to provide a `String nodeName` and a `String... literals` of possible values which you can use for your command declaration. The multi literal argument has all of the same benefits of a regular literal argument - they are hardcoded options that the user must enter - they don't allow other values. diff --git a/docssrc/src/arguments.md b/docssrc/src/arguments.md index 9284f33655..dc8f53ba30 100644 --- a/docssrc/src/arguments.md +++ b/docssrc/src/arguments.md @@ -75,7 +75,7 @@ The CommandAPI is very flexible when it comes to registering arguments, and lets ## Argument Casting -To access arguments, they have to be casted to the type that the argument represents. The order of the arguments in the `CommandArguments args` is the same as the order in which the arguments were declared. +To access arguments, they have to be casted to the type that the argument represents. The order of the arguments in the [`CommandArguments args`](./commandarguments.md) is the same as the order in which the arguments were declared.
@@ -133,7 +133,7 @@ The type to cast each argument (declared in the `dev.jorel.commandapi.arguments` | [`LocationArgument`](./argument_locations.md#location-3d-space) | `org.bukkit.Location` | | [`LongArgument`](./argument_primitives.md#numerical-arguments) | `long` | | [`LootTableArgument`](./argument_loottable.md) | `org.bukkit.loot.LootTable` | - | [`MapArgument`](./argument_map.md) | `java.util.LinkedhashMap` | + | [`MapArgument`](./argument_map.md) | `java.util.LinkedHashMap` | | [`MathOperationArgument`](./argument_mathoperation.md) | `dev.jorel.commandapi.wrappers.MathOperation` | | [`MultiLiteralArgument`](./argument_multiliteral.md) | `String` | | [`NamespacedKeyArgument`](./argument_namespacedkey.md) | `org.bukkit.NamespacedKey` | diff --git a/docssrc/src/commandarguments.md b/docssrc/src/commandarguments.md new file mode 100644 index 0000000000..a705124846 --- /dev/null +++ b/docssrc/src/commandarguments.md @@ -0,0 +1,256 @@ +# CommandArguments + +The `CommandArguments` class was introduced in CommandAPI 9.0.0 and provides a much more powerful way of accessing arguments than just an array of arguments which existed until 9.0.0. + +While the argument array just gives the possibility to access the arguments via the array notation (`args[0]`), the `CommandArguments` class offers much more, including: + +- [Access the inner structure directly](#access-the-inner-structure-directly) +- [Access arguments](#access-arguments) +- [Access raw arguments](#access-raw-arguments) +- [Access unsafe arguments](#access-unsafe-arguments) + +----- + +## Access the inner structure directly + +To access the inner structure of the `CommandArguments` class directly, it provides various methods which you can learn about below: + +**Get the argument array** + +```java +Object[] args(); +``` + +This returns the array of arguments as defined when creating your command. + +**Get the arguments mapped to their node name** + +```java +Map argsMap(); +``` + +This returns an unmodifiable map which contains the arguments mapped to their node names. + +**Get the raw argument array** + +```java +String[] rawArgs(); + ``` + +This returns the array of raw arguments. An explanation of what raw arguments are can be found in the section about [accessing raw arguments](#access-raw-arguments). + +**Get the raw arguments mapped to their node name** + +```java +Map rawArgsMap(); +``` + +This returns an unmodifiable map which contains the raw arguments mapped to their node names. An explanation of what raw arguments are can be found in the section about [accessing raw arguments](#access-raw-arguments). + +**Other useful methods** + +```java +String fullInput(); // Returns the full command input (including the / character) +int count(); // Returns the amount of arguments +``` + +----- + +## Access arguments + +The `CommandArguments` class provides its arguments in a way similar to how a `List` or `Map` let you access their contents. When using these methods, you need to cast the arguments to their respective type. The `CommandArguments` class also provides a way to [access unsafe arguments](#access-unsafe-arguments). + +You can choose to access arguments by their node name or by their index. + +### Access arguments by node name + +Accessing arguments by their node name is the recommended way of accessing arguments. + +There are four methods you can use to access arguments by their node name: + +```java +Object get(String nodeName); +Object getOrDefault(String nodeName, Object defaultValue); +Object getOrDefault(String nodeName, Supplier defaultValue); +Optional getOptional(String nodeName); +``` + +### Access arguments by index + +Accessing arguments by their index is the original way of accessing arguments. However, we recommend to [access arguments by node name](#access-arguments-by-node-name). + +Similar to the four methods of accessing arguments by their node name, there also are four methods you can use to access arguments by their index: + +```java +Object get(int index); +Object getOrDefault(int index, Object defaultValue); +Object getOrDefault(int index, Supplier defaultValue); +Optional getOptional(int index); +``` + +
+ +### Example - Access arguments by node name and index + +To demonstrate the different ways of accessing arguments, we want to register a command `/mycommand` like this: + +```mccmd +/mycommand +/mycommand +/mycommand +/mycommand +``` + +This is how these commands are implemented: + +
+ +```java,Java +{{#include ../../commandapi-documentation-code/src/main/java/dev/jorel/commandapi/examples/java/Examples.java:commandArguments1}} +``` + +```kotlin,Kotlin +{{#include ../../commandapi-documentation-code/src/main/kotlin/dev/jorel/commandapi/examples/kotlin/Examples.kt:commandArguments1}} +``` + +
+ +
+ +----- + +## Access raw arguments + +A "raw argument" is the `String` form of an argument as written in a command. For example: + +A user defines a command `/mycommand` that accepts a `double` as the first argument and an entity selector as the second argument. It could be executed with the values `15.3` as the `double` value and `@e` as the entity selector: + +```mccmd +/mycommand 15.3 @e +``` + +When [accessing the raw arguments](#access-raw-arguments) of this command there are `15.3` and `@e` available as `String`s. + +However, when [accessing the arguments](#access-arguments) of this command there is `15.3` available as `double` and `@e` available as `Collection`. + +Raw arguments are accessed basically the same way you would [access arguments](#access-arguments). You can access them by their node name and their index in the argument array. + +### Access raw arguments by node name + +Accessing raw arguments by their node name is the recommended way of doing it. + +To access raw arguments by their node name, you can use these methods: + +```java +String getRaw(String nodeName); +String getOrDefaultRaw(String nodeName, String defaultValue); +String getOrDefaultRaw(String nodeName, Supplier defaultValue); +Optional getRawOptional(String nodeName); +``` + +### Access raw arguments by index + +Of course, if you don't want to access raw arguments by their node name, we also provide the option to access them by index with these methods: + +```java +String getRaw(int index); +String getOrDefaultRaw(int index, String defaultValue); +String getOrDefaultRaw(int index, Supplier defaultValue); +Optional getRawOptional(int index); +``` + +
+ +### Example - Access raw arguments by node name and index + +To demonstrate how to access raw arguments, we are going to implement the `/mycommand` again, this time with the following syntax: + +```mccmd +/mycommand +``` + +We want to find out which entity selector is being used when the command is executed. + +
+ +```java,Java +{{#include ../../commandapi-documentation-code/src/main/java/dev/jorel/commandapi/examples/java/Examples.java:commandArguments2}} +``` + +```kotlin,Kotlin +{{#include ../../commandapi-documentation-code/src/main/kotlin/dev/jorel/commandapi/examples/kotlin/Examples.kt:commandArguments2}} +``` + +
+ +
+ +----- + +## Access unsafe arguments + +When [accessing arguments](#access-arguments) you need to cast the `Object` returned by these methods to the type the argument returns. More about casting arguments [here](./arguments.md#argument-casting). + +Unsafe arguments provide the ability to access an argument without needing to cast it to the argument's type. When not using unsafe arguments, your code looks like this: + +```java +String name = (String) args.get("name"); +``` + +When using unsafe arguments you can make your code look like this: + +```java +String name = args.getUnchecked("name"); +``` + +Unsafe arguments can also be accessed by their node names and their indices. + +### Access arguments by node name + +Unsafe arguments can also be accessed by node name which, again, is the recommended way of doing it. + +Use these methods when accessing unsafe arguments by their node name: + +```java +T getUnchecked(String nodeName); +T getOrDefaultUnchecked(String nodeName, T defaultValue); +T getOrDefaultUnchecked(String nodeName, Supplier defaultValue); +Optional getOptionalUnchecked(String nodeName); +``` + +### Access arguments by index + +If you want to access unsafe arguments by index, you can do that by using these methods: + +```java +T getUnchecked(int index); +T getOrDefaultUnchecked(int index, T defaultValue); +T getOrDefaultUnchecked(int index, Supplier defaultValue); +Optional getOptionalUnchecked(int index); +``` + +
+ +### Example - Access unsafe arguments by node name and index + +Finally, we want to implement the `/mycommand` again. This time we use this syntax: + +```mccmd +/mycommand +``` + +Here, we don't actually want to cast the argument, so we use unsafe arguments to remove that cast: + +
+ +```java,Java +{{#include ../../commandapi-documentation-code/src/main/java/dev/jorel/commandapi/examples/java/Examples.java:commandArguments3}} +``` + +```kotlin,Kotlin +{{#include ../../commandapi-documentation-code/src/main/kotlin/dev/jorel/commandapi/examples/kotlin/Examples.kt:commandArguments3}} +``` + +
+ +
diff --git a/docssrc/src/intro.md b/docssrc/src/intro.md index ac4b8c7a5b..2d296967cb 100644 --- a/docssrc/src/intro.md +++ b/docssrc/src/intro.md @@ -40,6 +40,7 @@ Here's the list of changes to the documentation between each update. You can vie ### Documentation changes 9.0.3 \\(\rightarrow\\) 9.0.4 - Updates [Multi literal arguments](./argument_multiliteral.md) page to mention new `MultiLiteralArgument` constructor +- Adds [CommandArguments](./commandarguments.md) page to explain the `CommandArguments` class introduced in 9.0.0 ### Documentation changes 9.0.2 \\(\rightarrow\\) 9.0.3 diff --git a/docssrc/src/listed.md b/docssrc/src/listed.md index 0d3163d161..f40d56bf82 100644 --- a/docssrc/src/listed.md +++ b/docssrc/src/listed.md @@ -1,8 +1,8 @@ # Listed arguments -Arguments have a setting which determine whether or not they are present in the `CommandArguments args` that is populated when executing a command. +Arguments have a setting which determine whether or not they are present in the [`CommandArguments args`](./commandarguments.md) that is populated when executing a command. -By default, the `LiteralArgument` has this setting set to `false`, hence the literal values are _not_ present in the `CommandArguments args`. +By default, the `LiteralArgument` has this setting set to `false`, hence the literal values are _not_ present in the [`CommandArguments args`](commandarguments.md). This flag is set using the following function: @@ -20,7 +20,7 @@ Say we have the following command: /mycommand ``` -Let's also say that in our implementation of this command, we don't actually perform any processing for ``. Hence, listing it in the `CommandArguments args` is unnecessary. +Let's also say that in our implementation of this command, we don't actually perform any processing for ``. Hence, listing it in the [`CommandArguments args`](./commandarguments.md) is unnecessary.
@@ -34,6 +34,6 @@ Let's also say that in our implementation of this command, we don't actually per
-In this scenario, the argument `` is not present in the `CommandArguments args` for the executor. +In this scenario, the argument `` is not present in the [`CommandArguments args`](./commandarguments.md) for the executor. diff --git a/docssrc/src/normalexecutors.md b/docssrc/src/normalexecutors.md index c2f56ff032..1601ed1824 100644 --- a/docssrc/src/normalexecutors.md +++ b/docssrc/src/normalexecutors.md @@ -1,6 +1,6 @@ # Normal command executors -Command executors are of the following format, where `sender` is a [`CommandSender`](https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/command/CommandSender.html), and `args` is a `CommandArguments` object, which represents arguments which are parsed by the CommandAPI. +Command executors are of the following format, where `sender` is a [`CommandSender`](https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/command/CommandSender.html), and `args` is a [`CommandArguments`](./commandarguments.md) object, which represents arguments which are parsed by the CommandAPI. ```java new CommandAPICommand("...") diff --git a/docssrc/src/optional_arguments.md b/docssrc/src/optional_arguments.md index 1578a57fd3..ac47fec0b1 100644 --- a/docssrc/src/optional_arguments.md +++ b/docssrc/src/optional_arguments.md @@ -78,24 +78,19 @@ However, calling `withOptionalArguments` is safer because it makes sure that the ## Avoiding null values -Previously, we've looked at how to handle null values. To make all of this easier, the CommandAPI implements multiple `getOptional()` methods for `CommandArguments`: - -
- -> **Developer's Note:** -> -> For 9.0.1, all `CommandArguments#getOrDefault()` methods have been deprecated and new methods have been added! -> The existing methods will be removed in an upcoming version! -> -> View the new methods below: - -
+Previously, we've looked at how to handle null values. To make all of this easier, the CommandAPI implements multiple additional methods for [`CommandArguments`](./commandarguments.md): ```java +Object getOrDefault(int index, Object defaultValue); +Object getOrDefault(int index, Supplier defaultValue); +Object getOrDefault(String nodeName, Object defaultValue); +Object getOrDefault(String nodeName, Supplier defaultValue); Optional getOptional(int index) Optional getOptional(String nodeName) ``` +The examples will be using the `getOptional` methods but there is no downside of using the `getOrDefault` methods. +
### Example - /sayhi command while using the getOptional method diff --git a/docssrc/src/stringargumentsuggestions.md b/docssrc/src/stringargumentsuggestions.md index 3d640d8925..401ea65ae4 100644 --- a/docssrc/src/stringargumentsuggestions.md +++ b/docssrc/src/stringargumentsuggestions.md @@ -104,7 +104,7 @@ This won't work, because we make use of a redirect: \\(\texttt{/execute run} \xrightarrow{redirect} \texttt{mycommand arg1 arg2 arg3}\\) -It is not possible to access the `CommandArguments` of previously declared arguments. **If a command occurs via a redirect, the `CommandArguments` of previously declared arguments will be null**. +It is not possible to access the [`CommandArguments`](./commandarguments.md) of previously declared arguments. **If a command occurs via a redirect, the [`CommandArguments`](./commandarguments.md) of previously declared arguments will be null**.
diff --git a/docssrc/src/upgrading.md b/docssrc/src/upgrading.md index 6b3abd6206..453f5f593c 100644 --- a/docssrc/src/upgrading.md +++ b/docssrc/src/upgrading.md @@ -24,11 +24,15 @@ withArguments(new MultiLiteralArgument("gamemodes", "survival", "creative", "adv +### CommandArguments changes + +For 9.0.4 all deprecated methods are no longer deprecated. To learn about all the methods now available, refer to the [CommandArguments](./commandarguments.md) page. + ## From 9.0.1 to 9.0.2 ### MultiLiteralArgument and LiteralArgument changes -In previous versions, the ability has been introduced to access arguments by their node names. However, while this was possible for every other argument, it wasn't possible for `MultiLiteralArgument`s. This was now changed because the values from the `MultiLiteralArgument` are included in the `CommandArguments` of a command. +In previous versions, the ability has been introduced to access arguments by their node names. However, while this was possible for every other argument, it wasn't possible for `MultiLiteralArgument`s. This was now changed because the values from the `MultiLiteralArgument` are included in the [`CommandArguments`](./commandarguments.md) of a command. Therefore, the current constructor has been deprecated and the new one should be used: @@ -50,7 +54,7 @@ withArguments(new MultiLiteralArgument("gamemodes", List.of("survival", "creativ -Because it is possible to list `LiteralArgument`s in the `CommandArguments` of a command, there was also an additional constructor add to the `LiteralArgument` class. The other one is not deprecated. +Because it is possible to list `LiteralArgument`s in the [`CommandArguments`](./commandarguments.md) of a command, there was also an additional constructor add to the `LiteralArgument` class. The other one is not deprecated. Now, the `LiteralArgument` class contains two possible constructors: diff --git a/pom.xml b/pom.xml index 711c2ece77..3e86d1d7f7 100644 --- a/pom.xml +++ b/pom.xml @@ -88,7 +88,7 @@ - 1.19.2-R0.1-SNAPSHOT + 1.19.4-R0.1-SNAPSHOT 1.0.1