-
Notifications
You must be signed in to change notification settings - Fork 1
Commands
BNCore has a custom commands framework built with Bear Nation in mind.
Instead of having one giant method with a ton of if statements and switch cases, each function of the command has it's own method in the class.
Please note that it is still under development and may change.
- Neat, concise, easy to read
- No editing the plugin.yml
- Automatic command registration
- Permission and executor checks (e.g. console only)
- Error handling
- Event based (cancellable by other processes)
- Built in and extendable tab completion
The main resource that the commands framework utilizes is Annotations. Annotations are descriptors or metadata on classes, methods, variables, or parameters. By themselves they do nothing, but using reflection (reading that metadata in runtime), you can utilize those annotations to make real decisions. Some examples of how the framework utilizes annotations are:
- Command aliases (
@Aliases) - Command permissions (
@Permission) - Command argument paths (
@Path) - Command arguments and default argument values (
@Arg)
The framework also utilizes an abstract class that each command must extend which provides all of the magic you can use when implementing your command. For example, to throw an error, simply write: error("Your message here"); and the framework handles the rest.
Below is an example command that covers a wide range of the framework's features. Refer to the full documentation below for more info on each part of the command.
// Define at least one alias (required)
@Aliases({"examplecommand", "examplecmd"}) // Note that annotations require curly braces when defining a list
@Permission("example.command")
// Extend CustomCommand (required)
public class ExampleCommand extends CustomCommand {
// Class variables
// Load shared variables here (e.g. services)
// Constructor (required)
public ExampleCommand(CommandEvent event) {
super(event);
}
@Path
void help() {
reply("You didn't pass any arguments that match what we expected, so this is method is executed by default!");
}
@Path("hello")
void helloWorld() {
reply("Hello, World!");
}
// Inject arguments
@Path("add {int} {int}")
void add(@Arg int num1, @Arg int num2) {
reply("Result: " + num1 + num2);
}
@Path("msg {player} {string...}")
// Require permission: example.command.message
@Permission("message")
void message(@Arg Player recipient, @Arg String message) {
recipient.sendMessage("From " + player() + ": " + message);
reply("To " + recipient.getName() + ": " + message);
}
// Default arguments
@Path("default [string]")
void defaultArg(@Arg("Hello!") String arg) {
// arg will have a default value if not passed
reply("Argument: " + arg);
}
}All done! Nothing else is needed.
Location: Class
Required: Yes
Define all aliases of the command.
Examples:
@Aliases("examplecommand")
@Aliases({"examplecommand", "examplecmd"})Location: Class and Method
Required: No
If the annotation exists on the class, all methods will require that permission.
If the annotation exists on the method, the permission is only required for that method.
If the annotation exists on both, both the class permission and the method permission are required. By default, the method permission extends the class permission. For example, if the class requires example.command, and the method should require example.command.dosomething, then you would write @Permission("dosomething"). The framework concatenates the two together.
Examples:
@Permission("example.command")If you want to have a method level permission that does not fall under the class's permission namespace, use:
@Permission(value = "some.permission.here", absolute = true)Location: Method
Required: On all executable methods
Define the argument path needed to execute the method. When the command is run, the framework checks each available path and decides which one the arguments best match. If no match is found, it will look for an empty path (nothing in the parenthesis).
- Literal words are treated as such
-
(one|uno)- Define argument aliases- These are treated as literal words. They are not passed into the method. If you want to make a decision based off which one is present, you should either use
{string}or create a new path and method.
- These are treated as literal words. They are not passed into the method. If you want to make a decision based off which one is present, you should either use
-
{type}- Define a required variable argument. -
[type]- Define an optional variable argument.
- String
- Use
{string...}to capture all subsequent arguments
- Use
- Player, OfflinePlayer
- Default to
selfto default to executor
- Default to
- Date (TODO)
- Int(eger), Double, Float, Short, Long, Byte
- Your own! See Custom Argument Types
Paths also control tab completion if the type has an available tab completer. See Tab Completion
Examples:
@Path("example")
@Path("example2 (one|uno)")
@Path("example3 {int}")
@Path("example4 {player} [string]")Location: Parameter
Required: Yes
Define a method argument to be a command argument. Method arguments must match the path's arguments in order.
- Any
{}path arguments MUST have a corresponding method argument. - Any
[]path arguments MUST have a corresponding method argument WITH a default value. - Nothing else is injected into the method.
Note that defaults are only respected within the framework's wiring. Calling the method directly in code doesn't respect the defaults, you will have to pass them yourself.
All commands must extend this class, and the command's constructor must call super(event);. The class mostly consists of helper methods.
-
getPrefix()- Returns the command's prefix, which is the class name withoutCommandin our default format. -
send(player, message)- Send a colored message to a player -
send(player, message, delay)- Send a delayed (ms) message to a player -
reply(message)- Send a message to the executor -
newline()- Send an empty line to the executor -
error(message)- Throw an error that is displayed to the player. Stops execution.
Calling the following performs an executor check (e.g. to make a command console only, call console())
-
player()- Checks executor is a player and returns the player object -
console()- Checks executor is console and returns the console object -
commandBlock()- Checks executor is a command block and returns the command block object
Arrays and indexes are hard. There are multiple methods to return the argument at a certain index (starting at 1, not 0). It will return null if the index doesn't exist instead of throwing an exception.
-
arg(index)- Returns a string -
arg(index, rest)- Returns a string of all the arguments at and after the index supplied. -
intArg(index)- Returns an integer. Throws an exception if not a number. -
doubleArg(index)- Returns a double. Throws an exception if not a number. -
booleanArg(index)- Returns a boolean (acceptstrue,enable,on,yes, and1) -
playerArg(index)- Returns a Player or an OfflinePlayer
TODO
TODO