This adds basic support for meta-annotations for commands and
parameters and allows users to create their own custom annotations
combining certain existing annotations and values. For example, a user
can now define their own `CustomAnnotation` which combines a
condition and a flag:
```java
@Conditions("conditionname:confitionconfig")
@Flags("flagconfig=flagvalue")
public @interface CustomAnnotation {}
```
(Necessary `@Retention` and `@Target` ignore for brevity)
And use it just like they would normally.
This works by recursively going through the annotations, instead of
just looking at the root level. The reason most existing annotations
had to be touched is for them to be allowed on other annotations as
most of them were restricted to method or fields.
Currently there's no limit on nesting because if the user wants to
nest it to obscure levels - so be it. We could decide to limit this at
some point to prevent users from shooting themselves in the foot if
that's necessary.
`@Dependency` and was specifically ignored as I don't think it makes
sense for that to be supported in this use case.
Relates to: #89
Fixes a bug introduced by PR 200. The bug related to the Values annotation which uses this getCompletionValues method also.
This is definitely not the propersolution. The underlying issue is
related to the logic calling `args` which is the original argument
array. And it should not be using arguments which have been resolved in
a previous parameter.
I was not able to find a quick/simple way to accommodate that issue.
This PR adds support for exceptions in CompletableFuture in Commands.
Usage: Just return a CompletableFuture. ACF will catch the exceptionally stuff.
```java
public CompletableFuture<Void> futuredExecution(Player player) {
return CompletableFuture.failedFuture(new InvalidCommandArgument("Failed in future.", false));
}
```
I added support for multi word tab completion.
Current problem:
the replacement "example" contains completions with whitespaces
```java
@CommandCompletion("@example")
public void test(Player player, String takesTheRest) {...}
```
"takesTheRest" takes all the whole rest howewer the tab completion only supports one word.
I don't use the ACFUtils much and maybe there are some ugly checks, feel free to refactor.
…ions by Optional annotation
In the past we could not handle a permission in relation to the presence of an optional argument, it forced us to manage it in the body of the command, and could be repetitive and boring, note that it also works with the annotation Default
now supports splitting commands over multiple BaseCommands better
should now only match probable @Default handlers, so @CatchUnknown
can still work in obviously wrong scenarios.
@HelpCommand no longer implies @Default as @CatchUnknown will pick it up
Currently there has to be the `@CatchUnknown` method in the same class as the `@Default` method.
Without finding any methods for handling unknown commands the default fallback method is the first registered or the class with `@Default` annotated method inside.
Maybe the solution to throw an exception for an unknown command is better.
The BaseCommand tries to execute the command context and if it's not possible it will throw an UnknownCommandException or smth like that.
I want to use own annotations for help implementations (link, tooltips, short description etc.)
I can't access the method directly for the annotations, please add the getter ;)
Currently the BaseCommand#hasPermission method doesn't actually check if the user has all the required permissions to execute a command, resulting in the following issue:
If user has permission permission.a they can execute:
/example
/example test
/example sub
/example sub testsub
Which is proper but if the user doesn't have permission.a they can only execute:
/example sub testsub
Example code:
```java
@CommandAlias("example")
@CommandPermission("permission.a")
public class ExampleCommand extends BaseCommand {
@HelpCommand
public void help(CommandHelp help) {
help.showHelp();
}
@Subcommand("test")
public void test(CommandSender sender) {
sender.sendMessage("has permission to test?");
}
@Subcommand("sub")
public class ExampleBCommand extends BaseCommand {
@Subcommand("testsub")
public void testSub(CommandSender sender) {
sender.sendMessage("has permission to testSub?");
}
}
@Subcommand("othersub")
@CommandPermission("permission.b")
public class ExampleCCommand extends BaseCommand {
@Subcommand("othersub")
public void otherSub(CommandSender sender) {
sender.sendMessage("has permission to otherSub?");
}
}
}
```
ACF's permission tree can go more complex where a single root command
may have multiple dependent perm nodes.
So essentially ACF does not assign permission nodes to root in bukkit
and the such in a reasonable manner.
With this commit, we try to identify a single unique permission node,
and assign that permission node as the node to use where applicable.
In Bukkit/Sponge, we implement testPermission instead, which does a smarter
look up of all potential commands that root command might execute for the
given issuer, and if they have permission to any of them, then pass as true.
This is much more accurate, so if the issuer has access to no subcommand
then the root command should not be revealed anymore in Bukkit or Sponge.
In bungee, we are best guess at the unique perm node, and if there is
any ambiguity, it will be null and seen by everyone (but still enforces
permission checks)