diff --git a/.checkstyle/checkstyle-suppressions.xml b/.checkstyle/checkstyle-suppressions.xml index a2f26326..ebc790d1 100644 --- a/.checkstyle/checkstyle-suppressions.xml +++ b/.checkstyle/checkstyle-suppressions.xml @@ -4,5 +4,5 @@ "https://checkstyle.org/dtds/suppressions_1_2.dtd"> - + diff --git a/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/BukkitCommandPreprocessor.java b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/BukkitCommandPreprocessor.java index 563bd890..d9df87b1 100644 --- a/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/BukkitCommandPreprocessor.java +++ b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/BukkitCommandPreprocessor.java @@ -23,9 +23,13 @@ // package cloud.commandframework.bukkit; +import cloud.commandframework.brigadier.argument.WrappedBrigadierParser; +import cloud.commandframework.bukkit.internal.BukkitBackwardsBrigadierSenderMapper; +import cloud.commandframework.bukkit.internal.CraftBukkitReflection; import cloud.commandframework.execution.preprocessor.CommandPreprocessingContext; import cloud.commandframework.execution.preprocessor.CommandPreprocessor; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import java.util.Set; @@ -39,6 +43,7 @@ final class BukkitCommandPreprocessor implements CommandPreprocessor { private final BukkitCommandManager commandManager; private final Set bukkitCapabilities; + private final @Nullable BukkitBackwardsBrigadierSenderMapper mapper; /** * The Bukkit Command Preprocessor for storing Bukkit-specific contexts in the command contexts @@ -48,10 +53,25 @@ final class BukkitCommandPreprocessor implements CommandPreprocessor { BukkitCommandPreprocessor(final @NonNull BukkitCommandManager commandManager) { this.commandManager = commandManager; this.bukkitCapabilities = commandManager.queryCapabilities(); + if (this.bukkitCapabilities.contains(CloudBukkitCapabilities.BRIGADIER) && CraftBukkitReflection.craftBukkit()) { + this.mapper = new BukkitBackwardsBrigadierSenderMapper<>(this.commandManager); + } else { + this.mapper = null; + } } @Override public void accept(final @NonNull CommandPreprocessingContext context) { + if (this.mapper != null) { + // If the server is Brigadier capable but the Brigadier manager has not been registered, store the native + // sender in context manually so that getting suggestions from WrappedBrigadierParser works like expected. + if (!context.getCommandContext().contains(WrappedBrigadierParser.COMMAND_CONTEXT_BRIGADIER_NATIVE_SENDER)) { + context.getCommandContext().store( + WrappedBrigadierParser.COMMAND_CONTEXT_BRIGADIER_NATIVE_SENDER, + this.mapper.apply(context.getCommandContext().getSender()) + ); + } + } context.getCommandContext().store( BukkitCommandContextKeys.BUKKIT_COMMAND_SENDER, this.commandManager.getBackwardsCommandSenderMapper().apply(context.getCommandContext().getSender()) diff --git a/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/CloudCommodoreManager.java b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/CloudCommodoreManager.java index aa684b9e..b3f2777a 100644 --- a/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/CloudCommodoreManager.java +++ b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/CloudCommodoreManager.java @@ -25,6 +25,7 @@ package cloud.commandframework.bukkit; import cloud.commandframework.Command; import cloud.commandframework.brigadier.CloudBrigadierManager; +import cloud.commandframework.bukkit.internal.BukkitBackwardsBrigadierSenderMapper; import cloud.commandframework.bukkit.internal.CraftBukkitReflection; import cloud.commandframework.context.CommandContext; import com.mojang.brigadier.tree.CommandNode; @@ -36,7 +37,6 @@ import org.bukkit.command.CommandSender; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -import java.lang.reflect.Method; import java.util.Collections; @SuppressWarnings({"unchecked", "rawtypes"}) @@ -64,19 +64,9 @@ class CloudCommodoreManager extends BukkitPluginRegistrationHandler { new BukkitBrigadierMapper<>(this.commandManager, this.brigadierManager); - if (!CraftBukkitReflection.craftBukkit()) { - return; + if (CraftBukkitReflection.craftBukkit()) { + this.brigadierManager.backwardsBrigadierSenderMapper(new BukkitBackwardsBrigadierSenderMapper<>(this.commandManager)); } - final Class vanillaCommandWrapperClass = CraftBukkitReflection.needOBCClass("command.VanillaCommandWrapper"); - final Method getListenerMethod = CraftBukkitReflection.needMethod( - vanillaCommandWrapperClass, "getListener", CommandSender.class); - this.brigadierManager.backwardsBrigadierSenderMapper(cloud -> { - try { - return getListenerMethod.invoke(null, this.commandManager.getBackwardsCommandSenderMapper().apply(cloud)); - } catch (final ReflectiveOperationException e) { - throw new RuntimeException(e); - } - }); } @Override diff --git a/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/internal/BukkitBackwardsBrigadierSenderMapper.java b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/internal/BukkitBackwardsBrigadierSenderMapper.java new file mode 100644 index 00000000..f67a36de --- /dev/null +++ b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/internal/BukkitBackwardsBrigadierSenderMapper.java @@ -0,0 +1,61 @@ +// +// MIT License +// +// Copyright (c) 2021 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.internal; + +import cloud.commandframework.bukkit.BukkitCommandManager; +import com.google.common.annotations.Beta; +import org.bukkit.command.CommandSender; +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.lang.reflect.Method; +import java.util.function.Function; + +/** + * This is not API, and as such, may break, change, or be removed without any notice. + */ +@Beta +public final class BukkitBackwardsBrigadierSenderMapper implements Function { + + private static final Class VANILLA_COMMAND_WRAPPER_CLASS = + CraftBukkitReflection.needOBCClass("command.VanillaCommandWrapper"); + private static final Method GET_LISTENER_METHOD = + CraftBukkitReflection.needMethod(VANILLA_COMMAND_WRAPPER_CLASS, "getListener", CommandSender.class); + + private final BukkitCommandManager commandManager; + + public BukkitBackwardsBrigadierSenderMapper(final @NonNull BukkitCommandManager commandManager) { + this.commandManager = commandManager; + } + + @SuppressWarnings("unchecked") + @Override + public S apply(final @NonNull C cloud) { + try { + return (S) GET_LISTENER_METHOD.invoke(null, this.commandManager.getBackwardsCommandSenderMapper().apply(cloud)); + } catch (final ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/internal/package-info.java b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/internal/package-info.java new file mode 100644 index 00000000..61b5a64f --- /dev/null +++ b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/internal/package-info.java @@ -0,0 +1,29 @@ +// +// MIT License +// +// Copyright (c) 2021 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. +// +/** + * Internal classes for the cloud-bukkit implementation. Classes in this package + * are not part of the API, and as such, may break, change, or be removed without + * any notice. + */ +package cloud.commandframework.bukkit.internal; diff --git a/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/parsers/ItemStackArgument.java b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/parsers/ItemStackArgument.java index a2e2de48..f7c929f8 100644 --- a/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/parsers/ItemStackArgument.java +++ b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/parsers/ItemStackArgument.java @@ -173,10 +173,7 @@ public final class ItemStackArgument extends CommandArgument commandContext, final @NonNull String input ) { - return Arrays.stream(Material.values()) - .filter(Material::isItem) - .map(value -> value.name().toLowerCase(Locale.ROOT)) - .collect(Collectors.toList()); + return this.parser.suggestions(commandContext, input); } } @@ -228,6 +225,14 @@ public final class ItemStackArgument extends CommandArgument suggestions( + final @NonNull CommandContext commandContext, + final @NonNull String input + ) { + return this.parser.suggestions(commandContext, input); + } + private static final class ModernProtoItemStack implements ProtoItemStack { private final Object itemInput; @@ -294,6 +299,17 @@ public final class ItemStackArgument extends CommandArgument suggestions( + final @NonNull CommandContext commandContext, + final @NonNull String input + ) { + return Arrays.stream(Material.values()) + .filter(Material::isItem) + .map(value -> value.name().toLowerCase(Locale.ROOT)) + .collect(Collectors.toList()); + } + private static final class LegacyProtoItemStack implements ProtoItemStack { private final Material material; diff --git a/cloud-minecraft/cloud-paper/src/main/java/cloud/commandframework/paper/PaperBrigadierListener.java b/cloud-minecraft/cloud-paper/src/main/java/cloud/commandframework/paper/PaperBrigadierListener.java index 8dafda73..7e33449d 100644 --- a/cloud-minecraft/cloud-paper/src/main/java/cloud/commandframework/paper/PaperBrigadierListener.java +++ b/cloud-minecraft/cloud-paper/src/main/java/cloud/commandframework/paper/PaperBrigadierListener.java @@ -27,18 +27,17 @@ import cloud.commandframework.CommandTree; import cloud.commandframework.arguments.CommandArgument; import cloud.commandframework.brigadier.CloudBrigadierManager; import cloud.commandframework.bukkit.BukkitBrigadierMapper; +import cloud.commandframework.bukkit.internal.BukkitBackwardsBrigadierSenderMapper; import cloud.commandframework.bukkit.internal.CraftBukkitReflection; import cloud.commandframework.context.CommandContext; import cloud.commandframework.permission.CommandPermission; import com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource; import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; import org.bukkit.command.PluginIdentifiableCommand; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.checkerframework.checker.nullness.qual.NonNull; -import java.lang.reflect.Method; import java.util.function.BiPredicate; import java.util.regex.Pattern; @@ -59,20 +58,10 @@ class PaperBrigadierListener implements Listener { new BukkitBrigadierMapper<>(this.paperCommandManager, this.brigadierManager); - if (!CraftBukkitReflection.craftBukkit()) { - return; + if (CraftBukkitReflection.craftBukkit()) { + this.brigadierManager + .backwardsBrigadierSenderMapper(new BukkitBackwardsBrigadierSenderMapper<>(this.paperCommandManager)); } - final Class vanillaCommandWrapperClass = CraftBukkitReflection.needOBCClass("command.VanillaCommandWrapper"); - final Method getListenerMethod = CraftBukkitReflection.needMethod( - vanillaCommandWrapperClass, "getListener", CommandSender.class); - this.brigadierManager.backwardsBrigadierSenderMapper(cloud -> { - try { - return (BukkitBrigadierCommandSource) getListenerMethod - .invoke(null, this.paperCommandManager.getBackwardsCommandSenderMapper().apply(cloud)); - } catch (final ReflectiveOperationException e) { - throw new RuntimeException(e); - } - }); } protected @NonNull CloudBrigadierManager brigadierManager() { 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 73ad5814..9391804c 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 @@ -26,8 +26,11 @@ package cloud.commandframework.examples.bukkit; import cloud.commandframework.ArgumentDescription; import cloud.commandframework.Command; import cloud.commandframework.CommandTree; +import cloud.commandframework.arguments.compound.ArgumentPair; +import cloud.commandframework.bukkit.data.ProtoItemStack; import cloud.commandframework.keys.SimpleCloudKey; import cloud.commandframework.minecraft.extras.MinecraftExceptionHandler; +import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys; import cloud.commandframework.minecraft.extras.MinecraftHelp; import cloud.commandframework.annotations.AnnotationParser; import cloud.commandframework.annotations.Argument; @@ -62,6 +65,7 @@ import cloud.commandframework.minecraft.extras.TextColorArgument; import cloud.commandframework.paper.PaperCommandManager; import cloud.commandframework.permission.PredicatePermission; import cloud.commandframework.tasks.TaskConsumer; +import cloud.commandframework.types.tuples.Pair; import cloud.commandframework.types.tuples.Triplet; import io.leangen.geantyref.TypeToken; import net.kyori.adventure.identity.Identity; @@ -410,6 +414,22 @@ public final class ExamplePlugin extends JavaPlugin { (sender, key) -> "'{input}' is not very cash money of you" ); } + + // vanilla-like give command + this.manager.command(this.manager.commandBuilder("givetest") + .senderType(Player.class) + .argument(ArgumentPair.of( + this.manager, + "itemstack", + Pair.of("item", "amount"), + Pair.of(ProtoItemStack.class, Integer.class) + ).withMapper(ItemStack.class, (sender, pair) -> { + final ProtoItemStack proto = pair.getFirst(); + final int amount = pair.getSecond(); + return proto.createItemStack(amount, true); + }), ArgumentDescription.of("The ItemStack to give")) + .meta(MinecraftExtrasMetaKeys.DESCRIPTION, text("Vanilla-like give command")) + .handler(ctx -> ((Player) ctx.getSender()).getInventory().addItem(ctx.get("itemstack")))); } @CommandMethod("example help [query]")