GithubHelp home page GithubHelp logo

jmhertlein / reflective Goto Github PK

View Code? Open in Web Editor NEW
2.0 3.0 2.0 74 KB

A Bukkit command framework that takes the hassle out of writing commands.

License: GNU General Public License v3.0

Java 100.00%

reflective's Introduction

Reflective

Reflective is a command framework for Minecraft server plugins that use the Spigot fork of the Bukkit API.

It lets you write commands like this:

@CommandMethod(path = "my test command", permNodes={"mytest.command"}, requiredArgs=3)
public void myTestCommand(Player sender, Integer arg1, Double arg2, String arg3, String[] rest) {
  //the player's command is mapped to this method in O(log(n)) time
  //The type of sender is checked for you
  //the permission node is checked for you
  //the number of supplied arguments is checked for you
  //arg1, 2, and 3 are all type-checked and converted for you- it can handle all the eight boxed primitive types + String
  //any additional stuff the user typed is copied into the String[]
}

And if you don't even need any parameters (you just want the command to DO something), well, that's even simpler:

@CommandMethod(path = "do something")
public void thingToDo() {

}

Reflective focuses on simplifying the process of handling commands and drastically reducing the amount of code you need to write. It offers a CommandExecutor implementation (TreeExecutor) that you add CommandDefinition instances to.

Your plugin makes CommandDefinition implementations and marks methods with the @CommandMethod annotation. This lets the TreeExecutor register them.

Reflective offers automatic tab completion for all commands registered with a TreeCommandExecutor- just add the associated TreeTabCompleter.

Reflective provides an annotation processor to add compile-time sanity checks of all methods annotated with @CommandMethod (CommandMethodProcessor) and it is strongly suggested you use it, I promise it's awesome.

The 'root' of each command still needs to be in your plugin.yml.

Usage

This is a library, so to use it just add it to your classpath.

Maven users can use this:

    <dependency>
      <groupId>net.jmhertlein</groupId>
      <artifactId>reflective</artifactId>
      <version>1.0</version>
      <scope>compile</scope>
    </dependency>

    <repository>
      <id>jmh-repo</id>
      <url>http://maven.jmhertlein.net/~joshua/maven/</url>
    </repository>

License

GPLv3, check LICENSE or COPYING for more details. Note that this is the full GPL- to use this library, your plugin must also be licensed under the GPLv3+. To clarify, that means your plugin will be free and open source software that anyone can use, copy, modify, and redistribute.

Example

The most important classes are:

  • TreeCommandExecutor - a CommandExecutor implementation pre-made for you
  • CommandDefinition - a marker interface that you'll make an implementation of
  • net.jmhertlein.reflective.CommandMethod - an annotation (one of those @ things above methods) to mark a method as a command

Suppose we have a simple ticket-handling plugin. The CommandDefinition might look like this:

public class TicketCommandDefinition implements CommandDefinition {
  @CommandMethod(path = "ticket open",
    requiredArgs = 1,
    permNodes = {"tickets.open"},
    helpMsg = "Usage: /ticket open [message]")
  public void openTicket(Player p, String[] args) {
    //logic here
  }

  @CommandMethod(path = "ticket close",
    requiredArgs = 1,
    permNodes = {"tickets.close"},
    helpMsg = "Usage: /ticket close [id]")
  public void closeTicket(CommandSender s, Integer id) {
    //logic here
  }

  @CommandMethod(path = "ticket list",
    permNodes = {"tickets.list"},
    helpMsg = "Usage: /ticket list")
  public void listTickets() {
    //logic here
  }
}

Make sure that you add the "ticket" command to your plugin.yml!!!

Then, in onEnable() of your JavaPlugin subclass,

onEnable() {
  //...
  TreeCommandExecutor tree = new TreeCommandExecutor();
  TreeTabCompleter completer = new TreeTabCompleter(tree); //only if you want free tab completion, see below

  tree.add(new TicketCommandDefinition());

  PluginCommand cmd = getCommand("ticket");
  cmd.setExecutor(tree);
  cmd.setTabCompleter(completer); //only if you want free tab completion, see below
  //...
}

And you're set. Hop in-game and try it out. The commands this makes are:

  • /ticket open
  • /ticket close
  • /ticket list

@CommandMethod has several arguments:

  • path - the command the player will type to run the method, minus the leading /. Required.
  • permNodes - the permission node the player needs to be able to run the command. Default none.
  • requiredArgs - the number of arguments that are guaranteed to be in the args array. If the player doesn't provide enough args, they will get the contents of helpMsg printed for them. Default 0.
  • helpMsg - The message printed to a player if they don't provide enough arguments. Default "No help available."
  • filters - Array of names of filters that getFilter() in your CommandDefinition will return.

Requirements

Methods annotated with @CommandMethod must conform to these rules:

  • Method must be public
  • Method must have either 0 or 1 parameters in the set {CommandSender, ConsoleCommandSender, Player}
  • Any parameter that is a CommandSender, ConsoleCommandSender, or Player, must be the first parameter
  • Method must have either 0 or 1 parameters of type String[]
  • Any parameter is a String[] must be the last parameter
  • The types of all parameters must be in the set {Player, ConsoleCommandSender, CommandSender, Integer, Long, Float, Double, Boolean, Character, Byte, Short, String, String[]}

Type Coercion

Reflective can automatically parse strings into any of the eight boxed primitive types listed above (in Requirements), as well as String itself.

Sender Checking

Reflective will check the runtime type of the CommandSender against what you specify in your method's parameter list. If you used Player, only players can run the command. If you used ConsoleCommandSender, then only console can run that command. If you used CommandSender, then either can run that command.

Optional Arguments

Reflective can handle optional arguments. For instance:

@CommandMethod(path = "cmd", requiredArgs = 1)
public void myCmd(Player p, Integer requiredInt, Float optionalFloat) {
  // NOTE: The names of the identifiers are not important
  // The order, from left to right, is what's important!
  //...
}

If the player types "/cmd 1", then optionalFloat will be null. If the player types "/cmd 1 2.2" then the float will contain 2.2.

Permission Checking

Reflective can also handle multiple permission nodes per command. If permNodes={"node.one", "node.two", "node.three"} then if a user has node.one OR node.two OR node.three, then they will be able to run the command.

Filters

Reflective supports filters that are vaguely inspired by Ruby on Rail's before_action/before_filter. They let you specify a list of Predicate<CommandSender>s that will be tested against the sender of each command whose @CommandMethod annotation specifies that filter's name in its filters array.

Ex:

/*
  In your CommandDefinition implementation...
*/

@CommandMethod(path = "cmd", filters="nameStartsWithN")
public void myCmd() {
  //...
}

@Override
public Predicate<CommandSender> getFilter(String filterName) {
  switch(filterName) {
    case "nameStartsWithN":
      return sender -> sender.getName().startsWith("N");
    default:
      return s -> true;
  }
}

In this example, when the players runs the command /cmd, all of the Predicates named in the filters array will be tested (in this case, just one: "nameStartsWithN"). If any of them evaluate to false, then the user will be denied permission to the command (with the default "insufficient permission" message).

GraphViz

Reflective can export a tree of all of your commands to a dot file for you.

TreeCommandExecutor e = ...; //the TreeCommandExecutor that you used
File f = new File(filename);
try(DotWriter w = new DotWriter(f, true)) {
  e.writeToGraph(w);
} catch(FileNotFoundException ex) {
  System.err.println("Error saving graph: " + ex.getLocalizedMessage());
}

This can then be converted to a PNG image with graphviz, ex: dot -Tpng my_dotfile.dot > out.png

Opt-out

While the framework can do a lot of args-count-checking, sender-type (console/player) checking, and permissions checking for you, you are of course free to ignore them and do your own checks.

Bugs

Open an issue here on GitHub.

To Do

  • Add support for custom messages to show the user for each filter in the event it evaluates to false.

Contributing

I'm always open to pull requests, bug reports, comments, criticism, etc. All contributed code must be licensed under the GPLv3+.

reflective's People

Contributors

jmhertlein avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar  avatar

reflective's Issues

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.