net.forthecrown.grenadier.annotations.package-info Maven / Gradle / Ivy
Show all versions of grenadier-annotations Show documentation
/**
* Grenadier command annotation library, see below for guides.
*
* The annotation library works by taking in an object with a {@link net.forthecrown.grenadier.annotations.CommandData}
* annotation, tokenizing the {@link net.forthecrown.grenadier.annotations.CommandData#value()}
* and parsing it into an abstract command tree and finally resolving all
* variable references, class field/method references and all other else before
* the command is registered.
*
* This framework makes the creation of commands easier as less boilerplate is
* required and command trees can be created faster.
*
*
Table of contents
*
* - Guide
*
*
* - Syntax Documentation
*
*
*
*
* Guide
* This part will act as a guide on how to use the Grenadier Annotations library.
*
* Creating a basic command
* Let's start with a simple command that just says hello world when it's ran,
* we would do that like so:
*
* @CommandData("""
* name = 'example_command'
* executes = run()
* """)
* public class ExampleCommand {
*
* public void run(CommandContext<CommandSource> context) {
* CommandSource source = context.getSource();
* source.sendMessage("Hello, world");
* }
* }
*
*
* You can then register the command like so:
*
* public class ExamplePlugin extends JavaPlugin {
*
* @Override
* public void onEnable() {
* AnnotatedCommandContext ctx = AnnotatedCommandContext.create();
* ctx.registerCommand(new ExampleCommand());
* }
* }
*
*
* Using variables
*
* Before talking about variables, it must be made clear that there are 2 types
* of variables, local and global. For this example, we'll show global variables
* first.
*
* Variables can be of any type and can be registered like this:
*
* AnnotatedCommandContext ctx = AnnotatedCommandContext.create();
*
* Map<String, Object> variables = ctx.getVariables();
* variables.put("variable_name", "foobar");
*
*
* You can then use variables like so:
*
* name = 'command_name'
*
* literal(@variable_name) {
* executes = methodName()
* }
*
* Variables can be used in lots of places, including in argument names,
* permission fields, as command names and even for the 'executes', 'suggests'
* and 'requires' fields. Make sure to read the Syntax
* documentation section for a full guide on variables and the syntax.
*
* Permission and executes defaults
*
* Default values for both command permissions and 'executes' can be registered
* to avoid typing similar permissions and names over and over again.
*
*
* Permission defaults can be registered like so:
*
* AnnotatedCommandContext ctx = AnnotatedCommandContext.create();
* ctx.setDefaultPermissionFormat("commands.permission.{command}");
*
* The {@code {command}} is a placeholder for the command's name.
*
*
* Execution defaults allow you to set a method name that will be used
* automatically by a command's 'root' node if no other 'executes' value was
* specified.
*
*
* We can set a default execution value like so:
*
* AnnotatedCommandContext ctx = AnnotatedCommandContext.create();
* ctx.setDefaultExecutes("execute");
*
*
* and then use it like so:
*
* // No 'executes' was specified, so it defaults to what we set as the
* // default above
* @CommandData("name = 'example_command'")
* public class ExampleCommand {
*
* // Default execution method
* public void execute(CommandContext<CommandSource> context) {
*
* }
* }
*
*
* Normally, the default execution method will be used if the 'root' node has no
* specified 'executes' value set. This can be changed to make sure the default
* is only used when there's no other command on the root node and when there's
* no child nodes on the command. This can be done like so:
*
*
* AnnotatedCommandContext ctx = AnnotatedCommandContext.create();
* ctx.setDefaultRule(DefaultExecutionRule.IF_NO_CHILDREN);
*
*
* Syntax documentation
* Before any of the general syntax is documented, a couple concepts have to be
* cleared up.
*
* Concepts
*
* Method/Field References
*
* These are values that reference a method or a field within a class. Examples:
*
* // References a field within the command's class
* fieldName
*
* // References a method within the command's class, do not
* // specify any actual parameters here, the '()' are just to
* // tell the parser this is referencing a method instead
* // of a field
* methodName()
*
* Both of the above-shown values can be combined like so:
* field.method().field.method().method()
*
* This does become a bit tricky for the behind-the-scenes evaluator as it'll
* have to trudge through all those field and method references anytime the
* command is executed, suggestions are needed or a requirements check is done.
*
* Variable references
*
* Far simpler than method/field references, these just reference a variable
* registered in {@link net.forthecrown.grenadier.annotations.AnnotatedCommandContext#getVariables()}.
*
* Examples:
* @variableName
*
* The values registered in {@link net.forthecrown.grenadier.annotations.AnnotatedCommandContext#getVariables()}
* are not the only variables commands can use, those are just the 'global'
* variables. Each command can register local variables by declaring a void
* method that takes a {@code Map} as input and annotating it
* with {@link net.forthecrown.grenadier.annotations.VariableInitializer}. This
* will be called before the command is 'compiled' to initialize local
* variables within that command's scope.
*
* Names
* For the most part, and most commonly, names are just quoted strings,
* eg: {@code 'name'}, but there are times when this is not enough. So, whenever
* a name is referenced in this documentation it can be 1 or 3 types of values.
* These are: A) Quoted strings, B) Variable references or C) Field references.
* In the case of C, they reference a field member of the command class.
*
* As an example, we'll use the 3 above name types in declaring a
* {@code literal} node:
*
* // Quoted string name
* literal('name') = methodName()
*
* // Variable reference name
* literal(@name) = methodName()
*
* // Field reference
* literal(argumentName) = methodName()
*
*
* Command node syntax
* The top level of the Annotation input is the 'root' node, it allows users to
* specify details about the base command such as aliases, permission, name and
* description.
*
* Root specific fields
*
* Name
* See Concepts, Names for valid input. Determines the
* name of the command.
*
* Examples:
* name = 'command_name'
* name = @variable
* name = classField
*
*
* Permission
* A quoted string or '@' variable reference. Specifies the permission the
* command uses. Examples:
* permission = 'foo.bar.foobar'
* permission = @permission_variable // Must be a string variable
*
*
* Using the {@link net.forthecrown.grenadier.annotations.AnnotatedCommandContext}
* a default permission can be set that is applied to all commands registered
* using that specific context. See {@link net.forthecrown.grenadier.annotations.AnnotatedCommandContext#setDefaultPermissionFormat(String)}
* for more info.
*
* Description
* A quoted string, specifies the command's description. Example:
*
* description = 'This command does a thing'
*
* See All Nodes, Descriptions for more info on
* descriptions
*
* Aliases
* A special list of either quoted strings, unquoted strings, or variable
* references. These obviously determine the aliases a command uses. Examples:
*
* aliases = alias1 | alias2 | alias3
*
*
* Translate plain
* A {@code true} or {@code false} value that specifies {@link net.forthecrown.grenadier.GrenadierCommand#withPlainTranslation(boolean)},
* defaults to {@code false}, Examples:
*
* translate_plain = true
* translate_plain = false
*
*
* Argument node specific fields
*
* Suggests
* A field/method reference, a variable reference, or a string suggestions list.
* Overrides the argument's ArgumentType suggestions. Examples:
* // Method reference, must take in a CommandContext and SuggestionsBuilder,
* // and return a CompletableFuture<Suggestions>
* suggests = getSomeSuggestions()
*
* suggests = [ 'foo', 'bar', 'foobar' ]
*
* // Variable must be a SuggestionProvider
* suggests = @suggestion_variable
*
* Just like the Executes field, the 'suggests' field
* is flexible when it comes to a method reference. Any of the following method
* parameters are automatically filled by the system:
*
* -
* Any parameter with the {@link net.forthecrown.grenadier.CommandSource}
* type is set to the current command's command source
*
* -
* Any parameter with the {@link com.mojang.brigadier.context.CommandContext}
* type is set to the current command context
*
* -
* Any parameter with the {@link com.mojang.brigadier.suggestion.SuggestionsBuilder}
* type is set to the suggestions builder
*
*
* The rest of the parameters are treated as argument values within the command.
* See the 'Executes' section for more info on that.
*
* Fields used by all nodes
*
* Fields that are accepted by all nodes (root, argument and literal)
*
* Executes
*
* A method/field reference or a variable reference. In the case of variable
* reference, the variable must be a {@link com.mojang.brigadier.Command}.
* Otherwise, in the case of a field reference, the field must point to a
* {@link com.mojang.brigadier.Command} value.
*
*
* In the case the executes value references a method then the method can be
* very flexible. For starters, the method must be a publicly accessible method.
*
* If the method has any {@link com.mojang.brigadier.context.CommandContext}
* parameters, then the context of the command being executed is inputted for
* that parameter. The rest of the parameters are treated as arguments in the
* command itself and are filled by calling {@link com.mojang.brigadier.context.CommandContext#getArgument(String, Class)}
* with the parameter's name and type.
*
* If you're encountering issues with the parameter names disappearing during
* compilation, you can use the {@link net.forthecrown.grenadier.annotations.Argument}
* annotation to preserve it, for example:
*
* public void run(@Argument("argumentName") int value) {
* // Do a thing
* }
*
* The {@link net.forthecrown.grenadier.annotations.Argument} annotation can
* also be used to avoid the {@link java.lang.IllegalStateException} thrown when
* one of the parameter arguments cannot be found like so:
*
* public void run(@Argument(value = "value", optional = true) int value) {
*
* }
*
* This allows for 1 executes method to be reused for several arguments where
* some arguments may be missing.
*
* Examples:
* executes = methodName()
* executes = @variableName
* executes = fieldName
*
*
*
* If the 'executes' field is unset of the 'root' command node, then it may be
* assigned a default value, if it exists. See {@link net.forthecrown.grenadier.annotations.AnnotatedCommandContext#getDefaultExecutes()}
* for more info.
*
*
* Since the 'map_result' can be applied to any argument to change it's result
* type, any value output from any modifier is also valid for executes methods.
* For example, say we have an argument that returns an intermediary object,
* like {@link net.forthecrown.grenadier.types.PositionArgument} which returns
* {@link net.forthecrown.grenadier.types.ParsedPosition}. If we have a
* map_result that converts the position into a location with {@link net.forthecrown.grenadier.types.ParsedPosition#apply(net.forthecrown.grenadier.CommandSource)}
* then we can use either the parsed position or location in method parameters.
*
*
Requires
* Accepts a field/method reference, a variable name or a special 'permission'
* value.
*
* Sets the requirement a command source must pass to use the command node and
* any child nodes.
*
* In the case this field is set to a variable name then the variable must be a
* {@link java.util.function.Predicate}. Otherwise, in the case of a field
* reference the field must be a {@link java.util.function.Predicate} and
* finally, in the case of a method reference the method must return a
* {@code boolean} and accept a single parameter, a {@link net.forthecrown.grenadier.CommandSource}.
*
* If the 'requires' is set to a permission value, the permission value can be
* a quoted string, a reference to a field in the command class or a variable.
* The variable must be a string or a {@link org.bukkit.permissions.Permission}
*
* Examples:
* requires = permission('permission.name')
* requires = permission(PERMISSION_CONSTANT)
* requires = permission(@permissionVariable)
*
* requires = @variableName
* requires = fieldName
* requires = methodName()
*
*
* Map Result
* A field/method reference or variable reference. Allows for the result of an
* argument type to mapped to a different type.
*
* Results can be mapped with a reference to a method/field within the command's
* class or with in the argument result's class.
*
* In the case the value of this is a variable reference, then the variable must
* be an instance of {@link net.forthecrown.grenadier.annotations.ArgumentModifier}.
*
*
* Examples:
*
* // References a method within the argument result
* map_result = result.apply()
* // References a method in the command class
* map_result = mapArgument()
* map_result = @variable
*
*
*
* If you need to map the value of an argument other than the current one, you
* can use {@code map_result(argument name)}, for example:
*
* argument('arg1', entities) {
*
* argument('arg2', int(min=1, max=2) {
* map_result('arg1') = result.findEntities()
* }
* }
*
*
* Description
* A quoted string, variable or translatable text key.
*
* Describes an argument's use description. If this is set in the root node,
* then this becomes the command's description and won't become the usage text
* unless there's an executes method in the root node.
*
* Literal description Example:
* description = 'Argument description'
*
* Translatable description example:
* description = translatable('translation.key')
*
* See {@link net.kyori.adventure.translation.TranslationRegistry},
* {@link net.kyori.adventure.translation.GlobalTranslator} or
* {@link net.kyori.adventure.text.TranslatableComponent} for more info on
* translatable text.
*
* Variable description example:
* description = @desc_variable
*
* The variable must be an instance of {@link net.kyori.adventure.text.Component}
*
* This and the {@code label} values are a part of the usage/help system
* of the command system. When this description is compiled it will be given to
* the {@link net.forthecrown.grenadier.annotations.SyntaxConsumer} of the
* current context with the path to the argument provided as well.
*
*
Syntax Label
* A quoted string, field name or variable that overrides the default node name
* for usage/help messages.
*
* Example:
* argument('pos', vec3i) {
* label = '<pos: x,y,z>'
* }
*
* In the above example, when the node's name is used in a help message, it will
* say '<pos: x,y,z>' instead of '<pos>'
*
* Child nodes
*
* There are 2 types of child nodes, literals and argument nodes, exactly like
* there are in normal Brigadier.
*
* Literals
*
* Literals only require the name that will be input and are declared so:
*
* literal('foobar') {
*
* }
*
*
* In the case a simple node with nothing but an executes is needed, you can
* use the following examples:
*
* literal('foobar') = executesMethod()
* literal('foobar') = commandField
* literal('foobar') = @executes_variable
*
* See Executes section for how executes methods are
* specified. And see Concepts, Names for valid name
* input
*
* Arguments
*
* Arguments require the name of the argument and the argument type. For info
* about the argument types and their parsers, see the {@link net.forthecrown.grenadier.annotations.TypeRegistry}.
*
* Examples:
*
* argument('argumentName', int(min=1, max=5)) {
*
* }
*
* Just like with literals, if all that is required is an empty node with an
* executes function, you can use the following examples:
*
* argument('arg', int(min=1, max=5)) = executesMethod()
* argument('arg', int(min=1, max=5)) = commandField
* argument('arg', int(min=1, max=5)) = @executes_variable
*
* See Executes section for how executes methods are
* specified. And see Concepts, Names for valid name
* input
*
* Comments
* Comments inside {@link net.forthecrown.grenadier.annotations.CommandData}
* values are the same as in java, '//' starts a line comment, and '/*' specifies
* a comment that lasts until '*/'
*
* Full example
*
*
* name = 'signedit'
* aliases = sign | signs
* permission = 'commands.admin.signedit'
* description = 'Allows you to edit signs'
*
* argument(SIGN_ARG, vec3i) {
* map_result = positionToSign()
* label = "<sign: x,y,z>"
*
* literal('clear') {
* description = "Clears a <sign>"
* executes = clear()
* }
*
* literal('copy') {
* description = "Copies a sign that you can later paste"
* executes = copy()
* }
*
* literal('paste') {
* description = "Pastes a previously copied sign"
* executes = paste()
* }
*
* literal('glowing').argument(GLOW_ARG, bool) {
* description = "Changes whether the sign is glowing or not"
* executes = setGlowing()
* }
*
* argument(LINE_ARG, int(min=1, max=4)) {
* label = '<line: 1..4>'
* suggests = ['1', '2', '3', '4']
*
* literal('set') {
* argument(TEXT_ARG, greedy_string) {
* description = "Sets the sign's <line> to <text>"
*
* map_result = stringToComponent()
*
* suggests = suggestSignLine()
* executes = setLine()
* }
* }
*
* literal('clear') {
* executes = clearLine()
* description = "Clears a sign's <line>"
* }
* }
* }
*
*
* @see net.forthecrown.grenadier.annotations.AnnotatedCommandContext
* Central command registration and handling class
*
* @see net.forthecrown.grenadier.annotations.TypeRegistry
* Argument type parser registry
*/
package net.forthecrown.grenadier.annotations;