bukkit: Implement ItemStackArgument (#257)

Fully featured on 1.13+, falls back to Material parser on legacy versions.

Also some general cleanup to the Bukkit impl
This commit is contained in:
Jason 2021-04-29 18:20:53 -07:00 committed by Jason
parent e5d6ce7b90
commit e3cc7d43cb
20 changed files with 899 additions and 180 deletions

View file

@ -4,4 +4,5 @@
"https://checkstyle.org/dtds/suppressions_1_2.dtd"> "https://checkstyle.org/dtds/suppressions_1_2.dtd">
<suppressions> <suppressions>
<suppress checks="(?:(?:Member|Method)Name|DesignForExtension|Javadoc.*)" files=".*[\\/]mixin[\\/].*"/> <suppress checks="(?:(?:Member|Method)Name|DesignForExtension|Javadoc.*)" files=".*[\\/]mixin[\\/].*"/>
<suppress checks="(?:Javadoc.*)" files=".*[\\/]CraftBukkitReflection.java"/>
</suppressions> </suppressions>

View file

@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- JDA Role argument parser - JDA Role argument parser
- Bukkit: Implement parser for ProtoItemStack ([#257](https://github.com/Incendo/cloud/pull/257))
### Changed ### Changed
- Use Command instead of TabCompleteEvent on Bukkit - Use Command instead of TabCompleteEvent on Bukkit

View file

@ -23,21 +23,25 @@
// //
package cloud.commandframework.bukkit; package cloud.commandframework.bukkit;
import cloud.commandframework.arguments.parser.ArgumentParser;
import cloud.commandframework.arguments.standard.UUIDArgument;
import cloud.commandframework.brigadier.CloudBrigadierManager; import cloud.commandframework.brigadier.CloudBrigadierManager;
import cloud.commandframework.bukkit.arguments.selector.MultipleEntitySelector; import cloud.commandframework.bukkit.internal.CraftBukkitReflection;
import cloud.commandframework.bukkit.arguments.selector.MultiplePlayerSelector; import cloud.commandframework.bukkit.parsers.EnchantmentArgument;
import cloud.commandframework.bukkit.arguments.selector.SingleEntitySelector; import cloud.commandframework.bukkit.parsers.ItemStackArgument;
import cloud.commandframework.bukkit.arguments.selector.SinglePlayerSelector; import cloud.commandframework.bukkit.parsers.location.Location2DArgument;
import cloud.commandframework.bukkit.parsers.location.Location2D; 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 com.mojang.brigadier.arguments.ArgumentType;
import org.bukkit.Bukkit; import com.mojang.brigadier.arguments.StringArgumentType;
import org.bukkit.Location; import io.leangen.geantyref.GenericTypeReflector;
import org.bukkit.enchantments.Enchantment; import io.leangen.geantyref.TypeToken;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.UUID;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.logging.Level; import java.util.logging.Level;
@ -46,14 +50,12 @@ import java.util.logging.Level;
* *
* @param <C> Command sender type * @param <C> Command sender type
*/ */
@SuppressWarnings({"unchecked", "rawtypes"})
public final class BukkitBrigadierMapper<C> { public final class BukkitBrigadierMapper<C> {
private static final int UUID_ARGUMENT_VERSION = 16; private static final int UUID_ARGUMENT_VERSION = 16;
private final BukkitCommandManager<C> commandManager; private final BukkitCommandManager<C> commandManager;
private final CloudBrigadierManager brigadierManager; private final CloudBrigadierManager<C, ?> brigadierManager;
private final String nmsVersion;
/** /**
@ -64,38 +66,48 @@ public final class BukkitBrigadierMapper<C> {
*/ */
public BukkitBrigadierMapper( public BukkitBrigadierMapper(
final @NonNull BukkitCommandManager<C> commandManager, final @NonNull BukkitCommandManager<C> commandManager,
final @NonNull CloudBrigadierManager brigadierManager final @NonNull CloudBrigadierManager<C, ?> brigadierManager
) { ) {
this.commandManager = commandManager; this.commandManager = commandManager;
this.brigadierManager = brigadierManager; this.brigadierManager = brigadierManager;
/* Detect Minecraft Version Metadata */ if (!CraftBukkitReflection.craftBukkit()) {
final String version = Bukkit.getServer().getClass().getPackage().getName(); this.commandManager.getOwningPlugin().getLogger().warning(
this.nmsVersion = version.substring(version.lastIndexOf(".") + 1); "Could not detect relocated CraftBukkit package, NMS brigadier mappings will not be enabled.");
final int majorMinecraftVersion = Integer.parseInt(this.nmsVersion.split("_")[1]); return;
}
try { this.registerMappings();
}
private void registerMappings() {
/* UUID nms argument is a 1.16+ feature */ /* UUID nms argument is a 1.16+ feature */
if (majorMinecraftVersion >= UUID_ARGUMENT_VERSION) { if (CraftBukkitReflection.MAJOR_REVISION >= UUID_ARGUMENT_VERSION) {
/* Map UUID */ /* Map UUID */
this.mapSimpleNMS(UUID.class, this.getNMSArgument("UUID").getConstructor()); this.mapSimpleNMS(new TypeToken<UUIDArgument.UUIDParser<C>>() {
}, "UUID");
} }
/* Map Enchantment */ /* Map Enchantment */
this.mapSimpleNMS(Enchantment.class, this.getNMSArgument("Enchantment").getConstructor()); this.mapSimpleNMS(new TypeToken<EnchantmentArgument.EnchantmentParser<C>>() {
}, "Enchantment");
/* Map ItemStackArgument */
this.mapSimpleNMS(new TypeToken<ItemStackArgument.Parser<C>>() {
}, "ItemStack");
/* Map Entity Selectors */ /* Map Entity Selectors */
this.mapComplexNMS(SingleEntitySelector.class, this.getEntitySelectorArgument(true, false)); this.mapNMS(new TypeToken<SingleEntitySelectorArgument.SingleEntitySelectorParser<C>>() {
this.mapComplexNMS(SinglePlayerSelector.class, this.getEntitySelectorArgument(true, true)); }, this.entitySelectorArgumentSupplier(true, false));
this.mapComplexNMS(MultipleEntitySelector.class, this.getEntitySelectorArgument(false, false)); this.mapNMS(new TypeToken<SinglePlayerSelectorArgument.SinglePlayerSelectorParser<C>>() {
this.mapComplexNMS(MultiplePlayerSelector.class, this.getEntitySelectorArgument(false, true)); }, this.entitySelectorArgumentSupplier(true, true));
this.mapNMS(new TypeToken<MultipleEntitySelectorArgument.MultipleEntitySelectorParser<C>>() {
}, this.entitySelectorArgumentSupplier(false, false));
this.mapNMS(new TypeToken<MultiplePlayerSelectorArgument.MultiplePlayerSelectorParser<C>>() {
}, this.entitySelectorArgumentSupplier(false, true));
/* Map Vec3 */ /* Map Vec3 */
this.mapComplexNMS(Location.class, this.getArgumentVec3()); this.mapNMS(new TypeToken<LocationArgument.LocationParser<C>>() {
}, this::argumentVec3);
/* Map Vec2I */ /* Map Vec2I */
this.mapComplexNMS(Location2D.class, this.getArgumentVec2I()); this.mapNMS(new TypeToken<Location2DArgument.Location2DParser<C>>() {
} catch (final Exception e) { }, this::argumentVec2i);
this.commandManager.getOwningPlugin()
.getLogger()
.log(Level.WARNING, "Failed to map Bukkit types to NMS argument types", e);
}
} }
/** /**
@ -103,45 +115,39 @@ public final class BukkitBrigadierMapper<C> {
* @param playersOnly Whether the selector is for players only (true), or for all entities (false) * @param playersOnly Whether the selector is for players only (true), or for all entities (false)
* @return The NMS ArgumentType * @return The NMS ArgumentType
*/ */
private @NonNull Supplier<ArgumentType<?>> getEntitySelectorArgument( private @NonNull Supplier<ArgumentType<?>> entitySelectorArgumentSupplier(
final boolean single, final boolean single,
final boolean playersOnly final boolean playersOnly
) { ) {
return () -> { return () -> {
try { try {
final Constructor<?> constructor = this.getNMSArgument("Entity").getDeclaredConstructors()[0]; final Constructor<?> constructor = getNMSArgument("Entity").getDeclaredConstructors()[0];
constructor.setAccessible(true); constructor.setAccessible(true);
return (ArgumentType<?>) constructor.newInstance(single, playersOnly); return (ArgumentType<?>) constructor.newInstance(single, playersOnly);
} catch (final Exception e) { } catch (final Exception e) {
this.commandManager.getOwningPlugin().getLogger().log(Level.INFO, "Failed to retrieve Selector Argument", e); this.commandManager.getOwningPlugin().getLogger().log(Level.INFO, "Failed to retrieve Selector Argument", e);
return null; return fallbackType();
} }
}; };
} }
@SuppressWarnings("UnnecessaryLambda") private @NonNull ArgumentType<?> argumentVec3() {
private @NonNull Supplier<ArgumentType<?>> getArgumentVec3() {
return () -> {
try { try {
return (ArgumentType<?>) this.getNMSArgument("Vec3").getDeclaredConstructor(boolean.class) return (ArgumentType<?>) getNMSArgument("Vec3").getDeclaredConstructor(boolean.class)
.newInstance(true); .newInstance(true);
} catch (final Exception e) { } catch (final Exception e) {
this.commandManager.getOwningPlugin().getLogger().log(Level.INFO, "Failed to retrieve Vec3D argument", e); this.commandManager.getOwningPlugin().getLogger().log(Level.INFO, "Failed to retrieve Vec3D argument", e);
return null; return fallbackType();
} }
};
} }
@SuppressWarnings("UnnecessaryLambda") private @NonNull ArgumentType<?> argumentVec2i() {
private @NonNull Supplier<ArgumentType<?>> getArgumentVec2I() {
return () -> {
try { try {
return (ArgumentType<?>) this.getNMSArgument("Vec2I").getDeclaredConstructor().newInstance(); return (ArgumentType<?>) getNMSArgument("Vec2I").getDeclaredConstructor().newInstance();
} catch (final Exception e) { } catch (final Exception e) {
this.commandManager.getOwningPlugin().getLogger().log(Level.INFO, "Failed to retrieve Vec2I argument", e); this.commandManager.getOwningPlugin().getLogger().log(Level.INFO, "Failed to retrieve Vec2I argument", e);
return null; return fallbackType();
} }
};
} }
/** /**
@ -149,40 +155,52 @@ public final class BukkitBrigadierMapper<C> {
* *
* @param argument Argument type name * @param argument Argument type name
* @return Argument class * @return Argument class
* @throws Exception If the type cannot be retrieved * @throws RuntimeException when the class is not found
*/ */
@NonNull private static @NonNull Class<?> getNMSArgument(final @NonNull String argument) throws RuntimeException {
private Class<?> getNMSArgument(final @NonNull String argument) throws Exception { return CraftBukkitReflection.needNMSClass("Argument" + argument);
return Class.forName(String.format("net.minecraft.server.%s.Argument%s", this.nmsVersion, 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 type Type to map
* @param constructor Constructor that construct the NMS argument type * @param <T> argument parser type
* @param argumentName NMS Argument class name (without 'Argument' prefix)
* @since 1.5.0
*/ */
public void mapSimpleNMS( public <T extends ArgumentParser<C, ?>> void mapSimpleNMS(
final @NonNull Class<?> type, final @NonNull TypeToken<T> type,
final @NonNull Constructor<?> constructor final @NonNull String argumentName
) { ) {
final Constructor<?> constructor;
try { try {
this.brigadierManager.registerDefaultArgumentTypeSupplier(type, () -> { 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 { try {
return constructor.newInstance(); return (ArgumentType<?>) constructor.newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { } catch (final ReflectiveOperationException e) {
e.printStackTrace(); this.commandManager.getOwningPlugin().getLogger().log(
} Level.WARNING,
return null; String.format(
}); "Failed to create instance of brigadier argument type '%s'.",
} catch (final Exception e) { GenericTypeReflector.erase(type.getType()).getCanonicalName()
this.commandManager.getOwningPlugin() ),
.getLogger() e
.warning(String.format( );
"Failed to map '%s' to a Mojang serializable argument type", return fallbackType();
type.getCanonicalName()
));
} }
}));
} }
/** /**
@ -190,21 +208,61 @@ public final class BukkitBrigadierMapper<C> {
* *
* @param type Type to map * @param type Type to map
* @param argumentTypeSupplier Supplier of the NMS argument type * @param argumentTypeSupplier Supplier of the NMS argument type
* @param <T> argument parser type
* @since 1.5.0
*/ */
public <T extends ArgumentParser<C, ?>> void mapNMS(
final @NonNull TypeToken<T> type,
final @NonNull Supplier<ArgumentType<?>> 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( public void mapComplexNMS(
final @NonNull Class<?> type, final @NonNull Class<?> type,
final @NonNull Supplier<ArgumentType<?>> argumentTypeSupplier final @NonNull Supplier<ArgumentType<?>> argumentTypeSupplier
) { ) {
try {
this.brigadierManager.registerDefaultArgumentTypeSupplier(type, argumentTypeSupplier); 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()
));
}
} }
} }

View file

@ -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<CommandSender> 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<Set<CloudBukkitCapabilities>> CLOUD_BUKKIT_CAPABILITIES = SimpleCloudKey.of(
"CloudBukkitCapabilities",
new TypeToken<Set<CloudBukkitCapabilities>>() {
}
);
private BukkitCommandContextKeys() {
}
}

View file

@ -31,7 +31,10 @@ import cloud.commandframework.bukkit.arguments.selector.MultipleEntitySelector;
import cloud.commandframework.bukkit.arguments.selector.MultiplePlayerSelector; import cloud.commandframework.bukkit.arguments.selector.MultiplePlayerSelector;
import cloud.commandframework.bukkit.arguments.selector.SingleEntitySelector; import cloud.commandframework.bukkit.arguments.selector.SingleEntitySelector;
import cloud.commandframework.bukkit.arguments.selector.SinglePlayerSelector; 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.EnchantmentArgument;
import cloud.commandframework.bukkit.parsers.ItemStackArgument;
import cloud.commandframework.bukkit.parsers.MaterialArgument; import cloud.commandframework.bukkit.parsers.MaterialArgument;
import cloud.commandframework.bukkit.parsers.OfflinePlayerArgument; import cloud.commandframework.bukkit.parsers.OfflinePlayerArgument;
import cloud.commandframework.bukkit.parsers.PlayerArgument; import cloud.commandframework.bukkit.parsers.PlayerArgument;
@ -81,7 +84,7 @@ public class BukkitCommandManager<C> extends CommandManager<C> implements Brigad
private final Plugin owningPlugin; private final Plugin owningPlugin;
private final int minecraftVersion; private final int minecraftVersion;
private final boolean paper; private final boolean paper = CraftBukkitReflection.classExists("com.destroystokyo.paper.PaperConfig");
private final Function<CommandSender, C> commandSenderMapper; private final Function<CommandSender, C> commandSenderMapper;
private final Function<C, CommandSender> backwardsCommandSenderMapper; private final Function<C, CommandSender> backwardsCommandSenderMapper;
@ -134,30 +137,7 @@ public class BukkitCommandManager<C> extends CommandManager<C> implements Brigad
this.taskFactory = new TaskFactory(bukkitSynchronizer); this.taskFactory = new TaskFactory(bukkitSynchronizer);
/* Try to determine the Minecraft version */ /* Try to determine the Minecraft version */
int version = -1; this.minecraftVersion = this.getMinecraftVersion();
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;
/* Register Bukkit Preprocessor */ /* Register Bukkit Preprocessor */
this.registerCommandPreProcessor(new BukkitCommandPreprocessor<>(this)); this.registerCommandPreProcessor(new BukkitCommandPreprocessor<>(this));
@ -177,6 +157,8 @@ public class BukkitCommandManager<C> extends CommandManager<C> implements Brigad
new LocationArgument.LocationParser<>()); new LocationArgument.LocationParser<>());
this.getParserRegistry().registerParserSupplier(TypeToken.get(Location2D.class), parserParameters -> this.getParserRegistry().registerParserSupplier(TypeToken.get(Location2D.class), parserParameters ->
new Location2DArgument.Location2DParser<>()); new Location2DArgument.Location2DParser<>());
this.getParserRegistry().registerParserSupplier(TypeToken.get(ProtoItemStack.class), parserParameters ->
new ItemStackArgument.Parser<>());
/* Register Entity Selector Parsers */ /* Register Entity Selector Parsers */
this.getParserRegistry().registerParserSupplier(TypeToken.get(SingleEntitySelector.class), parserParameters -> this.getParserRegistry().registerParserSupplier(TypeToken.get(SingleEntitySelector.class), parserParameters ->
new SingleEntitySelectorArgument.SingleEntitySelectorParser<>()); new SingleEntitySelectorArgument.SingleEntitySelectorParser<>());
@ -196,6 +178,19 @@ public class BukkitCommandManager<C> extends CommandManager<C> implements Brigad
this.setCaptionRegistry(new BukkitCaptionRegistryFactory<C>().create()); this.setCaptionRegistry(new BukkitCaptionRegistryFactory<C>().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. * Create a command manager using Bukkit's {@link CommandSender} as the sender type.
* *

View file

@ -27,6 +27,8 @@ import cloud.commandframework.execution.preprocessor.CommandPreprocessingContext
import cloud.commandframework.execution.preprocessor.CommandPreprocessor; import cloud.commandframework.execution.preprocessor.CommandPreprocessor;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Set;
/** /**
* Command preprocessor which decorates incoming {@link cloud.commandframework.context.CommandContext} * Command preprocessor which decorates incoming {@link cloud.commandframework.context.CommandContext}
* with Bukkit specific objects * with Bukkit specific objects
@ -35,26 +37,29 @@ import org.checkerframework.checker.nullness.qual.NonNull;
*/ */
final class BukkitCommandPreprocessor<C> implements CommandPreprocessor<C> { final class BukkitCommandPreprocessor<C> implements CommandPreprocessor<C> {
private final BukkitCommandManager<C> mgr; private final BukkitCommandManager<C> commandManager;
private final Set<CloudBukkitCapabilities> bukkitCapabilities;
/** /**
* The Bukkit Command Preprocessor for storing Bukkit-specific contexts in the command contexts * 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<C> mgr) { BukkitCommandPreprocessor(final @NonNull BukkitCommandManager<C> commandManager) {
this.mgr = mgr; 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 @Override
public void accept(final @NonNull CommandPreprocessingContext<C> context) { public void accept(final @NonNull CommandPreprocessingContext<C> context) {
context.getCommandContext().store("BukkitCommandSender", this.mgr.getBackwardsCommandSenderMapper().apply( context.getCommandContext().store(
context.getCommandContext().getSender())); BukkitCommandContextKeys.BUKKIT_COMMAND_SENDER,
context.getCommandContext().store("CloudBukkitCapabilities", this.mgr.queryCapabilities()); this.commandManager.getBackwardsCommandSenderMapper().apply(context.getCommandContext().getSender())
);
context.getCommandContext().store(
BukkitCommandContextKeys.CLOUD_BUKKIT_CAPABILITIES,
this.bukkitCapabilities
);
} }
} }

View file

@ -25,8 +25,8 @@ package cloud.commandframework.bukkit;
import cloud.commandframework.Command; import cloud.commandframework.Command;
import cloud.commandframework.brigadier.CloudBrigadierManager; import cloud.commandframework.brigadier.CloudBrigadierManager;
import cloud.commandframework.bukkit.internal.CraftBukkitReflection;
import cloud.commandframework.context.CommandContext; import cloud.commandframework.context.CommandContext;
import cloud.commandframework.permission.CommandPermission;
import com.mojang.brigadier.tree.CommandNode; import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.tree.LiteralCommandNode; import com.mojang.brigadier.tree.LiteralCommandNode;
import me.lucko.commodore.Commodore; 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.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import java.lang.reflect.Method;
import java.util.Collections; import java.util.Collections;
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})
class CloudCommodoreManager<C> extends BukkitPluginRegistrationHandler<C> { class CloudCommodoreManager<C> extends BukkitPluginRegistrationHandler<C> {
private final BukkitCommandManager<C> commandManager; private final BukkitCommandManager<C> commandManager;
private final CloudBrigadierManager brigadierManager; private final CloudBrigadierManager<C, Object> brigadierManager;
private final Commodore commodore; private final Commodore commodore;
CloudCommodoreManager(final @NonNull BukkitCommandManager<C> commandManager) CloudCommodoreManager(final @NonNull BukkitCommandManager<C> commandManager)
@ -53,17 +54,29 @@ class CloudCommodoreManager<C> extends BukkitPluginRegistrationHandler<C> {
} }
this.commandManager = commandManager; this.commandManager = commandManager;
this.commodore = CommodoreProvider.getCommodore(commandManager.getOwningPlugin()); this.commodore = CommodoreProvider.getCommodore(commandManager.getOwningPlugin());
this.brigadierManager = new CloudBrigadierManager<>(commandManager, () -> this.brigadierManager = new CloudBrigadierManager<>(commandManager, () -> new CommandContext<>(
new CommandContext<>(
commandManager.getCommandSenderMapper().apply(Bukkit.getConsoleSender()), commandManager.getCommandSenderMapper().apply(Bukkit.getConsoleSender()),
commandManager commandManager
)); ));
this.brigadierManager.brigadierSenderMapper(
sender -> this.commandManager.getCommandSenderMapper().apply( this.brigadierManager.brigadierSenderMapper(sender ->
this.commodore.getBukkitSender(sender) this.commandManager.getCommandSenderMapper().apply(this.commodore.getBukkitSender(sender)));
)
);
new BukkitBrigadierMapper<>(this.commandManager, this.brigadierManager); 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 @Override
@ -72,7 +85,7 @@ class CloudCommodoreManager<C> extends BukkitPluginRegistrationHandler<C> {
final @NonNull Command<?> command, final @NonNull Command<?> command,
final @NonNull BukkitCommand<C> bukkitCommand final @NonNull BukkitCommand<C> bukkitCommand
) { ) {
this.registerWithCommodore(label, command); this.registerWithCommodore(label, (Command<C>) command);
} }
protected @NonNull CloudBrigadierManager brigadierManager() { protected @NonNull CloudBrigadierManager brigadierManager() {
@ -81,17 +94,13 @@ class CloudCommodoreManager<C> extends BukkitPluginRegistrationHandler<C> {
private void registerWithCommodore( private void registerWithCommodore(
final @NonNull String label, final @NonNull String label,
final @NonNull Command<?> command final @NonNull Command<C> command
) { ) {
final com.mojang.brigadier.Command<?> cmd = o -> 1;
final LiteralCommandNode<?> literalCommandNode = this.brigadierManager final LiteralCommandNode<?> literalCommandNode = this.brigadierManager
.createLiteralCommandNode(label, command, (o, p) -> { .createLiteralCommandNode(label, command, (o, p) -> {
final CommandSender sender = this.commodore.getBukkitSender(o); final CommandSender sender = this.commodore.getBukkitSender(o);
return this.commandManager.hasPermission( return this.commandManager.hasPermission(this.commandManager.getCommandSenderMapper().apply(sender), p);
this.commandManager.getCommandSenderMapper().apply(sender), }, false, o -> 1);
(CommandPermission) p
);
}, false, cmd);
final CommandNode existingNode = this.commodore.getDispatcher().findNode(Collections.singletonList(label)); final CommandNode existingNode = this.commodore.getDispatcher().findNode(Collections.singletonList(label));
if (existingNode != null) { if (existingNode != null) {
this.mergeChildren(existingNode, literalCommandNode); this.mergeChildren(existingNode, literalCommandNode);

View file

@ -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;
}

View file

@ -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;

View file

@ -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.
*
* <p>This is not API to any extent, and as such, may break, change, or be removed without any notice.</p>
*/
@Beta
public final class CraftBukkitReflection {
private static final String PREFIX_NMS = "net.minecraft.server";
private static final String PREFIX_CRAFTBUKKIT = "org.bukkit.craftbukkit";
private static final String CRAFT_SERVER = "CraftServer";
private static final String VERSION;
public static final int MAJOR_REVISION;
static {
final Class<?> serverClass = Bukkit.getServer().getClass();
final String pkg = serverClass.getPackage().getName();
final String nmsVersion = pkg.substring(pkg.lastIndexOf(".") + 1);
if (!nmsVersion.contains("_")) {
MAJOR_REVISION = -1;
VERSION = null;
} else {
MAJOR_REVISION = Integer.parseInt(nmsVersion.split("_")[1]);
String name = serverClass.getName();
name = name.substring(PREFIX_CRAFTBUKKIT.length());
name = name.substring(0, name.length() - CRAFT_SERVER.length());
VERSION = name;
}
}
public static boolean craftBukkit() {
return MAJOR_REVISION != -1 && VERSION != null;
}
public static @NonNull Class<?> needNMSClass(final @NonNull String className) throws RuntimeException {
return needClass(PREFIX_NMS + VERSION + className);
}
public static @NonNull Class<?> needOBCClass(final @NonNull String className) throws RuntimeException {
return needClass(PREFIX_CRAFTBUKKIT + VERSION + className);
}
public static @NonNull Class<?> needClass(final @NonNull String className) throws RuntimeException {
try {
return Class.forName(className);
} catch (final ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
public static @Nullable Class<?> findClass(final @NonNull String className) {
try {
return Class.forName(className);
} catch (final ClassNotFoundException e) {
return null;
}
}
public static @NonNull Field needField(final @NonNull Class<?> holder, final @NonNull String name) throws RuntimeException {
try {
final Field field = holder.getDeclaredField(name);
field.setAccessible(true);
return field;
} catch (final ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
public static boolean classExists(final @NonNull String className) {
try {
Class.forName(className);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
public static @NonNull Method needMethod(
final @NonNull Class<?> holder,
final @NonNull String name,
final @NonNull Class<?>... params
) throws RuntimeException {
try {
return holder.getMethod(name, params);
} catch (final NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
private CraftBukkitReflection() {
}
}

View file

@ -0,0 +1,331 @@
//
// 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.parsers;
import cloud.commandframework.ArgumentDescription;
import cloud.commandframework.arguments.CommandArgument;
import cloud.commandframework.arguments.parser.ArgumentParseResult;
import cloud.commandframework.arguments.parser.ArgumentParser;
import cloud.commandframework.brigadier.argument.WrappedBrigadierParser;
import cloud.commandframework.bukkit.BukkitCommandManager;
import cloud.commandframework.bukkit.data.ProtoItemStack;
import cloud.commandframework.bukkit.internal.CraftBukkitReflection;
import cloud.commandframework.context.CommandContext;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Queue;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
/**
* Argument type for parsing a {@link Material} and optional extra NBT data into a {@link ProtoItemStack}.
*
* <p>This argument type only provides basic suggestions by default. On Minecraft 1.13 and newer, enabling Brigadier
* compatibility through {@link BukkitCommandManager#registerBrigadier()} will allow client side validation and
* suggestions to be utilized.</p>
*
* @param <C> Command sender type
* @since 1.5.0
*/
public final class ItemStackArgument<C> extends CommandArgument<C, ProtoItemStack> {
private ItemStackArgument(
final boolean required,
final @NonNull String name,
final @NonNull String defaultValue,
final @Nullable BiFunction<@NonNull CommandContext<C>, @NonNull String,
@NonNull List<@NonNull String>> suggestionsProvider,
final @NonNull ArgumentDescription defaultDescription
) {
super(required, name, new Parser<>(), defaultValue, ProtoItemStack.class, suggestionsProvider, defaultDescription);
}
/**
* Create a new {@link Builder}.
*
* @param name Name of the argument
* @param <C> Command sender type
* @return Created builder
* @since 1.5.0
*/
public static <C> ItemStackArgument.@NonNull Builder<C> builder(final @NonNull String name) {
return new ItemStackArgument.Builder<>(name);
}
/**
* Create a new required {@link ItemStackArgument}.
*
* @param name Argument name
* @param <C> Command sender type
* @return Created argument
* @since 1.5.0
*/
public static <C> @NonNull CommandArgument<C, ProtoItemStack> of(final @NonNull String name) {
return ItemStackArgument.<C>builder(name).build();
}
/**
* Create a new optional {@link ItemStackArgument}.
*
* @param name Argument name
* @param <C> Command sender type
* @return Created argument
* @since 1.5.0
*/
public static <C> @NonNull CommandArgument<C, ProtoItemStack> optional(final @NonNull String name) {
return ItemStackArgument.<C>builder(name).asOptional().build();
}
/**
* Builder for {@link ItemStackArgument}.
*
* @param <C> sender type
* @since 1.5.0
*/
public static final class Builder<C> extends TypedBuilder<C, ProtoItemStack, Builder<C>> {
private Builder(final @NonNull String name) {
super(ProtoItemStack.class, name);
}
@Override
public @NonNull ItemStackArgument<C> build() {
return new ItemStackArgument<>(
this.isRequired(),
this.getName(),
this.getDefaultValue(),
this.getSuggestionsProvider(),
this.getDefaultDescription()
);
}
}
/**
* Parser for {@link ProtoItemStack}. Requires a CraftBukkit based server implementation.
*
* @param <C> sender type
* @since 1.5.0
*/
public static final class Parser<C> implements ArgumentParser<C, ProtoItemStack> {
private final ArgumentParser<C, ProtoItemStack> parser;
/**
* Create a new {@link Parser}.
*
* @since 1.5.0
*/
public Parser() {
if (!CraftBukkitReflection.craftBukkit()) {
throw new UnsupportedOperationException("ItemStack parser requires CraftBukkit");
}
if (CraftBukkitReflection.MAJOR_REVISION >= 13) {
this.parser = new ModernParser<>();
} else {
this.parser = new LegacyParser<>();
}
}
@Override
public @NonNull ArgumentParseResult<ProtoItemStack> parse(
final @NonNull CommandContext<C> commandContext,
final @NonNull Queue<@NonNull String> inputQueue
) {
return this.parser.parse(commandContext, inputQueue);
}
@Override
public @NonNull List<@NonNull String> suggestions(
final @NonNull CommandContext<C> commandContext,
final @NonNull String input
) {
return Arrays.stream(Material.values())
.map(value -> value.name().toLowerCase(Locale.ROOT))
.collect(Collectors.toList());
}
}
private static final class ModernParser<C> implements ArgumentParser<C, ProtoItemStack> {
private static final Class<?> NMS_ITEM_STACK_CLASS = CraftBukkitReflection.needNMSClass("ItemStack");
private static final Class<?> CRAFT_ITEM_STACK_CLASS =
CraftBukkitReflection.needOBCClass("inventory.CraftItemStack");
private static final Class<?> ARGUMENT_ITEM_STACK_CLASS =
CraftBukkitReflection.needNMSClass("ArgumentItemStack");
private static final Class<?> ARGUMENT_PREDICATE_ITEM_STACK_CLASS =
CraftBukkitReflection.needNMSClass("ArgumentPredicateItemStack");
private static final Class<?> NMS_ITEM_CLASS = CraftBukkitReflection.needNMSClass("Item");
private static final Class<?> CRAFT_MAGIC_NUMBERS_CLASS =
CraftBukkitReflection.needOBCClass("util.CraftMagicNumbers");
private static final Method GET_MATERIAL_METHOD = CraftBukkitReflection
.needMethod(CRAFT_MAGIC_NUMBERS_CLASS, "getMaterial", NMS_ITEM_CLASS);
private static final Method CREATE_ITEM_STACK_METHOD = CraftBukkitReflection
.needMethod(ARGUMENT_PREDICATE_ITEM_STACK_CLASS, "a", int.class, boolean.class);
private static final Method AS_BUKKIT_COPY_METHOD = CraftBukkitReflection
.needMethod(CRAFT_ITEM_STACK_CLASS, "asBukkitCopy", NMS_ITEM_STACK_CLASS);
private static final Field ITEM_FIELD = CraftBukkitReflection.needField(ARGUMENT_PREDICATE_ITEM_STACK_CLASS, "b");
private static final Field COMPOUND_TAG_FIELD = CraftBukkitReflection.needField(ARGUMENT_PREDICATE_ITEM_STACK_CLASS, "c");
private final ArgumentParser<C, ProtoItemStack> parser;
ModernParser() {
try {
this.parser = this.createParser();
} catch (final ReflectiveOperationException ex) {
throw new RuntimeException("Failed to initialize modern ItemStack parser.", ex);
}
}
@SuppressWarnings("unchecked")
private ArgumentParser<C, ProtoItemStack> createParser() throws ReflectiveOperationException {
return new WrappedBrigadierParser<C, Object>(
(ArgumentType<Object>) ARGUMENT_ITEM_STACK_CLASS.getConstructor().newInstance()
).map((ctx, itemInput) -> ArgumentParseResult.success(new ModernProtoItemStack(itemInput)));
}
@Override
public @NonNull ArgumentParseResult<@NonNull ProtoItemStack> parse(
@NonNull final CommandContext<@NonNull C> commandContext,
@NonNull final Queue<@NonNull String> inputQueue
) {
// Minecraft has a parser for this - just use it
return this.parser.parse(commandContext, inputQueue);
}
private static final class ModernProtoItemStack implements ProtoItemStack {
private final Object itemInput;
private final Material material;
private final @Nullable String snbt;
ModernProtoItemStack(final @NonNull Object itemInput) {
this.itemInput = itemInput;
try {
this.material = (Material) GET_MATERIAL_METHOD.invoke(null, ITEM_FIELD.get(itemInput));
final Object compoundTag = COMPOUND_TAG_FIELD.get(itemInput);
if (compoundTag != null) {
this.snbt = compoundTag.toString();
} else {
this.snbt = null;
}
} catch (final ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
}
@Override
public @NonNull Material material() {
return this.material;
}
@Override
public boolean hasExtraData() {
return this.snbt != null;
}
@Override
public @NonNull ItemStack createItemStack(final int stackSize, final boolean respectMaximumStackSize) {
try {
return (ItemStack) AS_BUKKIT_COPY_METHOD.invoke(
null,
CREATE_ITEM_STACK_METHOD.invoke(this.itemInput, stackSize, respectMaximumStackSize)
);
} catch (final InvocationTargetException ex) {
final Throwable cause = ex.getCause();
if (cause instanceof CommandSyntaxException) {
throw new IllegalArgumentException(cause.getMessage(), cause);
}
throw new RuntimeException(ex);
} catch (final ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
}
}
private static final class LegacyParser<C> implements ArgumentParser<C, ProtoItemStack> {
private final ArgumentParser<C, ProtoItemStack> parser = new MaterialArgument.MaterialParser<C>()
.map((ctx, material) -> ArgumentParseResult.success(new LegacyProtoItemStack(material)));
@Override
public @NonNull ArgumentParseResult<@NonNull ProtoItemStack> parse(
@NonNull final CommandContext<@NonNull C> commandContext,
@NonNull final Queue<@NonNull String> inputQueue
) {
return this.parser.parse(commandContext, inputQueue);
}
private static final class LegacyProtoItemStack implements ProtoItemStack {
private final Material material;
private LegacyProtoItemStack(final @NonNull Material material) {
this.material = material;
}
@Override
public @NonNull Material material() {
return this.material;
}
@Override
public boolean hasExtraData() {
return false;
}
@Override
public @NonNull ItemStack createItemStack(final int stackSize, final boolean respectMaximumStackSize)
throws IllegalArgumentException {
if (respectMaximumStackSize && stackSize > this.material.getMaxStackSize()) {
throw new IllegalArgumentException(String.format(
"The maximum stack size for %s is %d",
this.material,
this.material.getMaxStackSize()
));
}
return new ItemStack(this.material, stackSize);
}
}
}
}

View file

@ -28,12 +28,14 @@ import cloud.commandframework.arguments.CommandArgument;
import cloud.commandframework.arguments.parser.ArgumentParseResult; import cloud.commandframework.arguments.parser.ArgumentParseResult;
import cloud.commandframework.arguments.parser.ArgumentParser; import cloud.commandframework.arguments.parser.ArgumentParser;
import cloud.commandframework.bukkit.BukkitCaptionKeys; import cloud.commandframework.bukkit.BukkitCaptionKeys;
import cloud.commandframework.bukkit.BukkitCommandContextKeys;
import cloud.commandframework.captions.CaptionVariable; import cloud.commandframework.captions.CaptionVariable;
import cloud.commandframework.context.CommandContext; import cloud.commandframework.context.CommandContext;
import cloud.commandframework.exceptions.parsing.NoInputProvidedException; import cloud.commandframework.exceptions.parsing.NoInputProvidedException;
import cloud.commandframework.exceptions.parsing.ParserException; import cloud.commandframework.exceptions.parsing.ParserException;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
@ -177,6 +179,10 @@ public final class OfflinePlayerArgument<C> extends CommandArgument<C, OfflinePl
List<String> output = new ArrayList<>(); List<String> output = new ArrayList<>();
for (Player player : Bukkit.getOnlinePlayers()) { for (Player player : Bukkit.getOnlinePlayers()) {
final CommandSender bukkit = commandContext.get(BukkitCommandContextKeys.BUKKIT_COMMAND_SENDER);
if (bukkit instanceof Player && !((Player) bukkit).canSee(player)) {
continue;
}
output.add(player.getName()); output.add(player.getName());
} }

View file

@ -28,11 +28,13 @@ import cloud.commandframework.arguments.CommandArgument;
import cloud.commandframework.arguments.parser.ArgumentParseResult; import cloud.commandframework.arguments.parser.ArgumentParseResult;
import cloud.commandframework.arguments.parser.ArgumentParser; import cloud.commandframework.arguments.parser.ArgumentParser;
import cloud.commandframework.bukkit.BukkitCaptionKeys; import cloud.commandframework.bukkit.BukkitCaptionKeys;
import cloud.commandframework.bukkit.BukkitCommandContextKeys;
import cloud.commandframework.captions.CaptionVariable; import cloud.commandframework.captions.CaptionVariable;
import cloud.commandframework.context.CommandContext; import cloud.commandframework.context.CommandContext;
import cloud.commandframework.exceptions.parsing.NoInputProvidedException; import cloud.commandframework.exceptions.parsing.NoInputProvidedException;
import cloud.commandframework.exceptions.parsing.ParserException; import cloud.commandframework.exceptions.parsing.ParserException;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
@ -169,6 +171,10 @@ public final class PlayerArgument<C> extends CommandArgument<C, Player> {
List<String> output = new ArrayList<>(); List<String> output = new ArrayList<>();
for (Player player : Bukkit.getOnlinePlayers()) { for (Player player : Bukkit.getOnlinePlayers()) {
final CommandSender bukkit = commandContext.get(BukkitCommandContextKeys.BUKKIT_COMMAND_SENDER);
if (bukkit instanceof Player && !((Player) bukkit).canSee(player)) {
continue;
}
output.add(player.getName()); output.add(player.getName());
} }

View file

@ -27,6 +27,7 @@ import cloud.commandframework.ArgumentDescription;
import cloud.commandframework.arguments.CommandArgument; import cloud.commandframework.arguments.CommandArgument;
import cloud.commandframework.arguments.parser.ArgumentParseResult; import cloud.commandframework.arguments.parser.ArgumentParseResult;
import cloud.commandframework.arguments.parser.ArgumentParser; import cloud.commandframework.arguments.parser.ArgumentParser;
import cloud.commandframework.bukkit.BukkitCommandContextKeys;
import cloud.commandframework.bukkit.parsers.location.LocationArgument.LocationParseException; import cloud.commandframework.bukkit.parsers.location.LocationArgument.LocationParseException;
import cloud.commandframework.context.CommandContext; import cloud.commandframework.context.CommandContext;
import io.leangen.geantyref.TypeToken; import io.leangen.geantyref.TypeToken;
@ -183,7 +184,7 @@ public final class Location2DArgument<C> extends CommandArgument<C, Location2D>
coordinates[i] = coordinate.getParsedValue().orElseThrow(NullPointerException::new); coordinates[i] = coordinate.getParsedValue().orElseThrow(NullPointerException::new);
} }
final Location originalLocation; final Location originalLocation;
final CommandSender bukkitSender = commandContext.get("BukkitCommandSender"); final CommandSender bukkitSender = commandContext.get(BukkitCommandContextKeys.BUKKIT_COMMAND_SENDER);
if (bukkitSender instanceof BlockCommandSender) { if (bukkitSender instanceof BlockCommandSender) {
originalLocation = ((BlockCommandSender) bukkitSender).getBlock().getLocation(); originalLocation = ((BlockCommandSender) bukkitSender).getBlock().getLocation();

View file

@ -29,6 +29,7 @@ import cloud.commandframework.arguments.parser.ArgumentParseResult;
import cloud.commandframework.arguments.parser.ArgumentParser; import cloud.commandframework.arguments.parser.ArgumentParser;
import cloud.commandframework.arguments.standard.IntegerArgument; import cloud.commandframework.arguments.standard.IntegerArgument;
import cloud.commandframework.bukkit.BukkitCaptionKeys; import cloud.commandframework.bukkit.BukkitCaptionKeys;
import cloud.commandframework.bukkit.BukkitCommandContextKeys;
import cloud.commandframework.captions.Caption; import cloud.commandframework.captions.Caption;
import cloud.commandframework.captions.CaptionVariable; import cloud.commandframework.captions.CaptionVariable;
import cloud.commandframework.context.CommandContext; import cloud.commandframework.context.CommandContext;
@ -191,7 +192,7 @@ public final class LocationArgument<C> extends CommandArgument<C, Location> {
coordinates[i] = coordinate.getParsedValue().orElseThrow(NullPointerException::new); coordinates[i] = coordinate.getParsedValue().orElseThrow(NullPointerException::new);
} }
final Location originalLocation; final Location originalLocation;
final CommandSender bukkitSender = commandContext.get("BukkitCommandSender"); final CommandSender bukkitSender = commandContext.get(BukkitCommandContextKeys.BUKKIT_COMMAND_SENDER);
if (bukkitSender instanceof BlockCommandSender) { if (bukkitSender instanceof BlockCommandSender) {
originalLocation = ((BlockCommandSender) bukkitSender).getBlock().getLocation(); originalLocation = ((BlockCommandSender) bukkitSender).getBlock().getLocation();

View file

@ -27,6 +27,7 @@ import cloud.commandframework.ArgumentDescription;
import cloud.commandframework.arguments.CommandArgument; import cloud.commandframework.arguments.CommandArgument;
import cloud.commandframework.arguments.parser.ArgumentParseResult; import cloud.commandframework.arguments.parser.ArgumentParseResult;
import cloud.commandframework.arguments.parser.ArgumentParser; import cloud.commandframework.arguments.parser.ArgumentParser;
import cloud.commandframework.bukkit.BukkitCommandContextKeys;
import cloud.commandframework.bukkit.CloudBukkitCapabilities; import cloud.commandframework.bukkit.CloudBukkitCapabilities;
import cloud.commandframework.bukkit.arguments.selector.MultipleEntitySelector; import cloud.commandframework.bukkit.arguments.selector.MultipleEntitySelector;
import cloud.commandframework.context.CommandContext; import cloud.commandframework.context.CommandContext;
@ -38,7 +39,6 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.List; import java.util.List;
import java.util.Queue; import java.util.Queue;
import java.util.Set;
import java.util.function.BiFunction; import java.util.function.BiFunction;
public final class MultipleEntitySelectorArgument<C> extends CommandArgument<C, MultipleEntitySelector> { public final class MultipleEntitySelectorArgument<C> extends CommandArgument<C, MultipleEntitySelector> {
@ -133,7 +133,7 @@ public final class MultipleEntitySelectorArgument<C> extends CommandArgument<C,
final @NonNull CommandContext<C> commandContext, final @NonNull CommandContext<C> commandContext,
final @NonNull Queue<@NonNull String> inputQueue final @NonNull Queue<@NonNull String> inputQueue
) { ) {
if (!commandContext.<Set<CloudBukkitCapabilities>>get("CloudBukkitCapabilities").contains( if (!commandContext.get(BukkitCommandContextKeys.CLOUD_BUKKIT_CAPABILITIES).contains(
CloudBukkitCapabilities.BRIGADIER)) { CloudBukkitCapabilities.BRIGADIER)) {
return ArgumentParseResult.failure(new SelectorParseException( return ArgumentParseResult.failure(new SelectorParseException(
"", "",
@ -153,7 +153,7 @@ public final class MultipleEntitySelectorArgument<C> extends CommandArgument<C,
List<Entity> entities; List<Entity> entities;
try { try {
entities = Bukkit.selectEntities(commandContext.get("BukkitCommandSender"), input); entities = Bukkit.selectEntities(commandContext.get(BukkitCommandContextKeys.BUKKIT_COMMAND_SENDER), input);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
return ArgumentParseResult.failure(new SelectorParseException( return ArgumentParseResult.failure(new SelectorParseException(
input, input,

View file

@ -27,6 +27,7 @@ import cloud.commandframework.ArgumentDescription;
import cloud.commandframework.arguments.CommandArgument; import cloud.commandframework.arguments.CommandArgument;
import cloud.commandframework.arguments.parser.ArgumentParseResult; import cloud.commandframework.arguments.parser.ArgumentParseResult;
import cloud.commandframework.arguments.parser.ArgumentParser; import cloud.commandframework.arguments.parser.ArgumentParser;
import cloud.commandframework.bukkit.BukkitCommandContextKeys;
import cloud.commandframework.bukkit.CloudBukkitCapabilities; import cloud.commandframework.bukkit.CloudBukkitCapabilities;
import cloud.commandframework.bukkit.arguments.selector.MultiplePlayerSelector; import cloud.commandframework.bukkit.arguments.selector.MultiplePlayerSelector;
import cloud.commandframework.bukkit.parsers.PlayerArgument; import cloud.commandframework.bukkit.parsers.PlayerArgument;
@ -34,6 +35,7 @@ import cloud.commandframework.context.CommandContext;
import cloud.commandframework.exceptions.parsing.NoInputProvidedException; import cloud.commandframework.exceptions.parsing.NoInputProvidedException;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
@ -42,7 +44,6 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Queue; import java.util.Queue;
import java.util.Set;
import java.util.function.BiFunction; import java.util.function.BiFunction;
public final class MultiplePlayerSelectorArgument<C> extends CommandArgument<C, MultiplePlayerSelector> { public final class MultiplePlayerSelectorArgument<C> extends CommandArgument<C, MultiplePlayerSelector> {
@ -146,7 +147,7 @@ public final class MultiplePlayerSelectorArgument<C> extends CommandArgument<C,
} }
inputQueue.remove(); inputQueue.remove();
if (!commandContext.<Set<CloudBukkitCapabilities>>get("CloudBukkitCapabilities").contains( if (!commandContext.get(BukkitCommandContextKeys.CLOUD_BUKKIT_CAPABILITIES).contains(
CloudBukkitCapabilities.BRIGADIER)) { CloudBukkitCapabilities.BRIGADIER)) {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
Player player = Bukkit.getPlayer(input); Player player = Bukkit.getPlayer(input);
@ -159,7 +160,7 @@ public final class MultiplePlayerSelectorArgument<C> extends CommandArgument<C,
List<Entity> entities; List<Entity> entities;
try { try {
entities = Bukkit.selectEntities(commandContext.get("BukkitCommandSender"), input); entities = Bukkit.selectEntities(commandContext.get(BukkitCommandContextKeys.BUKKIT_COMMAND_SENDER), input);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
return ArgumentParseResult.failure(new SelectorParseException( return ArgumentParseResult.failure(new SelectorParseException(
input, input,
@ -191,6 +192,10 @@ public final class MultiplePlayerSelectorArgument<C> extends CommandArgument<C,
List<String> output = new ArrayList<>(); List<String> output = new ArrayList<>();
for (Player player : Bukkit.getOnlinePlayers()) { for (Player player : Bukkit.getOnlinePlayers()) {
final CommandSender bukkit = commandContext.get(BukkitCommandContextKeys.BUKKIT_COMMAND_SENDER);
if (bukkit instanceof Player && !((Player) bukkit).canSee(player)) {
continue;
}
output.add(player.getName()); output.add(player.getName());
} }

View file

@ -27,6 +27,7 @@ import cloud.commandframework.ArgumentDescription;
import cloud.commandframework.arguments.CommandArgument; import cloud.commandframework.arguments.CommandArgument;
import cloud.commandframework.arguments.parser.ArgumentParseResult; import cloud.commandframework.arguments.parser.ArgumentParseResult;
import cloud.commandframework.arguments.parser.ArgumentParser; import cloud.commandframework.arguments.parser.ArgumentParser;
import cloud.commandframework.bukkit.BukkitCommandContextKeys;
import cloud.commandframework.bukkit.CloudBukkitCapabilities; import cloud.commandframework.bukkit.CloudBukkitCapabilities;
import cloud.commandframework.bukkit.arguments.selector.SingleEntitySelector; import cloud.commandframework.bukkit.arguments.selector.SingleEntitySelector;
import cloud.commandframework.context.CommandContext; import cloud.commandframework.context.CommandContext;
@ -38,7 +39,6 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.List; import java.util.List;
import java.util.Queue; import java.util.Queue;
import java.util.Set;
import java.util.function.BiFunction; import java.util.function.BiFunction;
public final class SingleEntitySelectorArgument<C> extends CommandArgument<C, SingleEntitySelector> { public final class SingleEntitySelectorArgument<C> extends CommandArgument<C, SingleEntitySelector> {
@ -139,7 +139,7 @@ public final class SingleEntitySelectorArgument<C> extends CommandArgument<C, Si
final @NonNull CommandContext<C> commandContext, final @NonNull CommandContext<C> commandContext,
final @NonNull Queue<@NonNull String> inputQueue final @NonNull Queue<@NonNull String> inputQueue
) { ) {
if (!commandContext.<Set<CloudBukkitCapabilities>>get("CloudBukkitCapabilities").contains( if (!commandContext.get(BukkitCommandContextKeys.CLOUD_BUKKIT_CAPABILITIES).contains(
CloudBukkitCapabilities.BRIGADIER)) { CloudBukkitCapabilities.BRIGADIER)) {
return ArgumentParseResult.failure(new SelectorParseException( return ArgumentParseResult.failure(new SelectorParseException(
"", "",
@ -159,7 +159,7 @@ public final class SingleEntitySelectorArgument<C> extends CommandArgument<C, Si
List<Entity> entities; List<Entity> entities;
try { try {
entities = Bukkit.selectEntities(commandContext.get("BukkitCommandSender"), input); entities = Bukkit.selectEntities(commandContext.get(BukkitCommandContextKeys.BUKKIT_COMMAND_SENDER), input);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
return ArgumentParseResult.failure(new SelectorParseException( return ArgumentParseResult.failure(new SelectorParseException(
input, input,

View file

@ -27,6 +27,7 @@ import cloud.commandframework.ArgumentDescription;
import cloud.commandframework.arguments.CommandArgument; import cloud.commandframework.arguments.CommandArgument;
import cloud.commandframework.arguments.parser.ArgumentParseResult; import cloud.commandframework.arguments.parser.ArgumentParseResult;
import cloud.commandframework.arguments.parser.ArgumentParser; import cloud.commandframework.arguments.parser.ArgumentParser;
import cloud.commandframework.bukkit.BukkitCommandContextKeys;
import cloud.commandframework.bukkit.CloudBukkitCapabilities; import cloud.commandframework.bukkit.CloudBukkitCapabilities;
import cloud.commandframework.bukkit.arguments.selector.SinglePlayerSelector; import cloud.commandframework.bukkit.arguments.selector.SinglePlayerSelector;
import cloud.commandframework.bukkit.parsers.PlayerArgument; import cloud.commandframework.bukkit.parsers.PlayerArgument;
@ -34,6 +35,7 @@ import cloud.commandframework.context.CommandContext;
import cloud.commandframework.exceptions.parsing.NoInputProvidedException; import cloud.commandframework.exceptions.parsing.NoInputProvidedException;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
@ -42,7 +44,6 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Queue; import java.util.Queue;
import java.util.Set;
import java.util.function.BiFunction; import java.util.function.BiFunction;
public final class SinglePlayerSelectorArgument<C> extends CommandArgument<C, SinglePlayerSelector> { public final class SinglePlayerSelectorArgument<C> extends CommandArgument<C, SinglePlayerSelector> {
@ -152,7 +153,7 @@ public final class SinglePlayerSelectorArgument<C> extends CommandArgument<C, Si
} }
inputQueue.remove(); inputQueue.remove();
if (!commandContext.<Set<CloudBukkitCapabilities>>get("CloudBukkitCapabilities").contains( if (!commandContext.get(BukkitCommandContextKeys.CLOUD_BUKKIT_CAPABILITIES).contains(
CloudBukkitCapabilities.BRIGADIER)) { CloudBukkitCapabilities.BRIGADIER)) {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
Player player = Bukkit.getPlayer(input); Player player = Bukkit.getPlayer(input);
@ -165,7 +166,7 @@ public final class SinglePlayerSelectorArgument<C> extends CommandArgument<C, Si
List<Entity> entities; List<Entity> entities;
try { try {
entities = Bukkit.selectEntities(commandContext.get("BukkitCommandSender"), input); entities = Bukkit.selectEntities(commandContext.get(BukkitCommandContextKeys.BUKKIT_COMMAND_SENDER), input);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
return ArgumentParseResult.failure(new SelectorParseException( return ArgumentParseResult.failure(new SelectorParseException(
input, input,
@ -205,6 +206,10 @@ public final class SinglePlayerSelectorArgument<C> extends CommandArgument<C, Si
List<String> output = new ArrayList<>(); List<String> output = new ArrayList<>();
for (Player player : Bukkit.getOnlinePlayers()) { for (Player player : Bukkit.getOnlinePlayers()) {
final CommandSender bukkit = commandContext.get(BukkitCommandContextKeys.BUKKIT_COMMAND_SENDER);
if (bukkit instanceof Player && !((Player) bukkit).canSee(player)) {
continue;
}
output.add(player.getName()); output.add(player.getName());
} }

View file

@ -27,15 +27,18 @@ import cloud.commandframework.CommandTree;
import cloud.commandframework.arguments.CommandArgument; import cloud.commandframework.arguments.CommandArgument;
import cloud.commandframework.brigadier.CloudBrigadierManager; import cloud.commandframework.brigadier.CloudBrigadierManager;
import cloud.commandframework.bukkit.BukkitBrigadierMapper; import cloud.commandframework.bukkit.BukkitBrigadierMapper;
import cloud.commandframework.bukkit.internal.CraftBukkitReflection;
import cloud.commandframework.context.CommandContext; import cloud.commandframework.context.CommandContext;
import cloud.commandframework.permission.CommandPermission; import cloud.commandframework.permission.CommandPermission;
import com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource; import com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.command.PluginIdentifiableCommand; import org.bukkit.command.PluginIdentifiableCommand;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import java.lang.reflect.Method;
import java.util.function.BiPredicate; import java.util.function.BiPredicate;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -46,18 +49,30 @@ class PaperBrigadierListener<C> implements Listener {
PaperBrigadierListener(final @NonNull PaperCommandManager<C> paperCommandManager) { PaperBrigadierListener(final @NonNull PaperCommandManager<C> paperCommandManager) {
this.paperCommandManager = paperCommandManager; this.paperCommandManager = paperCommandManager;
this.brigadierManager = new CloudBrigadierManager<>( this.brigadierManager = new CloudBrigadierManager<>(this.paperCommandManager, () -> new CommandContext<>(
this.paperCommandManager, this.paperCommandManager.getCommandSenderMapper().apply(Bukkit.getConsoleSender()),
() -> new CommandContext<>(
this.paperCommandManager.getCommandSenderMapper()
.apply(Bukkit.getConsoleSender()),
this.paperCommandManager this.paperCommandManager
) ));
);
this.brigadierManager.brigadierSenderMapper( this.brigadierManager.brigadierSenderMapper(sender ->
sender -> this.paperCommandManager.getCommandSenderMapper().apply(sender.getBukkitSender()) this.paperCommandManager.getCommandSenderMapper().apply(sender.getBukkitSender()));
);
new BukkitBrigadierMapper<>(this.paperCommandManager, this.brigadierManager); new BukkitBrigadierMapper<>(this.paperCommandManager, 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 (BukkitBrigadierCommandSource) getListenerMethod
.invoke(null, this.paperCommandManager.getBackwardsCommandSenderMapper().apply(cloud));
} catch (final ReflectiveOperationException e) {
throw new RuntimeException(e);
}
});
} }
protected @NonNull CloudBrigadierManager<C, BukkitBrigadierCommandSource> brigadierManager() { protected @NonNull CloudBrigadierManager<C, BukkitBrigadierCommandSource> brigadierManager() {