From 40eaa9ea07a4bf9ded34b251839d71c49182fb8f Mon Sep 17 00:00:00 2001 From: Aikar Date: Mon, 8 Jan 2018 23:30:27 -0500 Subject: [PATCH] =?UTF-8?q?Command=20Conditions=20and=20MANY=20other=20cod?= =?UTF-8?q?e=20changes=20for=20Generics=20<3=F0=9F=8C=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This completes and fully enables a new feature called "Conditions" We already had some forms of conditions built into @Flags such as on the Player for itemheld. However, letting end users add additional restrictions to existing context handlers such as players is not possible without redefining the context. That's not friendly nor scalable. Flags will now be primarily only for controlling how to resolve a context, and then Conditions will then be the way to validate the context and trigger a failure if the condition is not met. Conditions can be placed on Command Class, Methods, or individual Parameters. --- .../BukkitCommandCompletionContext.java | 7 +- .../BukkitCommandExecutionContext.java | 3 +- .../aikar/commands/BukkitCommandIssuer.java | 8 +- .../aikar/commands/BukkitCommandManager.java | 15 +-- .../commands/BukkitConditionContext.java | 15 ++- .../BungeeCommandCompletionContext.java | 9 +- .../BungeeCommandExecutionContext.java | 5 + .../aikar/commands/BungeeCommandIssuer.java | 11 +- .../aikar/commands/BungeeCommandManager.java | 24 ++-- .../commands/BungeeConditionContext.java | 16 ++- .../BungeeParameterConditionContext.java | 9 -- .../java/co/aikar/commands/BaseCommand.java | 4 +- .../commands/CommandCompletionContext.java | 6 +- .../co/aikar/commands/CommandConditions.java | 109 ++++++++++-------- .../co/aikar/commands/CommandManager.java | 21 ++-- .../co/aikar/commands/ConditionContext.java | 37 +++--- .../commands/ConditionFailedException.java | 23 +++- .../commands/InvalidCommandArgument.java | 11 +- .../main/java/co/aikar/commands/Locales.java | 11 +- .../commands/ParameterConditionContext.java | 97 ---------------- .../co/aikar/commands/RegisteredCommand.java | 16 ++- .../aikar/commands/annotation/Conditions.java | 3 - .../java/co/aikar/acfexample/ACFExample.java | 21 +++- .../SpongeCommandCompletionContext.java | 9 +- .../SpongeCommandExecutionContext.java | 5 + .../aikar/commands/SpongeCommandIssuer.java | 9 +- .../aikar/commands/SpongeCommandManager.java | 17 +-- .../commands/SpongeConditionContext.java | 16 ++- .../SpongeParameterConditionContext.java | 9 -- 29 files changed, 255 insertions(+), 291 deletions(-) delete mode 100644 bungee/src/main/java/co/aikar/commands/BungeeParameterConditionContext.java rename bukkit/src/main/java/co/aikar/commands/BukkitParameterConditionContext.java => core/src/main/java/co/aikar/commands/ConditionFailedException.java (64%) delete mode 100644 core/src/main/java/co/aikar/commands/ParameterConditionContext.java delete mode 100644 sponge/src/main/java/co/aikar/commands/SpongeParameterConditionContext.java diff --git a/bukkit/src/main/java/co/aikar/commands/BukkitCommandCompletionContext.java b/bukkit/src/main/java/co/aikar/commands/BukkitCommandCompletionContext.java index 2908e503..fdd9cb43 100644 --- a/bukkit/src/main/java/co/aikar/commands/BukkitCommandCompletionContext.java +++ b/bukkit/src/main/java/co/aikar/commands/BukkitCommandCompletionContext.java @@ -26,8 +26,8 @@ package co.aikar.commands; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -public class BukkitCommandCompletionContext extends CommandCompletionContext { - BukkitCommandCompletionContext(RegisteredCommand command, CommandIssuer issuer, String input, String config, String[] args) { +public class BukkitCommandCompletionContext extends CommandCompletionContext { + BukkitCommandCompletionContext(RegisteredCommand command, BukkitCommandIssuer issuer, String input, String config, String[] args) { super(command, issuer, input, config, args); } @@ -40,7 +40,6 @@ public class BukkitCommandCompletionContext extends CommandCompletionContext { * @return */ public Player getPlayer() { - CommandSender issuer = this.issuer.getIssuer(); - return issuer instanceof Player ? (Player) issuer : null; + return this.issuer.getPlayer(); } } diff --git a/bukkit/src/main/java/co/aikar/commands/BukkitCommandExecutionContext.java b/bukkit/src/main/java/co/aikar/commands/BukkitCommandExecutionContext.java index abef626a..e3cd18fd 100644 --- a/bukkit/src/main/java/co/aikar/commands/BukkitCommandExecutionContext.java +++ b/bukkit/src/main/java/co/aikar/commands/BukkitCommandExecutionContext.java @@ -45,7 +45,6 @@ public class BukkitCommandExecutionContext extends CommandExecutionContext T getIssuer() { + public CommandSender getIssuer() { //noinspection unchecked - return (T) sender; + return sender; + } + + public Player getPlayer() { + return isPlayer() ? (Player) sender : null; } @Override diff --git a/bukkit/src/main/java/co/aikar/commands/BukkitCommandManager.java b/bukkit/src/main/java/co/aikar/commands/BukkitCommandManager.java index f3055428..d2e65a7f 100644 --- a/bukkit/src/main/java/co/aikar/commands/BukkitCommandManager.java +++ b/bukkit/src/main/java/co/aikar/commands/BukkitCommandManager.java @@ -23,7 +23,6 @@ package co.aikar.commands; -import co.aikar.commands.annotation.Conditions; import co.aikar.commands.apachecommonslang.ApacheCommonsExceptionUtil; import co.aikar.timings.lib.MCTiming; import co.aikar.timings.lib.TimingManager; @@ -59,9 +58,7 @@ public class BukkitCommandManager extends CommandManager< ChatColor, BukkitMessageFormatter, BukkitCommandExecutionContext, - BukkitCommandCompletionContext, - BukkitConditionContext, - BukkitParameterConditionContext + BukkitConditionContext > { @SuppressWarnings("WeakerAccess") @@ -304,7 +301,7 @@ public class BukkitCommandManager extends CommandManager< @Override public BukkitCommandCompletionContext createCompletionContext(RegisteredCommand command, CommandIssuer sender, String input, String config, String[] args) { - return new BukkitCommandCompletionContext(command, sender, input, config, args); + return new BukkitCommandCompletionContext(command, (BukkitCommandIssuer) sender, input, config, args); } @Override @@ -313,14 +310,10 @@ public class BukkitCommandManager extends CommandManager< } @Override - public BukkitConditionContext createConditionContext(CommandOperationContext context, Conditions conditions) { - return new BukkitConditionContext(context.getRegisteredCommand(), (BukkitCommandIssuer) context.getCommandIssuer(), conditions); + public BukkitConditionContext createConditionContext(CommandIssuer issuer, String config) { + return new BukkitConditionContext((BukkitCommandIssuer) issuer, config); } - @Override - public

BukkitParameterConditionContext createConditionContext(CommandOperationContext context, BukkitCommandExecutionContext execContext, Conditions conditions) { - return new BukkitParameterConditionContext

(context.getRegisteredCommand(), (BukkitCommandIssuer) context.getCommandIssuer(), execContext, conditions); - } @Override public void log(LogLevel level, String message, Throwable throwable) { diff --git a/bukkit/src/main/java/co/aikar/commands/BukkitConditionContext.java b/bukkit/src/main/java/co/aikar/commands/BukkitConditionContext.java index e26095b6..377d20c3 100644 --- a/bukkit/src/main/java/co/aikar/commands/BukkitConditionContext.java +++ b/bukkit/src/main/java/co/aikar/commands/BukkitConditionContext.java @@ -23,10 +23,19 @@ package co.aikar.commands; -import co.aikar.commands.annotation.Conditions; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; public class BukkitConditionContext extends ConditionContext { - BukkitConditionContext(RegisteredCommand cmd, BukkitCommandIssuer issuer, Conditions condAnno) { - super(cmd, issuer, condAnno); + BukkitConditionContext(BukkitCommandIssuer issuer, String config) { + super(issuer, config); + } + + public CommandSender getSender() { + return getIssuer().getIssuer(); + } + + public Player getPlayer() { + return getIssuer().getPlayer(); } } diff --git a/bungee/src/main/java/co/aikar/commands/BungeeCommandCompletionContext.java b/bungee/src/main/java/co/aikar/commands/BungeeCommandCompletionContext.java index 02f8661c..d3db7ea3 100644 --- a/bungee/src/main/java/co/aikar/commands/BungeeCommandCompletionContext.java +++ b/bungee/src/main/java/co/aikar/commands/BungeeCommandCompletionContext.java @@ -24,14 +24,19 @@ package co.aikar.commands; import net.md_5.bungee.api.CommandSender; +import net.md_5.bungee.api.connection.ProxiedPlayer; -public class BungeeCommandCompletionContext extends CommandCompletionContext { +public class BungeeCommandCompletionContext extends CommandCompletionContext { - BungeeCommandCompletionContext(RegisteredCommand command, CommandIssuer issuer, String input, String config, String[] args) { + BungeeCommandCompletionContext(RegisteredCommand command, BungeeCommandIssuer issuer, String input, String config, String[] args) { super(command, issuer, input, config, args); } public CommandSender getSender() { return this.getIssuer().getIssuer(); } + + public ProxiedPlayer getPlayer() { + return this.issuer.getPlayer(); + } } diff --git a/bungee/src/main/java/co/aikar/commands/BungeeCommandExecutionContext.java b/bungee/src/main/java/co/aikar/commands/BungeeCommandExecutionContext.java index 01853b79..2eec2765 100644 --- a/bungee/src/main/java/co/aikar/commands/BungeeCommandExecutionContext.java +++ b/bungee/src/main/java/co/aikar/commands/BungeeCommandExecutionContext.java @@ -24,6 +24,7 @@ package co.aikar.commands; import net.md_5.bungee.api.CommandSender; +import net.md_5.bungee.api.connection.ProxiedPlayer; import java.lang.reflect.Parameter; import java.util.List; @@ -38,4 +39,8 @@ public class BungeeCommandExecutionContext extends CommandExecutionContext T getIssuer() { - //noinspection unchecked - return (T) sender; + public CommandSender getIssuer() { + return sender; + } + + public ProxiedPlayer getPlayer() { + return isPlayer() ? (ProxiedPlayer) sender : null; } @Override diff --git a/bungee/src/main/java/co/aikar/commands/BungeeCommandManager.java b/bungee/src/main/java/co/aikar/commands/BungeeCommandManager.java index 45ea391b..88476928 100644 --- a/bungee/src/main/java/co/aikar/commands/BungeeCommandManager.java +++ b/bungee/src/main/java/co/aikar/commands/BungeeCommandManager.java @@ -23,7 +23,6 @@ package co.aikar.commands; -import co.aikar.commands.annotation.Conditions; import co.aikar.commands.apachecommonslang.ApacheCommonsExceptionUtil; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.CommandSender; @@ -43,9 +42,7 @@ public class BungeeCommandManager extends CommandManager< ChatColor, BungeeMessageFormatter, BungeeCommandExecutionContext, - BungeeCommandCompletionContext, - BungeeConditionContext, - BungeeParameterConditionContext + BungeeConditionContext > { protected final Plugin plugin; @@ -160,26 +157,19 @@ public class BungeeCommandManager extends CommandManager< @Override public CommandCompletionContext createCompletionContext(RegisteredCommand command, CommandIssuer sender, String input, String config, String[] args) { - return new BungeeCommandCompletionContext(command, sender, input, config, args); + return new BungeeCommandCompletionContext(command, (BungeeCommandIssuer) sender, input, config, args); } - - @Override - public BungeeConditionContext createConditionContext(CommandOperationContext context, Conditions conditions) { - return new BungeeConditionContext(context.getRegisteredCommand(), (BungeeCommandIssuer) context.getCommandIssuer(), conditions); - } - - @Override - public

BungeeParameterConditionContext createConditionContext(CommandOperationContext context, BungeeCommandExecutionContext execContext, Conditions conditions) { - return new BungeeParameterConditionContext

(context.getRegisteredCommand(), (BungeeCommandIssuer) context.getCommandIssuer(), execContext, conditions); - } - - @Override public RegisteredCommand createRegisteredCommand(BaseCommand command, String cmdName, Method method, String prefSubCommand) { return new RegisteredCommand(command, cmdName, method, prefSubCommand); } + @Override + public BungeeConditionContext createConditionContext(CommandIssuer issuer, String config) { + return new BungeeConditionContext((BungeeCommandIssuer) issuer, config); + } + @Override public void log(LogLevel level, String message, Throwable throwable) { Logger logger = this.plugin.getLogger(); diff --git a/bungee/src/main/java/co/aikar/commands/BungeeConditionContext.java b/bungee/src/main/java/co/aikar/commands/BungeeConditionContext.java index d9abeacc..a0e5fd50 100644 --- a/bungee/src/main/java/co/aikar/commands/BungeeConditionContext.java +++ b/bungee/src/main/java/co/aikar/commands/BungeeConditionContext.java @@ -1,9 +1,19 @@ package co.aikar.commands; -import co.aikar.commands.annotation.Conditions; +import net.md_5.bungee.api.CommandSender; +import net.md_5.bungee.api.connection.ProxiedPlayer; public class BungeeConditionContext extends ConditionContext { - BungeeConditionContext(RegisteredCommand cmd, BungeeCommandIssuer issuer, Conditions condAnno) { - super(cmd, issuer, condAnno); + BungeeConditionContext(BungeeCommandIssuer issuer, String config) { + super(issuer, config); + } + + + public CommandSender getSender() { + return getIssuer().getIssuer(); + } + + public ProxiedPlayer getPlayer() { + return getIssuer().getPlayer(); } } diff --git a/bungee/src/main/java/co/aikar/commands/BungeeParameterConditionContext.java b/bungee/src/main/java/co/aikar/commands/BungeeParameterConditionContext.java deleted file mode 100644 index b605e5f2..00000000 --- a/bungee/src/main/java/co/aikar/commands/BungeeParameterConditionContext.java +++ /dev/null @@ -1,9 +0,0 @@ -package co.aikar.commands; - -import co.aikar.commands.annotation.Conditions; - -public class BungeeParameterConditionContext

extends ParameterConditionContext { - BungeeParameterConditionContext(RegisteredCommand cmd, BungeeCommandIssuer issuer, BungeeCommandExecutionContext execContext, Conditions conditions) { - super(cmd, issuer, execContext, conditions); - } -} diff --git a/core/src/main/java/co/aikar/commands/BaseCommand.java b/core/src/main/java/co/aikar/commands/BaseCommand.java index ec323bd1..027b5a8c 100644 --- a/core/src/main/java/co/aikar/commands/BaseCommand.java +++ b/core/src/main/java/co/aikar/commands/BaseCommand.java @@ -71,7 +71,7 @@ public abstract class BaseCommand { private String execSubcommand; @SuppressWarnings("WeakerAccess") private String[] origArgs; - CommandManager manager = null; + CommandManager manager = null; BaseCommand parentCommand; Map registeredCommands = new HashMap<>(); String description; @@ -443,7 +443,7 @@ public abstract class BaseCommand { return; } List sargs = Lists.newArrayList(args); - cmd.invoke(issuer, sargs); + cmd.invoke(issuer, sargs, commandOperationContext); } else { issuer.sendMessage(MessageType.ERROR, MessageKeys.PERMISSION_DENIED); } diff --git a/core/src/main/java/co/aikar/commands/CommandCompletionContext.java b/core/src/main/java/co/aikar/commands/CommandCompletionContext.java index 1b366d01..2ec3a49c 100644 --- a/core/src/main/java/co/aikar/commands/CommandCompletionContext.java +++ b/core/src/main/java/co/aikar/commands/CommandCompletionContext.java @@ -30,15 +30,15 @@ import java.lang.reflect.Parameter; import java.util.List; import java.util.Map; -public class CommandCompletionContext { +public class CommandCompletionContext { private final RegisteredCommand command; - protected final CommandIssuer issuer; + protected final I issuer; private final String input; private final String config; private final Map configs = Maps.newHashMap(); private final List args; - CommandCompletionContext(RegisteredCommand command, CommandIssuer issuer, String input, String config, String[] args) { + CommandCompletionContext(RegisteredCommand command, I issuer, String input, String config, String[] args) { this.command = command; this.issuer = issuer; this.input = input; diff --git a/core/src/main/java/co/aikar/commands/CommandConditions.java b/core/src/main/java/co/aikar/commands/CommandConditions.java index 1c5018a5..50325291 100644 --- a/core/src/main/java/co/aikar/commands/CommandConditions.java +++ b/core/src/main/java/co/aikar/commands/CommandConditions.java @@ -27,88 +27,92 @@ import co.aikar.commands.annotation.Conditions; import com.google.common.collect.HashBasedTable; import com.google.common.collect.Maps; import com.google.common.collect.Table; +import org.jetbrains.annotations.NotNull; import java.util.Map; @SuppressWarnings("BooleanMethodIsAlwaysInverted") // No IDEA, you are wrong public class CommandConditions < I extends CommandIssuer, - M extends CommandManager, - CC extends ConditionContext, CEC extends CommandExecutionContext, - PCC extends ParameterConditionContext + CC extends ConditionContext > { - M manager; - Map> conditions = Maps.newHashMap(); - Table, String, ParameterCondition> paramConditions = HashBasedTable.create(); - CommandConditions(M manager) { + private CommandManager manager; + private Map> conditions = Maps.newHashMap(); + private Table, String, ParameterCondition> paramConditions = HashBasedTable.create(); + + CommandConditions(CommandManager manager) { this.manager = manager; } - Condition addCondition(String id, Condition handler) { + public Condition addCondition(@NotNull String id, @NotNull Condition handler) { return this.conditions.put(id.toLowerCase(), handler); } -

ParameterCondition addCondition(Class

clazz, String id, ParameterCondition handler) { + public

ParameterCondition addCondition(Class

clazz, @NotNull String id, + @NotNull ParameterCondition handler) { return this.paramConditions.put(clazz, id.toLowerCase(), handler); } - boolean validateConditions(CommandOperationContext context, CEC cec) { + void validateConditions(CEC cec, Object value) throws InvalidCommandArgument { Conditions conditions = cec.getParam().getAnnotation(Conditions.class); - return conditions == null || validateConditions(conditions, context, cec); + validateConditions(conditions, cec, value); } - boolean validateConditions(CommandOperationContext context) { + void validateConditions(CommandOperationContext context) throws InvalidCommandArgument { RegisteredCommand cmd = context.getRegisteredCommand(); Conditions conditions = cmd.method.getAnnotation(Conditions.class); - if (conditions != null) { - if (!validateConditions(conditions, context)) { - return false; - } - } - return validateConditions(cmd.scope, context); + validateConditions(conditions, context); + validateConditions(cmd.scope, context); } - private boolean validateConditions(BaseCommand scope, CommandOperationContext operationContext) { + private void validateConditions(BaseCommand scope, CommandOperationContext operationContext) throws InvalidCommandArgument { Conditions conditions = scope.getClass().getAnnotation(Conditions.class); - //noinspection SimplifiableIfStatement - if (!validateConditions(conditions, operationContext)) { - return false; + validateConditions(conditions, operationContext); + + if (scope.parentCommand != null) { + validateConditions(scope.parentCommand, operationContext); } - return scope.parentCommand == null || validateConditions(scope.parentCommand, operationContext); } - private boolean validateConditions(Conditions condAnno, CommandOperationContext context) { + private void validateConditions(Conditions condAnno, CommandOperationContext context) throws InvalidCommandArgument { if (condAnno == null) { - return true; + return; } - //noinspection unchecked - CC conditionContext = (CC) this.manager.createConditionContext(context, condAnno); - String conditions = this.manager.getCommandReplacements().replace(condAnno.value()); - for (String cond : ACFPatterns.PIPE.split(conditions)) { - String[] split = ACFPatterns.EQUALS.split(cond, 2); - Condition condition = this.conditions.get(split[0].toLowerCase()); + String conditions = this.manager.getCommandReplacements().replace(condAnno.value()); + CommandIssuer issuer = context.getCommandIssuer(); + for (String cond : ACFPatterns.PIPE.split(conditions)) { + String[] split = ACFPatterns.COLON.split(cond, 2); + String id = split[0].toLowerCase(); + Condition condition = this.conditions.get(id); + if (condition == null) { + RegisteredCommand cmd = context.getRegisteredCommand(); + this.manager.log(LogLevel.ERROR, "Could not find command condition " + id + " for " + cmd.method.getName()); + continue; + } + + String config = split.length == 2 ? split[1] : null; + //noinspection unchecked + CC conditionContext = (CC) this.manager.createConditionContext(issuer, config); + //noinspection unchecked if (!condition.validateCondition(conditionContext)) { - return false; + return; } } - - return true; } - private boolean validateConditions(Conditions condAnno, CommandOperationContext context, CEC execContext) { + private void validateConditions(Conditions condAnno, CEC execContext, Object value) throws InvalidCommandArgument { if (condAnno == null) { - return true; + return; } - //noinspection unchecked - ParameterConditionContext conditionContext = this.manager.createConditionContext(context, execContext, condAnno); String conditions = this.manager.getCommandReplacements().replace(condAnno.value()); + I issuer = execContext.getIssuer(); for (String cond : ACFPatterns.PIPE.split(conditions)) { - String[] split = ACFPatterns.EQUALS.split(cond, 2); + String[] split = ACFPatterns.COLON.split(cond, 2); ParameterCondition condition; - Class cls = execContext.getParam().getClass(); + Class cls = execContext.getParam().getType(); String id = split[0].toLowerCase(); do { condition = this.paramConditions.get(cls, id); @@ -119,19 +123,28 @@ public class CommandConditions < } } while (cls != null); + + if (condition == null) { + RegisteredCommand cmd = execContext.getCmd(); + this.manager.log(LogLevel.ERROR, "Could not find command condition " + id + " for " + cmd.method.getName() + "::" +execContext.getParam().getName()); + continue; + } + String config = split.length == 2 ? split[1] : null; //noinspection unchecked - if (condition != null && !condition.validateCondition(conditionContext)) { - return false; + CC conditionContext = (CC) this.manager.createConditionContext(issuer, config); + + //noinspection unchecked + if (!condition.validateCondition(conditionContext, execContext, value)) { + return; } } - - return true; } - interface Condition { - boolean validateCondition(CC context); + public interface Condition { + boolean validateCondition(ConditionContext context) throws InvalidCommandArgument; } - interface ParameterCondition { - boolean validateCondition(PCC context); + + public interface ParameterCondition { + boolean validateCondition(ConditionContext context, CEC execContext, P value) throws InvalidCommandArgument; } } diff --git a/core/src/main/java/co/aikar/commands/CommandManager.java b/core/src/main/java/co/aikar/commands/CommandManager.java index d91bfb4b..9547c208 100644 --- a/core/src/main/java/co/aikar/commands/CommandManager.java +++ b/core/src/main/java/co/aikar/commands/CommandManager.java @@ -47,9 +47,7 @@ public abstract class CommandManager < FT, MF extends MessageFormatter, CEC extends CommandExecutionContext, - CCC extends CommandCompletionContext, - CC extends ConditionContext, - PCC extends ParameterConditionContext + CC extends ConditionContext > { /** @@ -65,6 +63,7 @@ public abstract class CommandManager < }); protected Map rootCommands = new HashMap<>(); protected final CommandReplacements replacements = new CommandReplacements(this); + protected final CommandConditions conditions = new CommandConditions<>(this); protected ExceptionHandler defaultExceptionHandler = null; protected boolean usePerIssuerLocale = false; @@ -118,6 +117,10 @@ public abstract class CommandManager < this.defaultFormatter = defaultFormatter; } + public CommandConditions getCommandConditions() { + return conditions; + } + /** * Gets the command contexts manager * @return Command Contexts @@ -205,14 +208,10 @@ public abstract class CommandManager < usePerIssuerLocale = setting; return old; } - public ConditionContext createConditionContext(CommandOperationContext context, Conditions conditions) { - //noinspection unchecked - return new ConditionContext<>(context.getRegisteredCommand(), context.getCommandIssuer(), conditions); - } - public

ParameterConditionContext createConditionContext(CommandOperationContext context, CEC execContext, Conditions conditions) { + public ConditionContext createConditionContext(CommandIssuer issuer, String config) { //noinspection unchecked - return new ParameterConditionContext(context.getRegisteredCommand(), (I) context.getCommandIssuer(), execContext, conditions); + return new ConditionContext(issuer, config); } public abstract CommandExecutionContext createCommandContext(RegisteredCommand command, Parameter parameter, CommandIssuer sender, List args, int i, Map passedArgs); @@ -391,4 +390,8 @@ public abstract class CommandManager < throw new IllegalStateException("Using an unstable API that has not been enabled ( " + api + "). See https://acfunstable.emc.gs"); } } + + boolean hasUnstableAPI(String api) { + return unstableAPIs.contains(api); + } } diff --git a/core/src/main/java/co/aikar/commands/ConditionContext.java b/core/src/main/java/co/aikar/commands/ConditionContext.java index bc6ab02c..0c2bda31 100644 --- a/core/src/main/java/co/aikar/commands/ConditionContext.java +++ b/core/src/main/java/co/aikar/commands/ConditionContext.java @@ -23,42 +23,45 @@ package co.aikar.commands; -import co.aikar.commands.annotation.Conditions; import com.google.common.collect.Maps; import java.util.Map; public class ConditionContext { - private final RegisteredCommand cmd; private final I issuer; - private final Conditions condAnno; - private final Map flags; + private final String config; + private final Map configs; - ConditionContext(RegisteredCommand cmd, I issuer, Conditions condAnno) { - this.cmd = cmd; + ConditionContext(I issuer, String config) { this.issuer = issuer; - this.condAnno = condAnno; - this.flags = Maps.newHashMap(); - for (String s : ACFPatterns.COMMA.split(cmd.scope.manager.getCommandReplacements().replace(condAnno.value()))) { - String[] v = ACFPatterns.EQUALS.split(s, 2); - this.flags.put(v[0], v.length > 1 ? v[1] : null); + this.config = config; + this.configs = Maps.newHashMap(); + if (config != null) { + for (String s : ACFPatterns.COMMA.split(config)) { + String[] v = ACFPatterns.EQUALS.split(s, 2); + this.configs.put(v[0], v.length > 1 ? v[1] : null); + } } } + public I getIssuer() { return issuer; } - public boolean hasFlag(String flag) { - return flags.containsKey(flag); + public String getConfig() { + return this.config; + } + public boolean hasConfig(String flag) { + return configs.containsKey(flag); } - public String getFlagValue(String flag, String def) { - return flags.getOrDefault(flag, def); + public String getConfigValue(String flag, String def) { + return configs.getOrDefault(flag, def); } - public Integer getFlagValue(String flag, Integer def) { - return ACFUtil.parseInt(this.flags.get(flag), def); + public Integer getConfigValue(String flag, Integer def) { + return ACFUtil.parseInt(this.configs.get(flag), def); } } diff --git a/bukkit/src/main/java/co/aikar/commands/BukkitParameterConditionContext.java b/core/src/main/java/co/aikar/commands/ConditionFailedException.java similarity index 64% rename from bukkit/src/main/java/co/aikar/commands/BukkitParameterConditionContext.java rename to core/src/main/java/co/aikar/commands/ConditionFailedException.java index 070ae7bd..290e1729 100644 --- a/bukkit/src/main/java/co/aikar/commands/BukkitParameterConditionContext.java +++ b/core/src/main/java/co/aikar/commands/ConditionFailedException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017 Daniel Ennis (Aikar) - MIT License + * Copyright (c) 2016-2018 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 @@ -23,10 +23,23 @@ package co.aikar.commands; -import co.aikar.commands.annotation.Conditions; +import co.aikar.locales.MessageKey; +import co.aikar.locales.MessageKeyProvider; -public class BukkitParameterConditionContext

extends ParameterConditionContext { - BukkitParameterConditionContext(RegisteredCommand cmd, BukkitCommandIssuer issuer, BukkitCommandExecutionContext execContext, Conditions conditions) { - super(cmd, issuer, execContext, conditions); +public class ConditionFailedException extends InvalidCommandArgument { + public ConditionFailedException() { + super(false); + } + + public ConditionFailedException(MessageKeyProvider key, String... replacements) { + super(key, false, replacements); + } + + public ConditionFailedException(MessageKey key, String... replacements) { + super(key, false, replacements); + } + + public ConditionFailedException(String message) { + super(message, false); } } diff --git a/core/src/main/java/co/aikar/commands/InvalidCommandArgument.java b/core/src/main/java/co/aikar/commands/InvalidCommandArgument.java index e6cf2060..46f521ee 100644 --- a/core/src/main/java/co/aikar/commands/InvalidCommandArgument.java +++ b/core/src/main/java/co/aikar/commands/InvalidCommandArgument.java @@ -53,19 +53,10 @@ public class InvalidCommandArgument extends Exception { this.replacements = replacements; } - /** - * Please move to a MessageKey - * @deprecated - */ - @Deprecated public InvalidCommandArgument(String message) { this(message, true); } - /** - * Please move to a MessageKey - * @deprecated - */ - @Deprecated + public InvalidCommandArgument(String message, boolean showSyntax) { super(message, null, false, false); this.showSyntax = showSyntax; diff --git a/core/src/main/java/co/aikar/commands/Locales.java b/core/src/main/java/co/aikar/commands/Locales.java index e7e64687..d0651e33 100644 --- a/core/src/main/java/co/aikar/commands/Locales.java +++ b/core/src/main/java/co/aikar/commands/Locales.java @@ -34,6 +34,7 @@ import org.jetbrains.annotations.NotNull; import java.util.HashMap; import java.util.Locale; import java.util.Map; +import java.util.Set; import java.util.regex.Matcher; @SuppressWarnings("WeakerAccess") @@ -72,7 +73,7 @@ public class Locales { public static final Locale WELSH = new Locale("cy"); - private final CommandManager manager; + private final CommandManager manager; private final LocaleManager localeManager; private final SetMultimap loadedBundles = HashMultimap.create(); @@ -97,7 +98,9 @@ public class Locales { * Looks for all previously loaded bundles, and if any new Supported Languages have been added, load them. */ public void loadMissingBundles() { - for (Locale locale : manager.getSupportedLanguages()) { + //noinspection unchecked + Set supportedLanguages = manager.getSupportedLanguages(); + for (Locale locale : supportedLanguages) { for (String bundleName : Sets.newHashSet(loadedBundles.keys())) { addMessageBundle(bundleName, locale); } @@ -106,7 +109,9 @@ public class Locales { public void addMessageBundles(String... bundleNames) { for (String bundleName : bundleNames) { - for (Locale locale : manager.getSupportedLanguages()) { + //noinspection unchecked + Set supportedLanguages = manager.getSupportedLanguages(); + for (Locale locale : supportedLanguages) { addMessageBundle(bundleName, locale); } } diff --git a/core/src/main/java/co/aikar/commands/ParameterConditionContext.java b/core/src/main/java/co/aikar/commands/ParameterConditionContext.java deleted file mode 100644 index 7b754e29..00000000 --- a/core/src/main/java/co/aikar/commands/ParameterConditionContext.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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.Conditions; - -import java.lang.annotation.Annotation; -import java.util.List; -import java.util.Map; - -public class ParameterConditionContext extends ConditionContext { - - private final CEC execContext; - - ParameterConditionContext(RegisteredCommand cmd, I issuer, CEC execContext, Conditions conditions) { - super(cmd, issuer, conditions); - - this.execContext = execContext; - } - - public boolean isLastArg() { - return execContext.isLastArg(); - } - - public int getNumParams() { - return execContext.getNumParams(); - } - - public boolean canOverridePlayerContext() { - return execContext.canOverridePlayerContext(); - } - - public Object getResolvedArg(String arg) { - return execContext.getResolvedArg(arg); - } - - public Object getResolvedArg(Class[] classes) { - return execContext.getResolvedArg(classes); - } - - public Object getResolvedArg(String key, Class[] classes) { - return execContext.getResolvedArg(key, classes); - } - - public boolean isOptional() { - return execContext.isOptional(); - } - - public Annotation getAnnotation(Class cls) { - return execContext.getAnnotation(cls); - } - - public boolean hasAnnotation(Class cls) { - return execContext.hasAnnotation(cls); - } - - public List getArgs() { - return execContext.getArgs(); - } - - public int getIndex() { - return execContext.getIndex(); - } - - public Map getPassedArgs() { - return execContext.getPassedArgs(); - } - - public String joinArgs() { - return execContext.joinArgs(); - } - - public String joinArgs(String sep) { - return execContext.joinArgs(sep); - } -} diff --git a/core/src/main/java/co/aikar/commands/RegisteredCommand.java b/core/src/main/java/co/aikar/commands/RegisteredCommand.java index cb8d5baf..a8ac0cf9 100644 --- a/core/src/main/java/co/aikar/commands/RegisteredCommand.java +++ b/core/src/main/java/co/aikar/commands/RegisteredCommand.java @@ -52,7 +52,7 @@ import java.util.Set; import java.util.stream.Collectors; @SuppressWarnings("WeakerAccess") -public class RegisteredCommand > { +public class RegisteredCommand > { final BaseCommand scope; final String command; final Method method; @@ -67,7 +67,7 @@ public class RegisteredCommand registeredSubcommands = new ArrayList<>(); - private final CommandManager manager; + private final CommandManager manager; RegisteredCommand(BaseCommand scope, String command, Method method, String prefSubCommand) { this.scope = scope; @@ -89,6 +89,7 @@ public class RegisteredCommand args) { + void invoke(CommandIssuer sender, List args, CommandOperationContext context) { if (!scope.canExecute(sender, this)) { return; } preCommand(); try { + this.manager.conditions.validateConditions(context); Map passedArgs = resolveContexts(sender, args); if (passedArgs == null) return; @@ -220,6 +222,8 @@ public class RegisteredCommand possible = Sets.newHashSet(); for (String s : split) { + //noinspection unchecked List check = this.manager.getCommandCompletions().getCompletionValues(this, sender, s, origArgs, opContext.isAsync()); if (!check.isEmpty()) { possible.addAll(check.stream().map(String::toLowerCase).collect(Collectors.toList())); @@ -248,7 +253,10 @@ public class RegisteredCommand { + if (value == null) { + return true; + } + if (c.hasConfig("min") && c.getConfigValue("min", 0) > value.getValue()) { + throw new ConditionFailedException("Min value must be " + c.getConfigValue("min", 0)); + } + if (c.hasConfig("max") && c.getConfigValue("max", 3) < value.getValue()) { + throw new ConditionFailedException("Max value must be " + c.getConfigValue("max", 3)); + } + return true; + }); + + // 6: Register your commands - This first command demonstrates adding an exception handler to that command commandManager.registerCommand(new SomeCommand().setExceptionHandler((command, registeredCommand, sender, args, t) -> { sender.sendMessage(MessageType.ERROR, MessageKeys.ERROR_GENERIC_LOGGED); return true; // mark as handeled, default message will not be send to sender })); - // 5: Register an additional command. This one happens to share the same CommandAlias as the previous command + // 7: Register an additional command. This one happens to share the same CommandAlias as the previous command // This means it simply registers additional sub commands under the same command, but organized into separate // Classes (Maybe different permission sets) commandManager.registerCommand(new SomeCommand_ExtraSubs()); - // 6: Register default exception handler for any command that doesn't supply its own + // 8: Register default exception handler for any command that doesn't supply its own commandManager.setDefaultExceptionHandler((command, registeredCommand, sender, args, t) -> { getLogger().warning("Error occured while executing command " + command.getName()); return false; // mark as unhandeled, sender will see default message diff --git a/sponge/src/main/java/co/aikar/commands/SpongeCommandCompletionContext.java b/sponge/src/main/java/co/aikar/commands/SpongeCommandCompletionContext.java index 5b75b474..b8e825f2 100644 --- a/sponge/src/main/java/co/aikar/commands/SpongeCommandCompletionContext.java +++ b/sponge/src/main/java/co/aikar/commands/SpongeCommandCompletionContext.java @@ -24,15 +24,20 @@ package co.aikar.commands; import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.entity.living.player.Player; @SuppressWarnings("WeakerAccess") -public class SpongeCommandCompletionContext extends CommandCompletionContext { +public class SpongeCommandCompletionContext extends CommandCompletionContext { - SpongeCommandCompletionContext(final RegisteredCommand command, final CommandIssuer issuer, final String input, final String config, final String[] args) { + SpongeCommandCompletionContext(final RegisteredCommand command, final SpongeCommandIssuer issuer, final String input, final String config, final String[] args) { super(command, issuer, input, config, args); } public CommandSource getSource() { return this.issuer.getIssuer(); } + + public Player getPlayer() { + return this.issuer.getPlayer(); + } } diff --git a/sponge/src/main/java/co/aikar/commands/SpongeCommandExecutionContext.java b/sponge/src/main/java/co/aikar/commands/SpongeCommandExecutionContext.java index 700e6996..9226df83 100644 --- a/sponge/src/main/java/co/aikar/commands/SpongeCommandExecutionContext.java +++ b/sponge/src/main/java/co/aikar/commands/SpongeCommandExecutionContext.java @@ -24,6 +24,7 @@ package co.aikar.commands; import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.entity.living.player.Player; import java.lang.reflect.Parameter; import java.util.List; @@ -39,4 +40,8 @@ public class SpongeCommandExecutionContext extends CommandExecutionContext T getIssuer() { - //noinspection unchecked - return (T) this.source; + public CommandSource getIssuer() { + return this.source; + } + + public Player getPlayer() { + return isPlayer() ? (Player) source : null; } @Override diff --git a/sponge/src/main/java/co/aikar/commands/SpongeCommandManager.java b/sponge/src/main/java/co/aikar/commands/SpongeCommandManager.java index 4376e809..ce51a36d 100644 --- a/sponge/src/main/java/co/aikar/commands/SpongeCommandManager.java +++ b/sponge/src/main/java/co/aikar/commands/SpongeCommandManager.java @@ -23,7 +23,6 @@ package co.aikar.commands; -import co.aikar.commands.annotation.Conditions; import co.aikar.commands.apachecommonslang.ApacheCommonsExceptionUtil; import co.aikar.timings.Timing; import co.aikar.timings.Timings; @@ -47,9 +46,7 @@ public class SpongeCommandManager extends CommandManager< TextColor, SpongeMessageFormatter, SpongeCommandExecutionContext, - SpongeCommandCompletionContext, - SpongeConditionContext, - SpongeParameterConditionContext + SpongeConditionContext > { protected final PluginContainer plugin; @@ -150,7 +147,7 @@ public class SpongeCommandManager extends CommandManager< @Override public CommandCompletionContext createCompletionContext(RegisteredCommand command, CommandIssuer sender, String input, String config, String[] args) { - return new SpongeCommandCompletionContext(command, sender, input, config, args); + return new SpongeCommandCompletionContext(command, (SpongeCommandIssuer) sender, input, config, args); } @Override @@ -192,15 +189,9 @@ public class SpongeCommandManager extends CommandManager< ); } - @Override - public SpongeConditionContext createConditionContext(CommandOperationContext context, Conditions conditions) { - return new SpongeConditionContext(context.getRegisteredCommand(), (SpongeCommandIssuer) context.getCommandIssuer(), conditions); - } - - @Override - public

SpongeParameterConditionContext createConditionContext(CommandOperationContext context, SpongeCommandExecutionContext execContext, Conditions conditions) { - return new SpongeParameterConditionContext

(context.getRegisteredCommand(), (SpongeCommandIssuer) context.getCommandIssuer(), execContext, conditions); + public SpongeConditionContext createConditionContext(CommandIssuer issuer, String config) { + return new SpongeConditionContext((SpongeCommandIssuer) issuer, config); } } diff --git a/sponge/src/main/java/co/aikar/commands/SpongeConditionContext.java b/sponge/src/main/java/co/aikar/commands/SpongeConditionContext.java index c06658bf..2257c663 100644 --- a/sponge/src/main/java/co/aikar/commands/SpongeConditionContext.java +++ b/sponge/src/main/java/co/aikar/commands/SpongeConditionContext.java @@ -1,9 +1,19 @@ package co.aikar.commands; -import co.aikar.commands.annotation.Conditions; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.entity.living.player.Player; public class SpongeConditionContext extends ConditionContext { - SpongeConditionContext(RegisteredCommand cmd, SpongeCommandIssuer issuer, Conditions condAnno) { - super(cmd, issuer, condAnno); + SpongeConditionContext(SpongeCommandIssuer issuer, String config) { + super(issuer, config); + } + + + public CommandSource getSource() { + return getIssuer().getIssuer(); + } + + public Player getPlayer() { + return getIssuer().getPlayer(); } } diff --git a/sponge/src/main/java/co/aikar/commands/SpongeParameterConditionContext.java b/sponge/src/main/java/co/aikar/commands/SpongeParameterConditionContext.java deleted file mode 100644 index 2dcac52e..00000000 --- a/sponge/src/main/java/co/aikar/commands/SpongeParameterConditionContext.java +++ /dev/null @@ -1,9 +0,0 @@ -package co.aikar.commands; - -import co.aikar.commands.annotation.Conditions; - -public class SpongeParameterConditionContext

extends ParameterConditionContext { - SpongeParameterConditionContext(RegisteredCommand cmd, SpongeCommandIssuer issuer, SpongeCommandExecutionContext execContext, Conditions conditions) { - super(cmd, issuer, execContext, conditions); - } -}