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

@ -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 <C> Command sender type
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public final class BukkitBrigadierMapper<C> {
private static final int UUID_ARGUMENT_VERSION = 16;
private final BukkitCommandManager<C> commandManager;
private final CloudBrigadierManager brigadierManager;
private final String nmsVersion;
private final CloudBrigadierManager<C, ?> brigadierManager;
/**
@ -64,38 +66,48 @@ public final class BukkitBrigadierMapper<C> {
*/
public BukkitBrigadierMapper(
final @NonNull BukkitCommandManager<C> commandManager,
final @NonNull CloudBrigadierManager brigadierManager
final @NonNull CloudBrigadierManager<C, ?> 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<UUIDArgument.UUIDParser<C>>() {
}, "UUID");
}
/* Map Enchantment */
this.mapSimpleNMS(new TypeToken<EnchantmentArgument.EnchantmentParser<C>>() {
}, "Enchantment");
/* Map ItemStackArgument */
this.mapSimpleNMS(new TypeToken<ItemStackArgument.Parser<C>>() {
}, "ItemStack");
/* Map Entity Selectors */
this.mapNMS(new TypeToken<SingleEntitySelectorArgument.SingleEntitySelectorParser<C>>() {
}, this.entitySelectorArgumentSupplier(true, false));
this.mapNMS(new TypeToken<SinglePlayerSelectorArgument.SinglePlayerSelectorParser<C>>() {
}, 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 */
this.mapNMS(new TypeToken<LocationArgument.LocationParser<C>>() {
}, this::argumentVec3);
/* Map Vec2I */
this.mapNMS(new TypeToken<Location2DArgument.Location2DParser<C>>() {
}, this::argumentVec2i);
}
/**
@ -103,45 +115,39 @@ public final class BukkitBrigadierMapper<C> {
* @param playersOnly Whether the selector is for players only (true), or for all entities (false)
* @return The NMS ArgumentType
*/
private @NonNull Supplier<ArgumentType<?>> getEntitySelectorArgument(
private @NonNull Supplier<ArgumentType<?>> 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<ArgumentType<?>> 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<ArgumentType<?>> 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<C> {
*
* @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 <T> 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 <T extends ArgumentParser<C, ?>> void mapSimpleNMS(
final @NonNull TypeToken<T> 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<C> {
*
* @param type Type to map
* @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(
final @NonNull Class<?> type,
final @NonNull Supplier<ArgumentType<?>> 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);
}
}

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.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<C> extends CommandManager<C> 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<CommandSender, C> commandSenderMapper;
private final Function<C, CommandSender> backwardsCommandSenderMapper;
@ -134,30 +137,7 @@ public class BukkitCommandManager<C> extends CommandManager<C> 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<C> extends CommandManager<C> 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<C> extends CommandManager<C> implements Brigad
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.
*

View file

@ -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<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
*
* @param mgr The BukkitCommandManager
* @param commandManager The BukkitCommandManager
*/
BukkitCommandPreprocessor(final @NonNull BukkitCommandManager<C> mgr) {
this.mgr = mgr;
BukkitCommandPreprocessor(final @NonNull BukkitCommandManager<C> 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<C> 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
);
}
}

View file

@ -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<C> extends BukkitPluginRegistrationHandler<C> {
private final BukkitCommandManager<C> commandManager;
private final CloudBrigadierManager brigadierManager;
private final CloudBrigadierManager<C, Object> brigadierManager;
private final Commodore commodore;
CloudCommodoreManager(final @NonNull BukkitCommandManager<C> commandManager)
@ -53,17 +54,29 @@ class CloudCommodoreManager<C> extends BukkitPluginRegistrationHandler<C> {
}
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<C> extends BukkitPluginRegistrationHandler<C> {
final @NonNull Command<?> command,
final @NonNull BukkitCommand<C> bukkitCommand
) {
this.registerWithCommodore(label, command);
this.registerWithCommodore(label, (Command<C>) command);
}
protected @NonNull CloudBrigadierManager brigadierManager() {
@ -81,17 +94,13 @@ class CloudCommodoreManager<C> extends BukkitPluginRegistrationHandler<C> {
private void registerWithCommodore(
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
.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);

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.ArgumentParser;
import cloud.commandframework.bukkit.BukkitCaptionKeys;
import cloud.commandframework.bukkit.BukkitCommandContextKeys;
import cloud.commandframework.captions.CaptionVariable;
import cloud.commandframework.context.CommandContext;
import cloud.commandframework.exceptions.parsing.NoInputProvidedException;
import cloud.commandframework.exceptions.parsing.ParserException;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
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<>();
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());
}

View file

@ -28,11 +28,13 @@ import cloud.commandframework.arguments.CommandArgument;
import cloud.commandframework.arguments.parser.ArgumentParseResult;
import cloud.commandframework.arguments.parser.ArgumentParser;
import cloud.commandframework.bukkit.BukkitCaptionKeys;
import cloud.commandframework.bukkit.BukkitCommandContextKeys;
import cloud.commandframework.captions.CaptionVariable;
import cloud.commandframework.context.CommandContext;
import cloud.commandframework.exceptions.parsing.NoInputProvidedException;
import cloud.commandframework.exceptions.parsing.ParserException;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
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<>();
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());
}

View file

@ -27,6 +27,7 @@ import cloud.commandframework.ArgumentDescription;
import cloud.commandframework.arguments.CommandArgument;
import cloud.commandframework.arguments.parser.ArgumentParseResult;
import cloud.commandframework.arguments.parser.ArgumentParser;
import cloud.commandframework.bukkit.BukkitCommandContextKeys;
import cloud.commandframework.bukkit.parsers.location.LocationArgument.LocationParseException;
import cloud.commandframework.context.CommandContext;
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);
}
final Location originalLocation;
final CommandSender bukkitSender = commandContext.get("BukkitCommandSender");
final CommandSender bukkitSender = commandContext.get(BukkitCommandContextKeys.BUKKIT_COMMAND_SENDER);
if (bukkitSender instanceof BlockCommandSender) {
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.standard.IntegerArgument;
import cloud.commandframework.bukkit.BukkitCaptionKeys;
import cloud.commandframework.bukkit.BukkitCommandContextKeys;
import cloud.commandframework.captions.Caption;
import cloud.commandframework.captions.CaptionVariable;
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);
}
final Location originalLocation;
final CommandSender bukkitSender = commandContext.get("BukkitCommandSender");
final CommandSender bukkitSender = commandContext.get(BukkitCommandContextKeys.BUKKIT_COMMAND_SENDER);
if (bukkitSender instanceof BlockCommandSender) {
originalLocation = ((BlockCommandSender) bukkitSender).getBlock().getLocation();

View file

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

View file

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

View file

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

View file

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