Learn the Ropes

Discussion in 'Plugin Development' started by Ahont, Jun 28, 2012.

Thread Status:
Not open for further replies.
  1. Offline


    I couldn't find a place to post this but I have beginner/intermediate java skills but little group experience. I also have never worked with an outside library or anything like that. If anyone needs a decent programmer to help with small tasks let me know. I want to get some hands on experience. I tried making my own basic plugin but was overwhelmed with how little I know about bukkit or it's library.
  2. Offline


    Oh you dont need to join a group to get some experience. Just ask us. What do you need help with?
  3. Offline


    I am just basically looking for a good basic tutorial for beginners or something along those lines. I would like for it to be fairly descriptive. Most tutorials i have seen on youtube have been pretty clueless why one line of code goes somewhere or something like that
  4. Offline


    Ill admit, when i first started learning the bukkit api, it was fairly confusing for me too, and i had no idea what i was doing. But a bit of tinkering here and there and ive gotten to the point where, if i may say so, i have an above average level of knowledge in the bukkit api.

    I guess a simple explination of the API would be that, for your plugin, the "public static void main" would be your onEnable method. Whenever your plugin boots up, it starts there. That will be where you kick everything off. Of course, your class fields will be declared before the onEnable method is ran, so be sure to not create objects that have constructors with dependancies on the plugin being enabled just yet. (i say declare them in the field, then initialize them in onEnable())

    Now heres where it gets fuzzy, In my opinion, at this point there are two MAIN bits to the plugin. Commands, and Events. These are, for the average plugin, where most (if not all) of the code is going to go. Im sure you can already guess what each is used for, so i wont bother explaining that, but i will go over the basics of how to use each of them.

    You will have to register your commands in your plugin.yml*. Ill explain how the plugin.yml file works later, but just know that it contains all of the information about each command, such as permissions, usage, description, etc. Now, whenever a command is executed on the server, it runs the onCommand method. This method returns a boolean. The boolean is basically how the command should return. False for failed command (not enough parameters, incorrect parameters, etc) true for a successful command.** If a command fails, it sends the commands "usage" string to the command sender.

    Now, the parameters: First is the CommandSender, or the "sender". thisis most commonly either one of two things, a Player, or a ConsoleCommandSender. (theres another, the RemoteConsoleCommandSender, but thats rarely used or cared about afaik) you can use instanceof to filter which is which. For instance, if you absolutely-definitely*** need a player, and not the console, you can do this:
    example (open)

    if(!(sender instanceof Player)){
    sender.sendMessage("You must be a player to use this command");
    return true;
    } else {
    Player player = (Player)sender;
    player.sendMessage("You are a player!");
    return true;

    next is the command. (cmd) Ive delved fairly deep into the api. dealt with a majority of the things it has to offer, but the only ever thing ive ever used the cmd object for, is to test the name. cmd.getName().equals("command"). You basically filter for which command theyre sending:
    example (open)

    return true;
    return true;

    Third, is the label. The label is an interesting parameter, in that its not typically needed to be used, but its extremely useful when you DO need it to be used. The label is the litteral command string that the sender has typed in. The reason this can be different than cmd.getName() is because commands can have "aliases"****. The reason this is useful is... Well lets say you have a time command. You can type /time <long> to set the time specifically, but lets say you give time an alias of "day" and "night". If you typed /day with no parameters, it would set it to a predetermined time, because you checked the label. If it was "day" then you would set it to a day-time. Same with night. Its just a way of making shortcuts, i guess!

    Lastly, and arguably most important, is String[] args. As you can tell, args is an array of strings. Basically, they are your arguments, or parameters. If i typed /command arg1 arg2, cmd.getName() would be "command" and args would be new String[]{"args1","args2"} Not much to say here, but this is basically where you put your parameters. im sure you can take it from here :3

    Thats basically how to use commands in a nutshell, But you dont always have to use onCommand from your main plugin instance. If you create an object that implements CommandExecutor, it inherits its very own onCommand method, that is pretty much an exact copy of the one in your main class. To register it, you have to do it per command. in your main class(typically onEnable), you would type getCommand(commandName).setExecutor(yourCommandExecutor); You need to do this for every command that will be executed by the executor.

    Events and Listeners:
    Listeners are the other huge part of plugin development. Typically, my plugins run a majority of their code through listeners. If you havnt guessed it already, listeners are bits(or bunches) of code that runs when something happens on the server. To set up a listener, the class you register must implement "Listener" Then, you choose your listeners, by creating methods that take a single parameter, which's type extends "event"*****. You can name the parameter anything you wish, but typically plugin devs call it event. The method can be named anything you wish, but it MUST have an @EventHandler annotation. Here is an example of an event method:
    example (open)

    public void playerChat(PlayerChatEvent event){
    //this method will run whenever a player types a message into the chat window.

    The method must be public, and must return void. It must contain a single event parameter. The event object will have everything you need inside of it. For instance, in the above player chat event, the event contains the player who chatted, and the message that will be sent. Some events implement cancellable. This is a special interface that will allow you to cancel events******. For instance, if you wanted to cancel the player chat event, you could. (event.setCancellable(true)) If you do that, the message wont be sent.

    Now that actually handleing the event is dealt with, you need to register your listener. Typically you register listeners in onEnable, by grabbing the PluginManager, and registering events:
    Bukkit.getPluginManager().registerEvents(yourListener, yourPlugin);

    Event priority is also another subject to touch on. if there are multiple plugins that run on the server, you're going to be handling events that other plugins are also handling. So bukkit created the priority system so you can, as they put it, get your priorities straight. Read this for an in depth explination. But the gist of it is, event methods with lower priority are fired first, then higher and higher untill all methods have run. To set the event priority, you give it to the annotation, as such:
    @EventHandler (priority = /**eventPriorityhere*/)

    The plugin.yml is where you put all of your settings. There are only four required entries, however:
    main, author, version, name.
    Main is the location of the class file that extends JavaPlugin (your "plugin instance")
    author is a string, your name.
    version is the version of your plugin.
    name is the name of the plugin.
    You also register commands and permissions here, and a few other things. Read this for more information about each.

    Anyways, sorry this took SO long to write up, and if i misunderstood your post, im really sorry for wasting your time, but i hope this answers the questions youve had...

    With that, your crash course introduction to the bukkit api is finished. If anyone else sees ive missed something, please point it out and post some more!

    * (open)

    *With reflection, you can actually hijack the command map and register commands on the fly, but thats fairly advanced stuff
    **My style typically always returns true, so i can just send the command sender my own custom error/success message.
    ***Please read this.
    ****Lets say you have a command "command" if you wanted to type something else, you would set "cmd" as the alias. So if you typed "/cmd", cmd.getName() would return "command" while label would return "cmd"
    *****Some events are abstract, and cant be listened to
    ******Events are always thrown just before the actual event happens on the server
    Wizehh, FlareLine, gomeow and 5 others like this.
  5. Offline


  6. Offline


    Just one thing, theres actually an onLoad() that gets called before the onEnable() in the plugins main class ;)
  7. Offline


    Is there?

    :eek: i had no idea. What is it useful for?
  8. onLoad() triggers before any other plugin's onEnable(), so you can do stuff before any other plugin enables.
    Careful on plugin-specific methods tough, like getConfig(), I'm unsure if it works properly in onLoad().

    I used it in the past to remove all recipes from the server, that way the recipes added by other plugins aren't affected.... but I had to resort to another method because server mod recipes are added before that xD but that's another story.
  9. Offline


    I usually use the onLoad() to initiate my custom logger object so i can output debug info directly as the onEnable() gets called :)
  10. Offline


    CorrieKay, this has been the single most helpful thread ive ever read on plugin development for beginners; because of your awesome post. im not sure if its against the forum rules to bump an oldish thread like this but the extreme amount of helpfulness this thread brings justifies any bump.
    CorrieKay likes this.
  11. Offline


Thread Status:
Not open for further replies.

Share This Page