diff --git a/.checkstyle/checkstyle-suppressions.xml b/.checkstyle/checkstyle-suppressions.xml
index dcf53640..a2f26326 100644
--- a/.checkstyle/checkstyle-suppressions.xml
+++ b/.checkstyle/checkstyle-suppressions.xml
@@ -4,4 +4,5 @@
"https://checkstyle.org/dtds/suppressions_1_2.dtd">
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6a8a0bce..0e34848b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- JDA Role argument parser
+ - Bukkit: Implement parser for ProtoItemStack ([#257](https://github.com/Incendo/cloud/pull/257))
### Changed
- Use Command instead of TabCompleteEvent on Bukkit
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 c3a9b459..26d84990 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
@@ -23,21 +23,25 @@
//
package cloud.commandframework.bukkit;
+import cloud.commandframework.arguments.parser.ArgumentParser;
+import cloud.commandframework.arguments.standard.UUIDArgument;
import cloud.commandframework.brigadier.CloudBrigadierManager;
-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.location.Location2D;
+import cloud.commandframework.bukkit.internal.CraftBukkitReflection;
+import cloud.commandframework.bukkit.parsers.EnchantmentArgument;
+import cloud.commandframework.bukkit.parsers.ItemStackArgument;
+import cloud.commandframework.bukkit.parsers.location.Location2DArgument;
+import cloud.commandframework.bukkit.parsers.location.LocationArgument;
+import cloud.commandframework.bukkit.parsers.selector.MultipleEntitySelectorArgument;
+import cloud.commandframework.bukkit.parsers.selector.MultiplePlayerSelectorArgument;
+import cloud.commandframework.bukkit.parsers.selector.SingleEntitySelectorArgument;
+import cloud.commandframework.bukkit.parsers.selector.SinglePlayerSelectorArgument;
import com.mojang.brigadier.arguments.ArgumentType;
-import org.bukkit.Bukkit;
-import org.bukkit.Location;
-import org.bukkit.enchantments.Enchantment;
+import com.mojang.brigadier.arguments.StringArgumentType;
+import io.leangen.geantyref.GenericTypeReflector;
+import io.leangen.geantyref.TypeToken;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.util.UUID;
import java.util.function.Supplier;
import java.util.logging.Level;
@@ -46,14 +50,12 @@ import java.util.logging.Level;
*
* @param Command sender type
*/
-@SuppressWarnings({"unchecked", "rawtypes"})
public final class BukkitBrigadierMapper {
private static final int UUID_ARGUMENT_VERSION = 16;
private final BukkitCommandManager commandManager;
- private final CloudBrigadierManager brigadierManager;
- private final String nmsVersion;
+ private final CloudBrigadierManager brigadierManager;
/**
@@ -64,38 +66,48 @@ public final class BukkitBrigadierMapper {
*/
public BukkitBrigadierMapper(
final @NonNull BukkitCommandManager commandManager,
- final @NonNull CloudBrigadierManager brigadierManager
+ final @NonNull CloudBrigadierManager brigadierManager
) {
this.commandManager = commandManager;
this.brigadierManager = brigadierManager;
- /* Detect Minecraft Version Metadata */
- final String version = Bukkit.getServer().getClass().getPackage().getName();
- this.nmsVersion = version.substring(version.lastIndexOf(".") + 1);
- final int majorMinecraftVersion = Integer.parseInt(this.nmsVersion.split("_")[1]);
-
- try {
- /* UUID nms argument is a 1.16+ feature */
- if (majorMinecraftVersion >= UUID_ARGUMENT_VERSION) {
- /* Map UUID */
- this.mapSimpleNMS(UUID.class, this.getNMSArgument("UUID").getConstructor());
- }
- /* Map Enchantment */
- this.mapSimpleNMS(Enchantment.class, this.getNMSArgument("Enchantment").getConstructor());
- /* Map Entity Selectors */
- this.mapComplexNMS(SingleEntitySelector.class, this.getEntitySelectorArgument(true, false));
- this.mapComplexNMS(SinglePlayerSelector.class, this.getEntitySelectorArgument(true, true));
- this.mapComplexNMS(MultipleEntitySelector.class, this.getEntitySelectorArgument(false, false));
- this.mapComplexNMS(MultiplePlayerSelector.class, this.getEntitySelectorArgument(false, true));
- /* Map Vec3 */
- this.mapComplexNMS(Location.class, this.getArgumentVec3());
- /* Map Vec2I */
- this.mapComplexNMS(Location2D.class, this.getArgumentVec2I());
- } catch (final Exception e) {
- this.commandManager.getOwningPlugin()
- .getLogger()
- .log(Level.WARNING, "Failed to map Bukkit types to NMS argument types", e);
+ if (!CraftBukkitReflection.craftBukkit()) {
+ this.commandManager.getOwningPlugin().getLogger().warning(
+ "Could not detect relocated CraftBukkit package, NMS brigadier mappings will not be enabled.");
+ return;
}
+
+ this.registerMappings();
+ }
+
+ private void registerMappings() {
+ /* UUID nms argument is a 1.16+ feature */
+ if (CraftBukkitReflection.MAJOR_REVISION >= UUID_ARGUMENT_VERSION) {
+ /* Map UUID */
+ this.mapSimpleNMS(new TypeToken>() {
+ }, "UUID");
+ }
+ /* Map Enchantment */
+ this.mapSimpleNMS(new TypeToken>() {
+ }, "Enchantment");
+ /* Map ItemStackArgument */
+ this.mapSimpleNMS(new TypeToken>() {
+ }, "ItemStack");
+ /* Map Entity Selectors */
+ this.mapNMS(new TypeToken>() {
+ }, this.entitySelectorArgumentSupplier(true, false));
+ this.mapNMS(new TypeToken>() {
+ }, this.entitySelectorArgumentSupplier(true, true));
+ this.mapNMS(new TypeToken>() {
+ }, this.entitySelectorArgumentSupplier(false, false));
+ this.mapNMS(new TypeToken>() {
+ }, this.entitySelectorArgumentSupplier(false, true));
+ /* Map Vec3 */
+ this.mapNMS(new TypeToken>() {
+ }, this::argumentVec3);
+ /* Map Vec2I */
+ this.mapNMS(new TypeToken>() {
+ }, this::argumentVec2i);
}
/**
@@ -103,45 +115,39 @@ public final class BukkitBrigadierMapper {
* @param playersOnly Whether the selector is for players only (true), or for all entities (false)
* @return The NMS ArgumentType
*/
- private @NonNull Supplier> getEntitySelectorArgument(
+ private @NonNull Supplier> entitySelectorArgumentSupplier(
final boolean single,
final boolean playersOnly
) {
return () -> {
try {
- final Constructor> constructor = this.getNMSArgument("Entity").getDeclaredConstructors()[0];
+ final Constructor> constructor = getNMSArgument("Entity").getDeclaredConstructors()[0];
constructor.setAccessible(true);
return (ArgumentType>) constructor.newInstance(single, playersOnly);
} catch (final Exception e) {
this.commandManager.getOwningPlugin().getLogger().log(Level.INFO, "Failed to retrieve Selector Argument", e);
- return null;
+ return fallbackType();
}
};
}
- @SuppressWarnings("UnnecessaryLambda")
- private @NonNull Supplier> getArgumentVec3() {
- return () -> {
- try {
- return (ArgumentType>) this.getNMSArgument("Vec3").getDeclaredConstructor(boolean.class)
- .newInstance(true);
- } catch (final Exception e) {
- this.commandManager.getOwningPlugin().getLogger().log(Level.INFO, "Failed to retrieve Vec3D argument", e);
- return null;
- }
- };
+ private @NonNull ArgumentType> argumentVec3() {
+ try {
+ return (ArgumentType>) getNMSArgument("Vec3").getDeclaredConstructor(boolean.class)
+ .newInstance(true);
+ } catch (final Exception e) {
+ this.commandManager.getOwningPlugin().getLogger().log(Level.INFO, "Failed to retrieve Vec3D argument", e);
+ return fallbackType();
+ }
}
- @SuppressWarnings("UnnecessaryLambda")
- private @NonNull Supplier> getArgumentVec2I() {
- return () -> {
- try {
- return (ArgumentType>) this.getNMSArgument("Vec2I").getDeclaredConstructor().newInstance();
- } catch (final Exception e) {
- this.commandManager.getOwningPlugin().getLogger().log(Level.INFO, "Failed to retrieve Vec2I argument", e);
- return null;
- }
- };
+ private @NonNull ArgumentType> argumentVec2i() {
+ try {
+ return (ArgumentType>) getNMSArgument("Vec2I").getDeclaredConstructor().newInstance();
+ } catch (final Exception e) {
+ this.commandManager.getOwningPlugin().getLogger().log(Level.INFO, "Failed to retrieve Vec2I argument", e);
+ return fallbackType();
+ }
}
/**
@@ -149,40 +155,52 @@ public final class BukkitBrigadierMapper {
*
* @param argument Argument type name
* @return Argument class
- * @throws Exception If the type cannot be retrieved
+ * @throws RuntimeException when the class is not found
*/
- @NonNull
- private Class> getNMSArgument(final @NonNull String argument) throws Exception {
- return Class.forName(String.format("net.minecraft.server.%s.Argument%s", this.nmsVersion, argument));
+ private static @NonNull Class> getNMSArgument(final @NonNull String argument) throws RuntimeException {
+ return CraftBukkitReflection.needNMSClass("Argument" + argument);
}
/**
- * Attempt to register a mapping between a type and a NMS argument type
+ * Attempt to register a mapping between a cloud argument parser type and an NMS brigadier argument type which
+ * has a no-args constructor.
*
- * @param type Type to map
- * @param constructor Constructor that construct the NMS argument type
+ * @param type Type to map
+ * @param argument parser type
+ * @param argumentName NMS Argument class name (without 'Argument' prefix)
+ * @since 1.5.0
*/
- public void mapSimpleNMS(
- final @NonNull Class> type,
- final @NonNull Constructor> constructor
+ public > void mapSimpleNMS(
+ final @NonNull TypeToken type,
+ final @NonNull String argumentName
) {
+ final Constructor> constructor;
try {
- this.brigadierManager.registerDefaultArgumentTypeSupplier(type, () -> {
- try {
- return constructor.newInstance();
- } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
- e.printStackTrace();
- }
- return null;
- });
- } catch (final Exception e) {
- this.commandManager.getOwningPlugin()
- .getLogger()
- .warning(String.format(
- "Failed to map '%s' to a Mojang serializable argument type",
- type.getCanonicalName()
- ));
+ final Class> nmsArgument = getNMSArgument(argumentName);
+ constructor = nmsArgument.getConstructor();
+ } catch (final RuntimeException | ReflectiveOperationException e) {
+ this.commandManager.getOwningPlugin().getLogger().log(
+ Level.WARNING,
+ String.format("Failed to create mapping for NMS brigadier argument type '%s'.", argumentName),
+ e
+ );
+ return;
}
+ this.brigadierManager.registerMapping(type, builder -> builder.to(argument -> {
+ try {
+ return (ArgumentType>) constructor.newInstance();
+ } catch (final ReflectiveOperationException e) {
+ this.commandManager.getOwningPlugin().getLogger().log(
+ Level.WARNING,
+ String.format(
+ "Failed to create instance of brigadier argument type '%s'.",
+ GenericTypeReflector.erase(type.getType()).getCanonicalName()
+ ),
+ e
+ );
+ return fallbackType();
+ }
+ }));
}
/**
@@ -190,21 +208,61 @@ public final class BukkitBrigadierMapper {
*
* @param type Type to map
* @param argumentTypeSupplier Supplier of the NMS argument type
+ * @param argument parser type
+ * @since 1.5.0
*/
+ public > void mapNMS(
+ final @NonNull TypeToken type,
+ final @NonNull Supplier> argumentTypeSupplier
+ ) {
+ this.brigadierManager.registerMapping(type, builder ->
+ builder.to(argument -> argumentTypeSupplier.get())
+ );
+ }
+
+ private static @NonNull StringArgumentType fallbackType() {
+ return StringArgumentType.word();
+ }
+
+ /**
+ * Attempt to register a mapping between a type and a NMS argument type
+ *
+ * @param type Type to map
+ * @param constructor Constructor that construct the NMS argument type
+ * @deprecated use {@link #mapSimpleNMS(TypeToken, String)} instead
+ */
+ @Deprecated
+ public void mapSimpleNMS(
+ final @NonNull Class> type,
+ final @NonNull Constructor> constructor
+ ) {
+ this.brigadierManager.registerDefaultArgumentTypeSupplier(type, () -> {
+ try {
+ return (ArgumentType>) constructor.newInstance();
+ } catch (final ReflectiveOperationException e) {
+ this.commandManager.getOwningPlugin().getLogger().log(
+ Level.WARNING,
+ String.format("Failed to map brigadier argument type '%s'", type.getCanonicalName()),
+ e
+ );
+ return fallbackType();
+ }
+ });
+ }
+
+ /**
+ * Attempt to register a mapping between a type and a NMS argument type
+ *
+ * @param type Type to map
+ * @param argumentTypeSupplier Supplier of the NMS argument type
+ * @deprecated use {@link #mapNMS(TypeToken, Supplier)} instead
+ */
+ @Deprecated
public void mapComplexNMS(
final @NonNull Class> type,
final @NonNull Supplier> argumentTypeSupplier
) {
- try {
- this.brigadierManager.registerDefaultArgumentTypeSupplier(type, argumentTypeSupplier);
- } catch (final Exception e) {
- this.commandManager.getOwningPlugin()
- .getLogger()
- .warning(String.format(
- "Failed to map '%s' to a Mojang serializable argument type",
- type.getCanonicalName()
- ));
- }
+ this.brigadierManager.registerDefaultArgumentTypeSupplier(type, argumentTypeSupplier);
}
}
diff --git a/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/BukkitCommandContextKeys.java b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/BukkitCommandContextKeys.java
new file mode 100644
index 00000000..88471a97
--- /dev/null
+++ b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/BukkitCommandContextKeys.java
@@ -0,0 +1,64 @@
+//
+// 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;
+
+import cloud.commandframework.keys.CloudKey;
+import cloud.commandframework.keys.SimpleCloudKey;
+import io.leangen.geantyref.TypeToken;
+import org.bukkit.command.CommandSender;
+
+import java.util.Set;
+
+/**
+ * Bukkit related {@link cloud.commandframework.context.CommandContext} keys.
+ *
+ * @since 1.5.0
+ */
+public final class BukkitCommandContextKeys {
+
+ /**
+ * Key used to store the Bukkit native {@link CommandSender} in the {@link cloud.commandframework.context.CommandContext}.
+ *
+ * @since 1.5.0
+ */
+ public static final CloudKey BUKKIT_COMMAND_SENDER = SimpleCloudKey.of(
+ "BukkitCommandSender",
+ TypeToken.get(CommandSender.class)
+ );
+
+ /**
+ * Key used to store the active {@link CloudBukkitCapabilities} in the {@link cloud.commandframework.context.CommandContext}.
+ *
+ * @since 1.5.0
+ */
+ public static final CloudKey> CLOUD_BUKKIT_CAPABILITIES = SimpleCloudKey.of(
+ "CloudBukkitCapabilities",
+ new TypeToken>() {
+ }
+ );
+
+ private BukkitCommandContextKeys() {
+ }
+
+}
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 bcb769b9..fc49b404 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
@@ -31,7 +31,10 @@ 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.data.ProtoItemStack;
+import cloud.commandframework.bukkit.internal.CraftBukkitReflection;
import cloud.commandframework.bukkit.parsers.EnchantmentArgument;
+import cloud.commandframework.bukkit.parsers.ItemStackArgument;
import cloud.commandframework.bukkit.parsers.MaterialArgument;
import cloud.commandframework.bukkit.parsers.OfflinePlayerArgument;
import cloud.commandframework.bukkit.parsers.PlayerArgument;
@@ -81,7 +84,7 @@ public class BukkitCommandManager extends CommandManager implements Brigad
private final Plugin owningPlugin;
private final int minecraftVersion;
- private final boolean paper;
+ private final boolean paper = CraftBukkitReflection.classExists("com.destroystokyo.paper.PaperConfig");
private final Function commandSenderMapper;
private final Function backwardsCommandSenderMapper;
@@ -134,30 +137,7 @@ public class BukkitCommandManager extends CommandManager implements Brigad
this.taskFactory = new TaskFactory(bukkitSynchronizer);
/* Try to determine the Minecraft version */
- int version = -1;
- try {
- final Matcher matcher = Pattern.compile("\\(MC: (\\d)\\.(\\d+)\\.?(\\d+?)?\\)")
- .matcher(Bukkit.getVersion());
- if (matcher.find()) {
- version = Integer.parseInt(
- matcher.toMatchResult().group(2),
- VERSION_RADIX
- );
- }
- } catch (final Exception e) {
- this.owningPlugin.getLogger().severe("Failed to determine Minecraft version "
- + "for cloud Bukkit capability detection");
- }
- this.minecraftVersion = version;
-
- boolean paper = false;
- try {
- Class.forName("com.destroystokyo.paper.PaperConfig");
- paper = true;
- } catch (final Exception ignored) {
- // This is fine
- }
- this.paper = paper;
+ this.minecraftVersion = this.getMinecraftVersion();
/* Register Bukkit Preprocessor */
this.registerCommandPreProcessor(new BukkitCommandPreprocessor<>(this));
@@ -177,6 +157,8 @@ public class BukkitCommandManager extends CommandManager implements Brigad
new LocationArgument.LocationParser<>());
this.getParserRegistry().registerParserSupplier(TypeToken.get(Location2D.class), parserParameters ->
new Location2DArgument.Location2DParser<>());
+ this.getParserRegistry().registerParserSupplier(TypeToken.get(ProtoItemStack.class), parserParameters ->
+ new ItemStackArgument.Parser<>());
/* Register Entity Selector Parsers */
this.getParserRegistry().registerParserSupplier(TypeToken.get(SingleEntitySelector.class), parserParameters ->
new SingleEntitySelectorArgument.SingleEntitySelectorParser<>());
@@ -196,6 +178,19 @@ public class BukkitCommandManager extends CommandManager implements Brigad
this.setCaptionRegistry(new BukkitCaptionRegistryFactory().create());
}
+ private int getMinecraftVersion() {
+ try {
+ final Matcher matcher = Pattern.compile("\\(MC: (\\d)\\.(\\d+)\\.?(\\d+?)?\\)").matcher(Bukkit.getVersion());
+ if (matcher.find()) {
+ return Integer.parseInt(matcher.toMatchResult().group(2), VERSION_RADIX);
+ }
+ } catch (final Exception e) {
+ this.owningPlugin.getLogger()
+ .severe("Failed to determine Minecraft version for cloud Bukkit capability detection");
+ }
+ return -1;
+ }
+
/**
* Create a command manager using Bukkit's {@link CommandSender} as the sender type.
*
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 32f8e596..563bd890 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
@@ -27,6 +27,8 @@ import cloud.commandframework.execution.preprocessor.CommandPreprocessingContext
import cloud.commandframework.execution.preprocessor.CommandPreprocessor;
import org.checkerframework.checker.nullness.qual.NonNull;
+import java.util.Set;
+
/**
* Command preprocessor which decorates incoming {@link cloud.commandframework.context.CommandContext}
* with Bukkit specific objects
@@ -35,26 +37,29 @@ import org.checkerframework.checker.nullness.qual.NonNull;
*/
final class BukkitCommandPreprocessor implements CommandPreprocessor {
- private final BukkitCommandManager mgr;
+ private final BukkitCommandManager commandManager;
+ private final Set bukkitCapabilities;
/**
* The Bukkit Command Preprocessor for storing Bukkit-specific contexts in the command contexts
*
- * @param mgr The BukkitCommandManager
+ * @param commandManager The BukkitCommandManager
*/
- BukkitCommandPreprocessor(final @NonNull BukkitCommandManager mgr) {
- this.mgr = mgr;
+ BukkitCommandPreprocessor(final @NonNull BukkitCommandManager commandManager) {
+ this.commandManager = commandManager;
+ this.bukkitCapabilities = commandManager.queryCapabilities();
}
- /**
- * Stores the sender mapped to {@link org.bukkit.command.CommandSender} in the context with the key "BukkitCommandSender",
- * and a {@link java.util.Set} of {@link CloudBukkitCapabilities} with the key "CloudBukkitCapabilities"
- */
@Override
public void accept(final @NonNull CommandPreprocessingContext context) {
- context.getCommandContext().store("BukkitCommandSender", this.mgr.getBackwardsCommandSenderMapper().apply(
- context.getCommandContext().getSender()));
- context.getCommandContext().store("CloudBukkitCapabilities", this.mgr.queryCapabilities());
+ context.getCommandContext().store(
+ BukkitCommandContextKeys.BUKKIT_COMMAND_SENDER,
+ this.commandManager.getBackwardsCommandSenderMapper().apply(context.getCommandContext().getSender())
+ );
+ context.getCommandContext().store(
+ BukkitCommandContextKeys.CLOUD_BUKKIT_CAPABILITIES,
+ this.bukkitCapabilities
+ );
}
}
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 15b04bba..aa684b9e 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,8 +25,8 @@ package cloud.commandframework.bukkit;
import cloud.commandframework.Command;
import cloud.commandframework.brigadier.CloudBrigadierManager;
+import cloud.commandframework.bukkit.internal.CraftBukkitReflection;
import cloud.commandframework.context.CommandContext;
-import cloud.commandframework.permission.CommandPermission;
import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.tree.LiteralCommandNode;
import me.lucko.commodore.Commodore;
@@ -36,13 +36,14 @@ 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"})
class CloudCommodoreManager extends BukkitPluginRegistrationHandler {
private final BukkitCommandManager commandManager;
- private final CloudBrigadierManager brigadierManager;
+ private final CloudBrigadierManager brigadierManager;
private final Commodore commodore;
CloudCommodoreManager(final @NonNull BukkitCommandManager commandManager)
@@ -53,17 +54,29 @@ class CloudCommodoreManager extends BukkitPluginRegistrationHandler {
}
this.commandManager = commandManager;
this.commodore = CommodoreProvider.getCommodore(commandManager.getOwningPlugin());
- this.brigadierManager = new CloudBrigadierManager<>(commandManager, () ->
- new CommandContext<>(
- commandManager.getCommandSenderMapper().apply(Bukkit.getConsoleSender()),
- commandManager
- ));
- this.brigadierManager.brigadierSenderMapper(
- sender -> this.commandManager.getCommandSenderMapper().apply(
- this.commodore.getBukkitSender(sender)
- )
- );
+ this.brigadierManager = new CloudBrigadierManager<>(commandManager, () -> new CommandContext<>(
+ commandManager.getCommandSenderMapper().apply(Bukkit.getConsoleSender()),
+ commandManager
+ ));
+
+ this.brigadierManager.brigadierSenderMapper(sender ->
+ this.commandManager.getCommandSenderMapper().apply(this.commodore.getBukkitSender(sender)));
+
new BukkitBrigadierMapper<>(this.commandManager, this.brigadierManager);
+
+ if (!CraftBukkitReflection.craftBukkit()) {
+ return;
+ }
+ 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
@@ -72,7 +85,7 @@ class CloudCommodoreManager extends BukkitPluginRegistrationHandler {
final @NonNull Command> command,
final @NonNull BukkitCommand bukkitCommand
) {
- this.registerWithCommodore(label, command);
+ this.registerWithCommodore(label, (Command) command);
}
protected @NonNull CloudBrigadierManager brigadierManager() {
@@ -81,17 +94,13 @@ class CloudCommodoreManager extends BukkitPluginRegistrationHandler {
private void registerWithCommodore(
final @NonNull String label,
- final @NonNull Command> command
+ final @NonNull Command command
) {
- final com.mojang.brigadier.Command> cmd = o -> 1;
final LiteralCommandNode> literalCommandNode = this.brigadierManager
.createLiteralCommandNode(label, command, (o, p) -> {
final CommandSender sender = this.commodore.getBukkitSender(o);
- return this.commandManager.hasPermission(
- this.commandManager.getCommandSenderMapper().apply(sender),
- (CommandPermission) p
- );
- }, false, cmd);
+ return this.commandManager.hasPermission(this.commandManager.getCommandSenderMapper().apply(sender), p);
+ }, false, o -> 1);
final CommandNode existingNode = this.commodore.getDispatcher().findNode(Collections.singletonList(label));
if (existingNode != null) {
this.mergeChildren(existingNode, literalCommandNode);
diff --git a/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/data/ProtoItemStack.java b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/data/ProtoItemStack.java
new file mode 100644
index 00000000..ee2e07c5
--- /dev/null
+++ b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/data/ProtoItemStack.java
@@ -0,0 +1,63 @@
+//
+// 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.data;
+
+import org.bukkit.Material;
+import org.bukkit.inventory.ItemStack;
+import org.checkerframework.checker.nullness.qual.NonNull;
+
+/**
+ * Intermediary result for an argument which parses a {@link Material} and optional NBT data.
+ *
+ * @since 1.5.0
+ */
+public interface ProtoItemStack {
+
+ /**
+ * Get the {@link Material} of this {@link ProtoItemStack}.
+ *
+ * @return the {@link Material}
+ * @since 1.5.0
+ */
+ @NonNull Material material();
+
+ /**
+ * Get whether this {@link ProtoItemStack} contains extra data besides the {@link Material}.
+ *
+ * @return whether there is extra data
+ */
+ boolean hasExtraData();
+
+ /**
+ * Create a new {@link ItemStack} from the state of this {@link ProtoItemStack}.
+ *
+ * @param stackSize stack size
+ * @param respectMaximumStackSize whether to respect the maximum stack size for the material
+ * @return the created {@link ItemStack}
+ * @throws IllegalArgumentException if the {@link ItemStack} could not be created, due to max stack size or other reasons
+ */
+ @NonNull ItemStack createItemStack(int stackSize, boolean respectMaximumStackSize)
+ throws IllegalArgumentException;
+
+}
diff --git a/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/data/package-info.java b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/data/package-info.java
new file mode 100644
index 00000000..05654e91
--- /dev/null
+++ b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/data/package-info.java
@@ -0,0 +1,27 @@
+//
+// 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.
+//
+/**
+ * cloud-bukkit data holders
+ */
+package cloud.commandframework.bukkit.data;
diff --git a/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/internal/CraftBukkitReflection.java b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/internal/CraftBukkitReflection.java
new file mode 100644
index 00000000..2ab3d085
--- /dev/null
+++ b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/internal/CraftBukkitReflection.java
@@ -0,0 +1,126 @@
+//
+// 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 com.google.common.annotations.Beta;
+import org.bukkit.Bukkit;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * Utilities for doing reflection on CraftBukkit, used by the cloud implementation.
+ *
+ *