From d4d2c490cabd70bc00dc5a87ff09afb5a3aaaced Mon Sep 17 00:00:00 2001 From: Aikar Date: Tue, 18 Apr 2017 20:38:30 -0400 Subject: [PATCH] Refactor stuff away from static and exposed Command Contexts - Fixes #2 --- src/main/java/co/aikar/commands/ACF.java | 4 - .../java/co/aikar/commands/BaseCommand.java | 7 +- .../aikar/commands/BukkitCommandContexts.java | 74 +++++++++++++++++++ .../{managers => }/BukkitCommandManager.java | 27 +++++-- .../co/aikar/commands/CommandContexts.java | 56 +++----------- .../{managers => }/CommandManager.java | 19 ++--- .../java/co/aikar/commands/CommandUtil.java | 6 ++ .../{managers => }/PaperCommandManager.java | 2 +- .../co/aikar/commands/RegisteredCommand.java | 26 +++---- 9 files changed, 135 insertions(+), 86 deletions(-) create mode 100644 src/main/java/co/aikar/commands/BukkitCommandContexts.java rename src/main/java/co/aikar/commands/{managers => }/BukkitCommandManager.java (69%) rename src/main/java/co/aikar/commands/{managers => }/CommandManager.java (81%) rename src/main/java/co/aikar/commands/{managers => }/PaperCommandManager.java (97%) diff --git a/src/main/java/co/aikar/commands/ACF.java b/src/main/java/co/aikar/commands/ACF.java index 8c5b6ed0..abff87c9 100644 --- a/src/main/java/co/aikar/commands/ACF.java +++ b/src/main/java/co/aikar/commands/ACF.java @@ -23,10 +23,6 @@ package co.aikar.commands; -import co.aikar.commands.managers.BukkitCommandManager; -import co.aikar.commands.managers.CommandManager; -import co.aikar.commands.managers.PaperCommandManager; -import org.bukkit.Bukkit; import org.bukkit.plugin.Plugin; /** diff --git a/src/main/java/co/aikar/commands/BaseCommand.java b/src/main/java/co/aikar/commands/BaseCommand.java index 7bb81126..34538696 100644 --- a/src/main/java/co/aikar/commands/BaseCommand.java +++ b/src/main/java/co/aikar/commands/BaseCommand.java @@ -44,6 +44,7 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -61,6 +62,8 @@ public abstract class BaseCommand extends Command { protected String execSubcommand; @SuppressWarnings("WeakerAccess") protected String[] origArgs; + CommandManager manager = null; + Map registeredCommands = new HashMap<>(); public BaseCommand(Plugin plugin) { this(plugin, null); @@ -139,8 +142,8 @@ public abstract class BaseCommand extends Command { register(getName(), this); } - private boolean register(String name, Command cmd) { - return Bukkit.getServer().getCommandMap().register(name.toLowerCase(), plugin.getName().toLowerCase(), cmd); + private void register(String name, Command cmd) { + this.registeredCommands.put(name.toLowerCase(), cmd); } private void registerSubcommand(Method method, String subCommand) { diff --git a/src/main/java/co/aikar/commands/BukkitCommandContexts.java b/src/main/java/co/aikar/commands/BukkitCommandContexts.java new file mode 100644 index 00000000..8b3dceee --- /dev/null +++ b/src/main/java/co/aikar/commands/BukkitCommandContexts.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2016-2017 Daniel Ennis (Aikar) - MIT License + * + * 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 co.aikar.commands; + +import co.aikar.commands.annotation.Optional; +import co.aikar.commands.contexts.OnlinePlayer; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; + +public class BukkitCommandContexts extends CommandContexts { + + BukkitCommandContexts(CommandManager manager) { + super(manager); + + registerContext(OnlinePlayer.class, (c) -> { + final String playercheck = c.popFirstArg(); + Player player = CommandUtil.findPlayerSmart(c.getSender(), playercheck); + if (player == null) { + CommandUtil.sendMsg(c.getSender(), "&cCould not find a player by the name " + playercheck); + throw new InvalidCommandArgument(false); + } + return new OnlinePlayer(player); + }); + registerSenderAwareContext(World.class, (c) -> { + String firstArg = c.getFirstArg(); + World world = firstArg != null ? Bukkit.getWorld(firstArg) : null; + if (world != null) { + c.popFirstArg(); + } + if (world == null && c.getSender() instanceof Player) { + world = ((Entity) c.getSender()).getWorld(); + } + if (world == null) { + throw new InvalidCommandArgument("Invalid World"); + } + return world; + }); + registerSenderAwareContext(CommandSender.class, CommandExecutionContext::getSender); + registerSenderAwareContext(Player.class, (c) -> { + Player player = c.getSender() instanceof Player ? (Player) c.getSender() : null; + if (player == null && !c.hasAnnotation(Optional.class)) { + throw new InvalidCommandArgument("Requires a player to run this command", false); + } + if (player != null && c.hasFlag("itemheld") && !CommandUtil.isValidItem(player.getInventory().getItemInMainHand())) { + throw new InvalidCommandArgument("You must be holding an item in your main hand.", false); + } + return player; + }); + } +} diff --git a/src/main/java/co/aikar/commands/managers/BukkitCommandManager.java b/src/main/java/co/aikar/commands/BukkitCommandManager.java similarity index 69% rename from src/main/java/co/aikar/commands/managers/BukkitCommandManager.java rename to src/main/java/co/aikar/commands/BukkitCommandManager.java index 95d1a919..fa4398c3 100644 --- a/src/main/java/co/aikar/commands/managers/BukkitCommandManager.java +++ b/src/main/java/co/aikar/commands/BukkitCommandManager.java @@ -21,28 +21,41 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package co.aikar.commands.managers; +package co.aikar.commands; -import co.aikar.commands.BaseCommand; import org.bukkit.Bukkit; +import org.bukkit.command.Command; import org.bukkit.plugin.Plugin; +import java.util.Map; + public class BukkitCommandManager implements CommandManager { @SuppressWarnings("WeakerAccess") protected final Plugin plugin; + private CommandContexts contexts; public BukkitCommandManager(Plugin plugin) { this.plugin = plugin; + this.contexts = new CommandContexts(this); + } + + @Override + public CommandContexts getCommandContexts() { + return contexts; } @Override public boolean register(BaseCommand command) { - return Bukkit.getServer().getCommandMap().register(this.plugin.getDescription().getName(), command); - } + command.manager = this; + final String plugin = this.plugin.getName().toLowerCase(); + boolean allSuccess = true; + for (Map.Entry entry : command.registeredCommands.entrySet()) { + if (!Bukkit.getServer().getCommandMap().register(entry.getKey().toLowerCase(), plugin, entry.getValue())) { + allSuccess = false; + } + } - @Override - public boolean register(BaseCommand command, String commandName) { - return Bukkit.getServer().getCommandMap().register(commandName, this.plugin.getDescription().getName(), command); + return allSuccess; } } diff --git a/src/main/java/co/aikar/commands/CommandContexts.java b/src/main/java/co/aikar/commands/CommandContexts.java index 298c6530..b124da9e 100644 --- a/src/main/java/co/aikar/commands/CommandContexts.java +++ b/src/main/java/co/aikar/commands/CommandContexts.java @@ -32,23 +32,22 @@ import co.aikar.commands.contexts.OnlinePlayer; import co.aikar.commands.contexts.SenderAwareContextResolver; import com.google.common.collect.Maps; import org.bukkit.Bukkit; -import org.bukkit.Material; import org.bukkit.World; import org.bukkit.command.CommandSender; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; import java.util.List; import java.util.Map; -public final class CommandContexts { - private static final Map, ContextResolver> contextMap = Maps.newHashMap(); +@SuppressWarnings("WeakerAccess") +public class CommandContexts { + private final CommandManager manager; + private final Map, ContextResolver> contextMap = Maps.newHashMap(); - private CommandContexts() {} - - public static void initialize() { + CommandContexts(CommandManager manager) { + this.manager = manager; registerContext(Integer.class, (c) -> { try { return CommandUtil.parseNumber(c.popFirstArg(), c.hasFlag("suffixes")).intValue(); @@ -118,40 +117,6 @@ public final class CommandContexts { return result; }); - registerContext(OnlinePlayer.class, (c) -> { - final String playercheck = c.popFirstArg(); - Player player = CommandUtil.findPlayerSmart(c.getSender(), playercheck); - if (player == null) { - CommandUtil.sendMsg(c.getSender(), "&cCould not find a player by the name " + playercheck); - throw new InvalidCommandArgument(false); - } - return new OnlinePlayer(player); - }); - registerSenderAwareContext(World.class, (c) -> { - String firstArg = c.getFirstArg(); - World world = firstArg != null ? Bukkit.getWorld(firstArg) : null; - if (world != null) { - c.popFirstArg(); - } - if (world == null && c.getSender() instanceof Player) { - world = ((Entity) c.getSender()).getWorld(); - } - if (world == null) { - throw new InvalidCommandArgument("Invalid World"); - } - return world; - }); - registerSenderAwareContext(CommandSender.class, CommandExecutionContext::getSender); - registerSenderAwareContext(Player.class, (c) -> { - Player player = c.getSender() instanceof Player ? (Player) c.getSender() : null; - if (player == null && !c.hasAnnotation(Optional.class)) { - throw new InvalidCommandArgument("Requires a player to run this command", false); - } - if (player != null && c.hasFlag("itemheld") && !isValidItem(player.getInventory().getItemInMainHand())) { - throw new InvalidCommandArgument("You must be holding an item in your main hand.", false); - } - return player; - }); registerContext(Enum.class, (c) -> { final String first = c.popFirstArg(); Class> enumCls = (Class>) c.getParam().getType(); @@ -164,14 +129,14 @@ public final class CommandContexts { }); } - public static void registerSenderAwareContext(Class context, SenderAwareContextResolver supplier) { + public void registerSenderAwareContext(Class context, SenderAwareContextResolver supplier) { contextMap.put(context, supplier); } - public static void registerContext(Class context, ContextResolver supplier) { + public void registerContext(Class context, ContextResolver supplier) { contextMap.put(context, supplier); } - public static ContextResolver getResolver(Class type) { + public ContextResolver getResolver(Class type) { Class rootType = type; do { if (type == Object.class) { @@ -187,7 +152,4 @@ public final class CommandContexts { CommandLog.exception(new InvalidConfigurationException("No context resolver defined for " + rootType.getName())); return null; } - private static boolean isValidItem(ItemStack item) { - return item != null && item.getType() != Material.AIR && item.getAmount() > 0; - } } diff --git a/src/main/java/co/aikar/commands/managers/CommandManager.java b/src/main/java/co/aikar/commands/CommandManager.java similarity index 81% rename from src/main/java/co/aikar/commands/managers/CommandManager.java rename to src/main/java/co/aikar/commands/CommandManager.java index 0113a407..fe1917ea 100644 --- a/src/main/java/co/aikar/commands/managers/CommandManager.java +++ b/src/main/java/co/aikar/commands/CommandManager.java @@ -21,12 +21,16 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package co.aikar.commands.managers; - -import co.aikar.commands.BaseCommand; +package co.aikar.commands; public interface CommandManager { + /** + * Gets the command contexts registered + * @return Command Contexts + */ + CommandContexts getCommandContexts(); + /** * Registers a command with ACF * @@ -34,13 +38,4 @@ public interface CommandManager { * @return boolean */ boolean register(BaseCommand command); - - /** - * Registers a command with ACF - * - * @param command The command to register - * @param commandName Specific command name to register as - * @return boolean - */ - boolean register(BaseCommand command, String commandName); } diff --git a/src/main/java/co/aikar/commands/CommandUtil.java b/src/main/java/co/aikar/commands/CommandUtil.java index b18863b8..1b4ba158 100644 --- a/src/main/java/co/aikar/commands/CommandUtil.java +++ b/src/main/java/co/aikar/commands/CommandUtil.java @@ -34,6 +34,7 @@ import org.bukkit.World; import org.bukkit.command.CommandSender; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -880,6 +881,11 @@ final class CommandUtil { } return timingProvider.newTiming(cmd, command); } + + static boolean isValidItem(ItemStack item) { + return item != null && item.getType() != Material.AIR && item.getAmount() > 0; + } + private enum TimingType { SPIGOT() { @Override diff --git a/src/main/java/co/aikar/commands/managers/PaperCommandManager.java b/src/main/java/co/aikar/commands/PaperCommandManager.java similarity index 97% rename from src/main/java/co/aikar/commands/managers/PaperCommandManager.java rename to src/main/java/co/aikar/commands/PaperCommandManager.java index 4b3df50e..5d772fe9 100644 --- a/src/main/java/co/aikar/commands/managers/PaperCommandManager.java +++ b/src/main/java/co/aikar/commands/PaperCommandManager.java @@ -21,7 +21,7 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package co.aikar.commands.managers; +package co.aikar.commands; import org.bukkit.plugin.Plugin; diff --git a/src/main/java/co/aikar/commands/RegisteredCommand.java b/src/main/java/co/aikar/commands/RegisteredCommand.java index 691a33db..b5148ae7 100644 --- a/src/main/java/co/aikar/commands/RegisteredCommand.java +++ b/src/main/java/co/aikar/commands/RegisteredCommand.java @@ -48,18 +48,18 @@ import java.util.Set; import java.util.stream.Collectors; public class RegisteredCommand { - public final BaseCommand scope; + private final BaseCommand scope; public final String command; - public final Method method; - public final String prefSubCommand; - public final Parameter[] parameters; - public final ContextResolver[] resolvers; - public final String syntax; + private final Method method; + final String prefSubCommand; + final Parameter[] parameters; + final ContextResolver[] resolvers; + final String syntax; - public final CommandPermission perm; - public final CommandCompletion complete; - public final int nonSenderAwareResolvers; - public final int optionalResolvers; + private final CommandPermission perm; + final CommandCompletion complete; + final int nonSenderAwareResolvers; + final int optionalResolvers; CommandTiming timing; RegisteredCommand(BaseCommand scope, String command, Method method, String prefSubCommand) { @@ -83,7 +83,7 @@ public class RegisteredCommand { for (int i = 0; i < parameters.length; i++) { final Parameter parameter = parameters[i]; final Class type = parameter.getType(); - final ContextResolver resolver = CommandContexts.getResolver(type); + final ContextResolver resolver = scope.manager.getCommandContexts().getResolver(type); if (resolver != null) { resolvers[i] = resolver; @@ -117,7 +117,7 @@ public class RegisteredCommand { this.optionalResolvers = optionalResolvers; } - public void invoke(CommandSender sender, List args) { + void invoke(CommandSender sender, List args) { if (!scope.canExecute(sender, this)) { return; } @@ -191,7 +191,7 @@ public class RegisteredCommand { } } - public boolean hasPermission(CommandSender check) { + boolean hasPermission(CommandSender check) { return perm == null || !(check instanceof Player) || check.hasPermission(perm.value()); } }