diff --git a/core/src/main/java/co/aikar/commands/BaseCommand.java b/core/src/main/java/co/aikar/commands/BaseCommand.java index 30410e71..883f1e03 100644 --- a/core/src/main/java/co/aikar/commands/BaseCommand.java +++ b/core/src/main/java/co/aikar/commands/BaseCommand.java @@ -788,7 +788,7 @@ public abstract class BaseCommand { } public boolean hasPermission(CommandIssuer issuer) { - return getRequiredPermissions().isEmpty() || getRequiredPermissions().stream().allMatch(permission -> manager.hasPermission(issuer, permission)); + return this.manager.hasPermission(issuer, getRequiredPermissions()); } public Set getRequiredPermissions() { diff --git a/core/src/main/java/co/aikar/commands/CommandExecutionContext.java b/core/src/main/java/co/aikar/commands/CommandExecutionContext.java index 620a20b2..bc0f4008 100644 --- a/core/src/main/java/co/aikar/commands/CommandExecutionContext.java +++ b/core/src/main/java/co/aikar/commands/CommandExecutionContext.java @@ -29,7 +29,7 @@ import java.util.List; import java.util.Map; import java.util.Set; -@SuppressWarnings({"WeakerAccess"}) +@SuppressWarnings({"WeakerAccess", "unchecked"}) public class CommandExecutionContext { private final RegisteredCommand cmd; private final CommandParameter param; @@ -101,7 +101,6 @@ public class CommandExecutionContext clazz : classes) { if (clazz.isInstance(o)) { - //noinspection unchecked return (T) o; } } @@ -109,8 +108,8 @@ public class CommandExecutionContext getPermissions() { - return param.getPermissions(); + public Set getParameterPermissions() { + return param.getRequiredPermissions(); } public boolean isOptional() { diff --git a/core/src/main/java/co/aikar/commands/CommandManager.java b/core/src/main/java/co/aikar/commands/CommandManager.java index f82b0cb8..9f191420 100644 --- a/core/src/main/java/co/aikar/commands/CommandManager.java +++ b/core/src/main/java/co/aikar/commands/CommandManager.java @@ -48,14 +48,14 @@ import java.util.concurrent.ConcurrentHashMap; @SuppressWarnings("WeakerAccess") -public abstract class CommandManager < +public abstract class CommandManager< IT, I extends CommandIssuer, FT, MF extends MessageFormatter, CEC extends CommandExecutionContext, CC extends ConditionContext - > { + > { /** * This is a stack incase a command calls a command @@ -113,7 +113,7 @@ public abstract class CommandManager < public void setFormat(MessageType type, FT... colors) { MF format = getFormat(type); for (int i = 1; i <= colors.length; i++) { - format.setColor(i, colors[i-1]); + format.setColor(i, colors[i - 1]); } } @@ -136,17 +136,23 @@ public abstract class CommandManager < /** * Gets the command contexts manager + * * @return Command Contexts */ public abstract CommandContexts getCommandContexts(); /** * Gets the command completions manager + * * @return Command Completions */ public abstract CommandCompletions getCommandCompletions(); - /** @deprecated Unstable API */ @Deprecated @UnstableAPI + /** + * @deprecated Unstable API + */ + @Deprecated + @UnstableAPI public CommandHelp generateCommandHelp(@NotNull String command) { verifyUnstableAPI("help"); CommandOperationContext context = getCurrentCommandOperationContext(); @@ -156,13 +162,21 @@ public abstract class CommandManager < return generateCommandHelp(context.getCommandIssuer(), command); } - /** @deprecated Unstable API */ @Deprecated @UnstableAPI + /** + * @deprecated Unstable API + */ + @Deprecated + @UnstableAPI public CommandHelp generateCommandHelp(CommandIssuer issuer, @NotNull String command) { verifyUnstableAPI("help"); return generateCommandHelp(issuer, obtainRootCommand(command)); } - /** @deprecated Unstable API */ @Deprecated @UnstableAPI + /** + * @deprecated Unstable API + */ + @Deprecated + @UnstableAPI public CommandHelp generateCommandHelp() { verifyUnstableAPI("help"); CommandOperationContext context = getCurrentCommandOperationContext(); @@ -173,29 +187,50 @@ public abstract class CommandManager < return generateCommandHelp(context.getCommandIssuer(), this.obtainRootCommand(commandLabel)); } - /** @deprecated Unstable API */ @Deprecated @UnstableAPI + /** + * @deprecated Unstable API + */ + @Deprecated + @UnstableAPI public CommandHelp generateCommandHelp(CommandIssuer issuer, RootCommand rootCommand) { verifyUnstableAPI("help"); return new CommandHelp(this, rootCommand, issuer); } - /** @deprecated Unstable API */ @Deprecated @UnstableAPI + /** + * @deprecated Unstable API + */ + @Deprecated + @UnstableAPI public int getDefaultHelpPerPage() { verifyUnstableAPI("help"); return defaultHelpPerPage; } - /** @deprecated Unstable API */ @Deprecated @UnstableAPI + /** + * @deprecated Unstable API + */ + @Deprecated + @UnstableAPI public void setDefaultHelpPerPage(int defaultHelpPerPage) { verifyUnstableAPI("help"); this.defaultHelpPerPage = defaultHelpPerPage; } - /** @deprecated Unstable API */ @Deprecated @UnstableAPI + + /** + * @deprecated Unstable API + */ + @Deprecated + @UnstableAPI public void setHelpFormatter(CommandHelpFormatter helpFormatter) { this.helpFormatter = helpFormatter; } - /** @deprecated Unstable API */ @Deprecated @UnstableAPI + /** + * @deprecated Unstable API + */ + @Deprecated + @UnstableAPI public CommandHelpFormatter getHelpFormatter() { return helpFormatter; } @@ -211,7 +246,9 @@ public abstract class CommandManager < * @return boolean */ public abstract void registerCommand(BaseCommand command); + public abstract boolean hasRegisteredCommands(); + public abstract boolean isCommandIssuer(Class type); // TODO: Change this to IT if we make a breaking change @@ -221,6 +258,7 @@ public abstract class CommandManager < /** * Returns a Locales Manager to add and modify language tables for your commands. + * * @return */ public abstract Locales getLocales(); @@ -253,16 +291,26 @@ public abstract class CommandManager < /** * Lets you add custom string replacements that can be applied to annotation values, * to reduce duplication/repetition of common values such as permission nodes and command prefixes. - * + *

* Any replacement registered starts with a % - * + *

* So for ex @CommandPermission("%staff") + * * @return Replacements Manager */ public CommandReplacements getCommandReplacements() { return replacements; } + public boolean hasPermission(CommandIssuer issuer, Set permissions) { + for (String permission : permissions) { + if (!hasPermission(issuer, permission)) { + return false; + } + } + return true; + } + public boolean hasPermission(CommandIssuer issuer, String permission) { if (permission == null || permission.isEmpty()) { return true; @@ -422,6 +470,7 @@ public abstract class CommandManager < /** * Gets a list of all currently supported languages for this manager. * These locales will be automatically loaded from + * * @return */ public Set getSupportedLanguages() { @@ -444,11 +493,11 @@ public abstract class CommandManager < * The command manager will attempt to inject all fields in a command class that are annotated with * {@link co.aikar.commands.annotation.Dependency} with the provided instance. * - * @param clazz the class the injector should look for when injecting + * @param clazz the class the injector should look for when injecting * @param instance the instance of the class that should be injected * @throws IllegalStateException when there is already an instance for the provided class registered */ - public void registerDependency(Class clazz, T instance){ + public void registerDependency(Class clazz, T instance) { registerDependency(clazz, clazz.getName(), instance); } @@ -457,12 +506,12 @@ public abstract class CommandManager < * The command manager will attempt to inject all fields in a command class that are annotated with * {@link co.aikar.commands.annotation.Dependency} with the provided instance. * - * @param clazz the class the injector should look for when injecting - * @param key the key which needs to be present if that + * @param clazz the class the injector should look for when injecting + * @param key the key which needs to be present if that * @param instance the instance of the class that should be injected * @throws IllegalStateException when there is already an instance for the provided class registered */ - public void registerDependency(Class clazz, String key, T instance){ + public void registerDependency(Class clazz, String key, T instance) { if (dependencies.containsKey(clazz, key)) { throw new IllegalStateException("There is already an instance of " + clazz.getName() + " with the key " + key + " registered!"); } @@ -514,6 +563,7 @@ public abstract class CommandManager < public void enableUnstableAPI(String api) { unstableAPIs.add(api); } + void verifyUnstableAPI(String api) { if (!unstableAPIs.contains(api)) { throw new IllegalStateException("Using an unstable API that has not been enabled ( " + api + "). See https://acfunstable.emc.gs"); diff --git a/core/src/main/java/co/aikar/commands/CommandParameter.java b/core/src/main/java/co/aikar/commands/CommandParameter.java index 60e61e91..ba4f7ec5 100644 --- a/core/src/main/java/co/aikar/commands/CommandParameter.java +++ b/core/src/main/java/co/aikar/commands/CommandParameter.java @@ -272,7 +272,7 @@ public class CommandParameter getPermissions() { + public Set getRequiredPermissions() { return permissions; } } diff --git a/core/src/main/java/co/aikar/commands/MessageKeys.java b/core/src/main/java/co/aikar/commands/MessageKeys.java index 04fc55bb..9e0ce32f 100644 --- a/core/src/main/java/co/aikar/commands/MessageKeys.java +++ b/core/src/main/java/co/aikar/commands/MessageKeys.java @@ -32,6 +32,7 @@ import co.aikar.locales.MessageKeyProvider; @SuppressWarnings("WeakerAccess") public enum MessageKeys implements MessageKeyProvider { PERMISSION_DENIED, + PERMISSION_DENIED_PARAMETER, ERROR_GENERIC_LOGGED, UNKNOWN_COMMAND, INVALID_SYNTAX, @@ -58,6 +59,7 @@ public enum MessageKeys implements MessageKeyProvider { ; private final MessageKey key = MessageKey.of("acf-core." + this.name().toLowerCase()); + public MessageKey getMessageKey() { return key; } diff --git a/core/src/main/java/co/aikar/commands/RegisteredCommand.java b/core/src/main/java/co/aikar/commands/RegisteredCommand.java index 7fc2f56c..48007c0a 100644 --- a/core/src/main/java/co/aikar/commands/RegisteredCommand.java +++ b/core/src/main/java/co/aikar/commands/RegisteredCommand.java @@ -227,10 +227,15 @@ public class RegisteredCommand parameterPermissions = parameter.getRequiredPermissions(); if (args.isEmpty() && !(isLast && type == String[].class)) { if (allowOptional && parameter.getDefaultValue() != null) { args.add(parameter.getDefaultValue()); } else if (allowOptional && parameter.isOptional()) { + if (!this.manager.hasPermission(sender, parameterPermissions)) { + sender.sendMessage(MessageType.ERROR, MessageKeys.PERMISSION_DENIED_PARAMETER, "{param}", parameterName); + throw new InvalidCommandArgument(false); + } Object value = parameter.isOptionalResolver() ? resolver.getContext(context) : null; if (value == null && parameter.getClass().isPrimitive()) { @@ -239,12 +244,16 @@ public class RegisteredCommand parameterPermissions = parameter.getPermissions(); - if (!parameter.isOptionalResolver() && parameterPermissions != null && !parameterPermissions.isEmpty()) { - if (allowOptional && parameter.isOptional()) { - for (String perm : parameterPermissions) { - if (!perm.isEmpty() && !sender.hasPermission(perm)) { - sender.sendMessage(MessageType.ERROR, MessageKeys.PERMISSION_DENIED); - return null; - } - } - } else { - throw new IllegalStateException("Using CommandPermission annotation on parameter that is not optional is useless and you should not do it."); - } - } + Object paramValue = resolver.getContext(context); //noinspection unchecked this.manager.conditions.validateConditions(context, paramValue); @@ -290,10 +286,9 @@ public class RegisteredCommand/help -acf-core.invalid_syntax = Usage: {command} {syntax} -acf-core.error_prefix = Error: {message} -acf-core.error_performing_command = I'm sorry, but there was an error performing this command. -acf-core.info_message = {message} -acf-core.please_specify_one_of = Error: Please specify one of ({valid}). -acf-core.must_be_a_number = Error: {num} must be a number. -acf-core.must_be_min_length = Error: Must be at least {min} characters long. -acf-core.must_be_max_length = Error: Must be at most {max} characters long. -acf-core.please_specify_at_most = Error: Please specify a value at most {max}. -acf-core.please_specify_at_least = Error: Please specify a value at least {min}. -acf-core.not_allowed_on_console = Error: Console may not execute this command. -acf-core.could_not_find_player = Error: Could not find a player by the name: {search} -acf-core.no_command_matched_search = No command matched {search}. -acf-core.help_page_information = - Showing page {page} of {totalpages} ({results} results). -acf-core.help_no_results = Error: No more results. -acf-core.help_header = === Showing help for {commandprefix}{command} === -acf-core.help_format = {command} {parameters} {separator} {description} -acf-core.help_detailed_header = === Showing detailed help for {commandprefix}{command} === -acf-core.help_detailed_command_format = {command} {parameters} {separator} {description} -acf-core.help_detailed_parameter_format = {name}: {description} -acf-core.help_search_header = === Search results for {commandprefix}{command} {search} === +acf-core.permission_denied=I'm sorry, but you do not have permission to perform this command. +acf-core.permission_denied_parameter=I'm sorry, but you do not have permission to perform this command. +acf-core.error_generic_logged=An error occurred. This problem has been logged. Sorry for the inconvenience. +acf-core.unknown_command=Unknown Command, please type /help +acf-core.invalid_syntax=Usage: {command} {syntax} +acf-core.error_prefix=Error: {message} +acf-core.error_performing_command=I'm sorry, but there was an error performing this command. +acf-core.info_message={message} +acf-core.please_specify_one_of=Error: Please specify one of ({valid}). +acf-core.must_be_a_number=Error: {num} must be a number. +acf-core.must_be_min_length=Error: Must be at least {min} characters long. +acf-core.must_be_max_length=Error: Must be at most {max} characters long. +acf-core.please_specify_at_most=Error: Please specify a value at most {max}. +acf-core.please_specify_at_least=Error: Please specify a value at least {min}. +acf-core.not_allowed_on_console=Error: Console may not execute this command. +acf-core.could_not_find_player=Error: Could not find a player by the name: {search} +acf-core.no_command_matched_search=No command matched {search}. +acf-core.help_page_information=- Showing page {page} of {totalpages} ({results} results). +acf-core.help_no_results=Error: No more results. +acf-core.help_header==== Showing help for {commandprefix}{command} === +acf-core.help_format={command} {parameters} {separator} {description} +acf-core.help_detailed_header==== Showing detailed help for {commandprefix}{command} === +acf-core.help_detailed_command_format={command} {parameters} {separator} {description} +acf-core.help_detailed_parameter_format={name}: {description} +acf-core.help_search_header==== Search results for {commandprefix}{command} {search} ===