diff --git a/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/BukkitBrigadierMapper.java b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/BukkitBrigadierMapper.java index c630d56a..9b25ab2f 100644 --- a/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/BukkitBrigadierMapper.java +++ b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/BukkitBrigadierMapper.java @@ -30,9 +30,7 @@ import cloud.commandframework.bukkit.arguments.selector.SingleEntitySelector; import cloud.commandframework.bukkit.arguments.selector.SinglePlayerSelector; import com.mojang.brigadier.arguments.ArgumentType; import org.bukkit.Bukkit; -import org.bukkit.Material; import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.EntityType; import org.checkerframework.checker.nullness.qual.NonNull; import java.lang.reflect.Constructor; @@ -81,10 +79,6 @@ public final class BukkitBrigadierMapper { } /* Map Enchantment */ this.mapSimpleNMS(Enchantment.class, this.getNMSArgument("Enchantment").getConstructor()); - /* Map EntityType */ - this.mapSimpleNMS(EntityType.class, this.getNMSArgument("EntitySummon").getConstructor()); - /* Map Material */ - this.mapSimpleNMS(Material.class, this.getNMSArgument("ItemStack").getConstructor()); /* Map Entity Selectors */ this.mapComplexNMS(SingleEntitySelector.class, this.getEntitySelectorArgument(true, false)); this.mapComplexNMS(SinglePlayerSelector.class, this.getEntitySelectorArgument(true, true)); diff --git a/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/BukkitCommandManager.java b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/BukkitCommandManager.java index fd3daf66..f571fb2b 100644 --- a/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/BukkitCommandManager.java +++ b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/BukkitCommandManager.java @@ -29,6 +29,7 @@ import cloud.commandframework.bukkit.arguments.selector.MultipleEntitySelector; import cloud.commandframework.bukkit.arguments.selector.MultiplePlayerSelector; import cloud.commandframework.bukkit.arguments.selector.SingleEntitySelector; import cloud.commandframework.bukkit.arguments.selector.SinglePlayerSelector; +import cloud.commandframework.bukkit.parsers.EnchantmentArgument; import cloud.commandframework.bukkit.parsers.MaterialArgument; import cloud.commandframework.bukkit.parsers.OfflinePlayerArgument; import cloud.commandframework.bukkit.parsers.PlayerArgument; @@ -46,6 +47,7 @@ import org.bukkit.Material; import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.command.CommandSender; +import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.checkerframework.checker.nullness.qual.NonNull; @@ -135,18 +137,16 @@ public class BukkitCommandManager extends CommandManager { this.registerCommandPreProcessor(new BukkitCommandPreprocessor<>(this)); /* Register Bukkit Parsers */ - this.getParserRegistry().registerParserSupplier(TypeToken.get(World.class), params -> new WorldArgument.WorldParser<>()); - this.getParserRegistry().registerParserSupplier( - TypeToken.get(Material.class), - params -> new MaterialArgument.MaterialParser<>() - ); - this.getParserRegistry() - .registerParserSupplier(TypeToken.get(Player.class), params -> new PlayerArgument.PlayerParser<>()); - this.getParserRegistry() - .registerParserSupplier( - TypeToken.get(OfflinePlayer.class), - params -> new OfflinePlayerArgument.OfflinePlayerParser<>() - ); + this.getParserRegistry().registerParserSupplier(TypeToken.get(World.class), parserParameters -> + new WorldArgument.WorldParser<>()); + this.getParserRegistry().registerParserSupplier(TypeToken.get(Material.class), parserParameters -> + new MaterialArgument.MaterialParser<>()); + this.getParserRegistry().registerParserSupplier(TypeToken.get(Player.class), parserParameters -> + new PlayerArgument.PlayerParser<>()); + this.getParserRegistry().registerParserSupplier(TypeToken.get(OfflinePlayer.class), parserParameters -> + new OfflinePlayerArgument.OfflinePlayerParser<>()); + this.getParserRegistry().registerParserSupplier(TypeToken.get(Enchantment.class), parserParameters -> + new EnchantmentArgument.EnchantmentParser<>()); /* Register Entity Selector Parsers */ this.getParserRegistry().registerParserSupplier(TypeToken.get(SingleEntitySelector.class), parserParameters -> new SingleEntitySelectorArgument.SingleEntitySelectorParser<>()); diff --git a/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/parsers/EnchantmentArgument.java b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/parsers/EnchantmentArgument.java new file mode 100644 index 00000000..08ee8603 --- /dev/null +++ b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/parsers/EnchantmentArgument.java @@ -0,0 +1,190 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg & Contributors +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +package cloud.commandframework.bukkit.parsers; + +import cloud.commandframework.arguments.CommandArgument; +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.context.CommandContext; +import org.bukkit.NamespacedKey; +import org.bukkit.enchantments.Enchantment; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Queue; +import java.util.function.BiFunction; + +/** + * cloud argument type that parses Bukkit {@link Enchantment enchantments} + * + * @param Command sender type + */ +public class EnchantmentArgument extends CommandArgument { + + protected EnchantmentArgument( + final boolean required, + final @NonNull String name, + final @NonNull String defaultValue, + final @Nullable BiFunction<@NonNull CommandContext, @NonNull String, + @NonNull List<@NonNull String>> suggestionsProvider + ) { + super(required, name, new EnchantmentParser<>(), defaultValue, Enchantment.class, suggestionsProvider); + } + + /** + * Create a new builder + * + * @param name Name of the argument + * @param Command sender type + * @return Created builder + */ + public static EnchantmentArgument.@NonNull Builder newBuilder(final @NonNull String name) { + return new EnchantmentArgument.Builder<>(name); + } + + /** + * Create a new required argument + * + * @param name Argument name + * @param Command sender type + * @return Created argument + */ + public static @NonNull CommandArgument of(final @NonNull String name) { + return EnchantmentArgument.newBuilder(name).asRequired().build(); + } + + /** + * Create a new optional argument + * + * @param name Argument name + * @param Command sender type + * @return Created argument + */ + public static @NonNull CommandArgument optional(final @NonNull String name) { + return EnchantmentArgument.newBuilder(name).asOptional().build(); + } + + /** + * Create a new optional argument with a default value + * + * @param name Argument name + * @param enchantment Default value + * @param Command sender type + * @return Created argument + */ + public static @NonNull CommandArgument optional( + final @NonNull String name, + final @NonNull Enchantment enchantment + ) { + return EnchantmentArgument.newBuilder(name).asOptionalWithDefault(enchantment.getKey().toString()).build(); + } + + public static final class Builder extends CommandArgument.Builder { + + protected Builder(final @NonNull String name) { + super(Enchantment.class, name); + } + + } + + public static final class EnchantmentParser implements ArgumentParser { + + @Override + public @NonNull ArgumentParseResult parse( + final @NonNull CommandContext commandContext, + final @NonNull Queue<@NonNull String> inputQueue + ) { + final String input = inputQueue.peek(); + if (input == null) { + return ArgumentParseResult.failure(new NullPointerException("No input was provided")); + } + + final NamespacedKey key; + if (input.contains(":")) { + final String[] splitInput = input.split(":"); + //noinspection deprecation + key = new NamespacedKey(splitInput[0], splitInput[1]); + } else { + key = NamespacedKey.minecraft(input); + } + + final Enchantment enchantment = Enchantment.getByKey(key); + if (enchantment == null) { + return ArgumentParseResult.failure(new EnchantmentParseException(input)); + } + inputQueue.remove(); + return ArgumentParseResult.success(enchantment); + } + + @Override + public @NonNull List<@NonNull String> suggestions( + final @NonNull CommandContext commandContext, + final @NonNull String input + ) { + final List completions = new ArrayList<>(); + for (Enchantment value : Enchantment.values()) { + if (value.getKey().getNamespace().equals(NamespacedKey.MINECRAFT)) { + completions.add(value.getKey().getKey()); + } else { + completions.add(value.getKey().toString()); + } + } + return completions; + } + + } + + + public static final class EnchantmentParseException extends IllegalArgumentException { + + private final String input; + + /** + * Construct a new EnchantmentParseException + * + * @param input Input + */ + public EnchantmentParseException(final @NonNull String input) { + this.input = input; + } + + /** + * Get the input + * + * @return Input + */ + public @NonNull String getInput() { + return this.input; + } + + @Override + public String getMessage() { + return String.format("'%s' is not a valid enchantment", this.input); + } + + } + +} diff --git a/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/parsers/MaterialArgument.java b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/parsers/MaterialArgument.java index 21afd704..9497cb24 100644 --- a/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/parsers/MaterialArgument.java +++ b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/parsers/MaterialArgument.java @@ -31,6 +31,7 @@ import org.bukkit.Material; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import java.util.ArrayList; import java.util.List; import java.util.Queue; import java.util.function.BiFunction; @@ -108,7 +109,6 @@ public class MaterialArgument extends CommandArgument { } - public static final class MaterialParser implements ArgumentParser { @Override @@ -121,21 +121,27 @@ public class MaterialArgument extends CommandArgument { return ArgumentParseResult.failure(new NullPointerException("No input was provided")); } - /* Pre-process input */ - if (input.contains("minecraft:")) { - input = input.substring("minecraft:".length()); - } - input = input.toUpperCase(); - try { - final Material material = Material.valueOf(input); + final Material material = Material.valueOf(input.toUpperCase()); inputQueue.remove(); return ArgumentParseResult.success(material); } catch (final IllegalArgumentException exception) { - return ArgumentParseResult.failure(new MaterialParseException(inputQueue.peek())); + return ArgumentParseResult.failure(new MaterialParseException(input)); } } + @Override + public @NonNull List<@NonNull String> suggestions( + final @NonNull CommandContext commandContext, + final @NonNull String input + ) { + final List completions = new ArrayList<>(); + for (Material value : Material.values()) { + completions.add(value.name().toLowerCase()); + } + return completions; + } + } diff --git a/cloud-minecraft/cloud-minecraft-extras/build.gradle b/cloud-minecraft/cloud-minecraft-extras/build.gradle index d79d3ce4..91894abc 100644 --- a/cloud-minecraft/cloud-minecraft-extras/build.gradle +++ b/cloud-minecraft/cloud-minecraft-extras/build.gradle @@ -1,5 +1,4 @@ dependencies { - api 'net.kyori:adventure-api:4.0.0-SNAPSHOT' api project(':cloud-core') - api 'net.kyori:adventure-text-minimessage:4.0.0-SNAPSHOT' + api 'net.kyori:adventure-api:4.0.0-SNAPSHOT' } diff --git a/cloud-minecraft/cloud-paper/src/main/java/cloud/commandframework/paper/PaperCommandManager.java b/cloud-minecraft/cloud-paper/src/main/java/cloud/commandframework/paper/PaperCommandManager.java index e55b118f..5f07996b 100644 --- a/cloud-minecraft/cloud-paper/src/main/java/cloud/commandframework/paper/PaperCommandManager.java +++ b/cloud-minecraft/cloud-paper/src/main/java/cloud/commandframework/paper/PaperCommandManager.java @@ -56,10 +56,8 @@ public class PaperCommandManager extends BukkitCommandManager { CommandExecutionCoordinator> commandExecutionCoordinator, final @NonNull Function commandSenderMapper, final @NonNull Function backwardsCommandSenderMapper - ) throws - Exception { + ) throws Exception { super(owningPlugin, commandExecutionCoordinator, commandSenderMapper, backwardsCommandSenderMapper); - } /** diff --git a/examples/example-bukkit/src/main/java/cloud/commandframework/examples/bukkit/ExamplePlugin.java b/examples/example-bukkit/src/main/java/cloud/commandframework/examples/bukkit/ExamplePlugin.java index 5dde5db1..023ed717 100644 --- a/examples/example-bukkit/src/main/java/cloud/commandframework/examples/bukkit/ExamplePlugin.java +++ b/examples/example-bukkit/src/main/java/cloud/commandframework/examples/bukkit/ExamplePlugin.java @@ -49,6 +49,8 @@ import cloud.commandframework.bukkit.BukkitCommandManager; import cloud.commandframework.bukkit.BukkitCommandMetaBuilder; import cloud.commandframework.bukkit.CloudBukkitCapabilities; import cloud.commandframework.bukkit.arguments.selector.SingleEntitySelector; +import cloud.commandframework.bukkit.parsers.EnchantmentArgument; +import cloud.commandframework.bukkit.parsers.MaterialArgument; import cloud.commandframework.bukkit.parsers.WorldArgument; import cloud.commandframework.bukkit.parsers.selector.SingleEntitySelectorArgument; import cloud.commandframework.context.CommandContext; @@ -71,6 +73,8 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.command.CommandSender; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; @@ -287,7 +291,7 @@ public final class ExamplePlugin extends JavaPlugin { )); manager.command(manager.commandBuilder("give") .senderType(Player.class) - .argument(EnumArgument.of(Material.class, "material")) + .argument(MaterialArgument.of("material")) .argument(IntegerArgument.of("amount")) .handler(c -> { final Material material = c.get("material"); @@ -296,6 +300,21 @@ public final class ExamplePlugin extends JavaPlugin { ((Player) c.getSender()).getInventory().addItem(itemStack); c.getSender().sendMessage("You've been given stuff, bro."); })); + manager.command(builder.literal("summon") + .senderType(Player.class) + .argument(EnumArgument.of(EntityType.class, "type")) + .handler(c -> manager.taskRecipe().begin(c).synchronous(ctx -> { + final Location loc = ((Player) ctx.getSender()).getLocation(); + loc.getWorld().spawnEntity(loc, ctx.get("type")); + }).execute())); + manager.command(builder.literal("enchant") + .senderType(Player.class) + .argument(EnchantmentArgument.of("enchant")) + .argument(IntegerArgument.of("level")) + .handler(c -> manager.taskRecipe().begin(c).synchronous(ctx -> { + final Player player = ((Player) ctx.getSender()); + player.getInventory().getItemInHand().addEnchantment(ctx.get("enchant"), ctx.get("level")); + }).execute())); // // An Argument Parser for TextColor that accepts NamedTextColor names or RGB colors in the format 'RRGGBB' @@ -419,7 +438,8 @@ public final class ExamplePlugin extends JavaPlugin { final @NonNull Player player, final @NonNull @Argument("material") Material material, final @Argument("amount") int number, - final @Nullable @Flag("color") ChatColor nameColor + final @Nullable @Flag("color") ChatColor nameColor, + final @Nullable @Flag("enchant") Enchantment enchant ) { final ItemStack itemStack = new ItemStack(material, number); String itemName = String.format( @@ -437,6 +457,9 @@ public final class ExamplePlugin extends JavaPlugin { meta.setDisplayName(itemName); itemStack.setItemMeta(meta); } + if (enchant != null) { + itemStack.addUnsafeEnchantment(enchant, 10); + } player.getInventory().addItem(itemStack); player.sendMessage(ChatColor.GREEN + String.format("You have been given %d x %s", number, material)); }