So I have wanted to learn Java and since my favourite game of the moment, Minecraft is written in Java, I thought, “What better way to learn Java than to start with having a play with writing Minecraft plugins?”. I have a bit of experience with Java and I have looked over the source code for a few Bukkit plugins that I have used and to achieve some fairly simple things it isn’t that difficult and so I am here to share my experiences.

What is Bukkit?

I suppose I should start with explaining a little about Bukkit itself. Bukkit is an unofficial extension on the Minecraft Server providing an API allowing developers to write extensions to the server-side. Unfortunately you are unable to do anything that would require any changes on the client side however this still provides a lot of When playing multi-player, it is down the server to tell the client what blocks are where, which players are where, handle the chat and many more things that are required to link the user experiences of the many players together. Because of this, Bukkit is able to emulate a whole bunch of things – where I have found the main limitations would be, are with visual changes on the client, such as things that would require new textures or 3D models, or even additional configuration GUI but what you can do is use commands. The way Bukkit actually works is by decompiling the official Minecraft releases and editing this where required such that the methods of the API can be implemented. Minecraft (at the moment) do not provide their own API, and a lot of the code is subject to change.

The purpose of the API is to provide a fixed, unchanging interface into the underlying functionality of the server. The Bukkit API is essentially just a set of Java interface files, and the implementation of these interfaces is known as CraftBukkit. Although you can directly access methods of the CraftBukkit objects, this is discouraged, because if it is not part of the interface, then there is nothing saying it won’t change at the next release, and in turn potentially break your code. CraftBukkit is the bridge between what is often referred to as NMS (an abbreviation of the package name for the official Minecraft Server: net.minecraft.server) and hence is updated with every release of Minecraft. The idea is that it abstracts away from the actual code running behind Minecraft, just providing the hooks you need.

What is VoidWarp?

When deciding what plugin I wanted to do, I wanted to pick something simple and achievable as a starting point. After looking through the Bukkit API, playing with a few tutorial projects to get my head round things, I decided on making the VoidWarp plugin. VoidWarp is a simple plugin that teleports the player to a new location when they fall through the void. This would be a simple case of checking the players current location, determining if they are in the void (using their Y coördinate) and then teleporting them to new coördinates. Although this was a fairly simple thing to do there were a few concepts and a few problems I had to get my head around.

The core of a Bukkit Plugin

Making a Bukkit plugin is actually surprisingly simple – or at least to make the shell of a Bukkit Plugin. To get started with the most simple of plugins, you will need:

  • A plugin class
  • A plugin.yml

That’s it!

Plugin Class

Using VoidWarp as my example, the bare minimum for the main class:

package me.flungo.bukkit.VoidWarp;

import org.bukkit.plugin.java.JavaPlugin;

public class VoidWarp extends JavaPlugin {

}

Yep, that’s it! it really is THAT simple! This plugin won’t do much… well it won’t do anything and could be considered rather useless but it just shows how easy it is to actually get started with a Bukkit Plugin. Since that is fairly useless we will make it a bit more useful with the following alterations:

  • Implement a Java Logger for sending output to the console. You can use the System.out.println() but it is strongly discouraged. The logger is simple to use and requires just one line of code to set up:

    public final Logger logger = Logger.getLogger("MineCraft");
    

    If you haven’t used a Java logger before, it will not take long to get your head around the basics. The advantages of the Logger is that with each message a Logger.Level can be set. This makes it easy to have log messages that only show when a finer level is chosen. The true extent of a Logger is a whole subject matter in itself, but as with anything, the best place to start is with the documentation

  • Add onEnable and onDisable methods so that the plugin can be initialised. One thing you can’t (or at least absolutely shouldn’t do) with a Bukkit plugin is use the constructor on your main plugin class. It is for CraftBukkit to instantiate your plugin and only when onEnable is called should you do any work loading classes, initialising variables and such. This then abstracts away any concept of plugin management to CraftBukkit and means that if your plugin is disabled then it will not be consuming memory or other resources with objects that you have instantiated (which, may also lead to your plugin’s functionality not actually being disabled). This also means that the control flow is much more predictable and means you are less likely to break the whole server as calls to your classes, should be wrapped and isolated in try { } catch ( ) { } blocks.

    @Override
    public void onEnable() {
        PluginDescriptionFile pdffile = this.getDescription();
        this.logger.info(pdffile.getName() + " version " + pdffile.getVersion() + " is enabled.");
    }
    
    @Override
    public void onDisable() {
        PluginDescriptionFile pdffile = this.getDescription();
        this.logger.info(pdffile.getName() + " is now disabled");
    }
    

    In these methods we are just implementing a message that confirms that the plugin has been enabled. We use a PluginDescriptionFile object that represents the plugin.yml (see next section) of the plugin. This allows us to get the name and versions of the plugin. Although these strings could be hard coded this is poor practice as it makes the code difficult to maintain.

plugin.yml

The plugin.yml is a file that should be stored in the root of your generated jar (not inside the package) that contains all the metadata Bukkit needs to be able to load your class. The most important ones are name, version and main:

name: VoidWarp
main: me.flungo.bukkit.VoidWarp.VoidWarp
version: 0.2.2

The syntax of this file is YAML (Yet Another Markup Language) which is actually a great little markup language for configurations and settings. It’s simple to learn and the basics needed for now are the idea of key: value for simple mappings. Full details about what can be put into a plugin.yml is available from the BukkitWiki. There are a lot of different settings that can be set including dependencies (to ensure all dependencies are loaded before your plugin), command registration and various other pieces of metadata.

In the example, the most important attribute is main. This defines the fully qualified name of your main class (your plugin class). Without this Bukkit will not know which class to load for your plugin!

Bukkit Events

The first thing is the Bukkit events system. One of the functions provided by the Bukkit API is an events system which provides an efficient way to respond to in game actions. For detailed usage information on how to use this, the best place to look is the BukkitWiki but I hope to explain the basic of using this and also explain a bit about the actual implementation under the hood.

To implement the events, one of the things that CraftBukkit does is add method calls within the original NMS code to trigger the events. In some cases the event is constructed from known information about the event provided from the Minecraft code which can be actually modified by your event. A common modification to an event is to set a boolean flag so that the event is cancelled.

Listeners

There was a recent update to the usage of the events system, but if anything it has made it even easier to use! What you will need is a Listener. A listener is a class that represents a single or a set of EventHandlers. These are usually grouped in a logical way depending on how concise you want each class to be. For example, you may make a PlayerListener and handle all events related to players, or you might make a BlockListener for block events. I went for something a little more specific which was a PlayerLocationListener which would have the one EventHandler. Producing a Listener is as simple as implementing the Listener interface from org.bukkit.event.Listener; as an example, here is my stub class that needs to be populated with EventHandlers:

package me.flungo.bukkit.VoidWarp;

import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerMoveEvent;

public class PlayerLocationListener implements Listener {
    public static VoidWarp plugin;

    public PlayerLocationListener(VoidWarp instance) {
        plugin = instance;
    }
}

I have also implemented a basic constructor that just takes my implementation of JavaPlugin, VoidWarp for later use.

Event handler

Event handlers are very clever in terms of their implementation and make creating new handlers incredibly easy. Using the power of Java annotations, all you need to do is create a method within the Listener of arbitrary name and annotate it with @EventHandler. The way Bukkit then knows what kind of events it handles is through type inference, specifically the type of the first argument of the event handler. The signature for the method must be of the form public void arbitraryMethodName(T event) where T extends Event.

There are a whole bunch of events and the best and most up to date way to find the ones you need is through the Bukkit API Documentation.

In our case, we want the PlayerMoveEvent to check the players position, whenever it changes. We are looking to detect a player in the void so really we are only interested in their Y coördinate. To make sure they are in the void and add a bit more suspense to the teleportation, we will wait until they are at y = -50 (well infact we will check y < -50 as this gives a larger window in case of lag).

To then teleport the player we will construct a Location object that is 2 blocks above the spawn location so that they drop onto the spawn. To then teleport the player to this location is simple, using the Player.teleport() method of the Bukkit API.

All of the information and objects we need can be gotten from the event and can be implemented as so:

@EventHandler
public void onPlayerMove(PlayerMoveEvent event) {
    Player p = event.getPlayer();
    World w = p.getWorld();
    Location to = event.getTo();
    int y = to.getBlockY();
    if (y < -50) {
        Location spawn = new Location(w, w.getSpawnLocation().getX(), w.getHighestBlockYAt(w.getSpawnLocation())+2, w.getSpawnLocation().getZ());
        p.teleport(spawn);
    }
}

Registering Events

So that’s it isn’t it? We have our plugin, we have out listener and event handler, what else do we need to do? Well, we need to tell Bukkit about our listener class! This is easy as pie in the grand scheme of things. All we need to do is instantiate our PlayerLocationListener and register it with Bukkit. We will instantiate the class as an instance variable of our VoidWarp class. To then register this event we will add the following to our onEnable method:

PluginManager pm = getServer().getPluginManager();
pm.registerEvents(this.playerListener, this)

Summary

And that’s all that was needed to make a simple, first Bukkit plugin. It’s not perfect and there are many features to add and things to improve in the code but I thought I would just give you a rough guide of what I have been up to recently.

VoidWarp.java

package me.flungo.bukkit.VoidWarp;

import java.util.logging.Logger;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;

public class VoidWarp extends JavaPlugin {

    public static VoidWarp plugin;

    public final Logger logger = Logger.getLogger("MineCraft");

    public final PlayerLocationListener playerListener = new PlayerLocationListener(this);

    @Override
    public void onDisable() {
        PluginDescriptionFile pdffile = this.getDescription();
        this.logger.info(pdffile.getName() + " is now disabled");
    }

    @Override
    public void onEnable() {
        PluginManager pm = getServer().getPluginManager();
        pm.registerEvents(this.playerListener, this);
        PluginDescriptionFile pdffile = this.getDescription();
        this.logger.info(pdffile.getName() + " version " + pdffile.getVersion() + " is enabled.");
    }
}

PlayerLocationListener.java

package me.flungo.bukkit.VoidWarp;

import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerMoveEvent;

public class PlayerLocationListener implements Listener {
    public static VoidWarp plugin;

    public PlayerLocationListener(VoidWarp instance) {
        plugin = instance;
    }

    @EventHandler
    public void onPlayerMove(PlayerMoveEvent event) {
        Player p = event.getPlayer();
        World w = p.getWorld();
        Location to = event.getTo();
        int y = to.getBlockY();
        if (y < -50) {
            Location spawn = new Location(w, w.getSpawnLocation().getX(), w.getHighestBlockYAt(w.getSpawnLocation())+2, w.getSpawnLocation().getZ());
            p.teleport(spawn);
        }
    }
}

Source code

The full source can be found on my GitHub repository for VoidWarp. This was produced with the commit e167cf3


As of version 0.3.0 there have been some changes to the syntax of the Flatr Shortcode Widget so I have rewritten this guide accordingly! There are still the 3 methods that there were before for inserting the widget however for this guide, I have simplified it down to two!

Simple

The simple method (as the name suggests) is the easiest way to add a widget to your blog posts and pages! It will use all the default settings and all you have to do is insert the code!

[flattr /]

When you use this simple widget, here is how your widget will be configured:

  • The button type will be set to large
  • The User ID will be set to the author’s flattr id (if it is set and enabled in the settings), failing that it will be set to the default flattr ID set on the settings page or through the official Flattr plugin.
  • The title will be set to the Page/Post title
  • The description will be set to the Page/Post excerpt
  • The category will be set to text
  • The language will be set to English
  • Tags will not be set
  • The url will be set to the Page/Post’s permalink
  • The thing will not be hidden from listings on flattr.com

Advanced

You can also customise this code so that you can manually set the variables when calling the shortcode.

[flattr uid='{uid}' btn='{btn}' tle='{tle}' dsc='{dsc}' cat='{cat}' lng='{lng}' tag='{tag}' url='{url}' hide='{hide}' anc={anc} setanc={setanc} qty={qty} /]

All variables are optional (defaults will be used if left blank). If, for example, you wanted the default url you could exclude all “url=’{uid}’ ” and the default would be used. Leaving a variable empty will also result in the default being used but it is probably best practise to remove variables you are not going to be using.

To use edit the shortcode you should change the parameter values (indicated with curly brackets surrounding them). The parameters are:

  • btn – This is the type of button you would like to display. To get the compact button use ‘compact’ otherwise the default (large) button is displayed.
  • uid – This is your personal user id. If not defined, it The User ID will be set to the author’s flattr id (if it is set and enabled in the settings), failing that it will be set to the default flattr ID set on the settings page or through the official Flattr plugin, otherwise the widget will fail and return an error!
  • tle – This is the title of the thing you want to submit. This is typically the title of your blog entry or software name. If undefined the title of your Post/Page will be used.
  • dsc – This is the full excerpt of the content. Some blog text or information about your song you’ve written or so forth. If undefined excerpt title of your Post/Page will be used.
  • cat – This is the flattr category the content belongs to. You can choose between the following: text, images, video, audio, software, rest. If undefined text will be used.
  • lng – Language of the submitted thing. List of available languages. If undefined Enlgish (en_GB) will be used.
  • tag – This is the tags of the thing, to help people finding your content easier on the Flattr website. If you want to use multiple tags, separate using a normal comma (,) sign. If undefined no tags will be used.
  • url – This is the URL of the thing, if this is not always the same on your site. Maybe you have multiple domains with the same content. This is to lock the content to always be recognized as the same content for Flattr. If undefined the permalink of your Post/Page will be used. If you have an anchor that you want to append, it would be best practice to append it using the ‘anc’ parameter.
  • hide – Use this to hide the thing from listings on flattr.com. The value ‘true’ or ‘t’ will hide the thing. If undefined the the thing will be shown on listings on flattr.com.
  • anc – Appends an anchor to the url (saves you having to write the whole URL just to add an anchor). If a unique anchor is used on each widget it allows for multiple widget on the same URL. This must be unique otherwise 2 widgets with the same ‘url’ and ‘anc’ they will be the for the same flattr. Default is blank.
  • setanc – This value is ignored if no anchor is set, if it is set then it will add a code to the top of the widget so that the defined anchor redirects to the widget’s location. This means that when people follow the link from flattr.com, they will be taken to the location of the widget on the page. This is good if you want to have multiple flattrs for different sections and you put the flattr widget at the top of each section. Set to ‘1’ to set to true, ‘0’ to set to false. Set to false if you want to manually input the anchor code (if for example you wanted it elsewhere rather than at the point of the widget or you just wanted the backlink from flattr.com to go to your page as normal)
  • qty – Allows for you to have as many Flattr widgets as you want. Whatever number you set the value to will be the ammount of unique flattr widgets that will be created. Uses anchors to make them unique and is compatible with the ‘anc’ variable – it may cause problems if an anchor is set in the ‘url’ variable. Default is ‘1’.


Contents
    • New Features
      • Flattr Shortcode Syntax Modified
      • Flattr Shortcode Widget Settings
    • Change Log
    • Bugs
    • Features
    • Download

Sorry for the dellay in posting an accompanying blog post to the recent update of the Flattr Shortcode Widget! I must say I am very excited about this new build as it is the start of a lot of great new features that will be coming soon so watch this space!

Click here to go to the download page.

New Features

Flattr Shortcode Syntax Modified

This is not a new feature but is certainly something any existing users should be aware of! The syntax for the shortcode has changed! It is only a minor change and the widget is still backwards compatible but I do plan to eventually remove backwards compatibility all together so it would be best to update to the new syntax. The new syntax stops a lot of common bugs that was happening and makes it all a lot clearer. To find out more about the new syntax view the new syntax information.

Flattr Shortcode Widget Settings

There is now a Flattr Shortcode Settings Page which can be found under the settings tab of your WordPress administration. From this page you can edit/set the default UID for the blog. Currently this is still linked to the official flattr widgets setting however this will soon become independent! The main advantage of this new feature is that you can now set a default flattr UID to be used even if you do not have the official Flattr Widget.

On this page you also have the option to enable/disable author specific UIDs. Having this feature enabled adds a new option to the profile page for a user’s flattr ID. When users who have set their flattr ID make a post their UID will automatically be used for shortcodes they use within their posts! This makes it great for use on multi-author sites!

Change Log

0.3.0

  • NEW: Flattr UID option for induvidual users allowing each user to have their own default Flattr UID
  • NEW: Options Page to set the default Flattr UID for the blog
  • UPDATE: Flattr Shortcode modified – new uid tag added

0.2.3

  • UPDATE: More tags added

0.2.2

  • BUG FIX: Feeds would try and render the javascript button.
  • NEW: RSS displays a Flattr this image in substitute of the js widget but this links to the flattr home page due to Flattr API restictions
  • BUG FIX: Default widget size is not reset to large after creating a compact widget if the Official Flattr Widget is not installed.
  • BUG FIX: Name change was not fully migrated

0.2.1

  • BUG FIX: Anchor now set when used with multi-flattr feature
  • BUG FIX: Anchors <a> tag is now closed properly
  • UPDATE: Additional flattrs made by multi-flattr are hidden from listing on flattr.com to stop spamming
  • BUG FIX: Further whitespace removal to all variables

0.2.0

  • NEW: Anchors added so that multiple flattrs can be used on the same URL
  • NEW: Your backlink from flattr can link straight back to the widget rather than just back to the page (uses anchors)
  • NEW: You can define how many flattr widgets you want to be generated and each work independantly (allows multiple flattrs)
  • NEW: You can use multiple flattrs and anchor features simultaniously
  • UPDATE: All true/flase values must now be set to ‘1’ (true) or ‘0’ (flase)
  • BUG FIX: Hide not always set to true
  • BUG FIX: Default language now works
  • UPDATE: Arrays now used instead of lots of independant variables
  • BUG FIX: Whitespace in variables that would cause the widget to fail is now removed

0.1.4

  • BUG FIX: Decription was not filled in if not manually set and was therefore required

0.1.3

  • BUG FIX: Problems with svn sync fixed
  • BUG FIX: Version numbers corrected

0.1.2

  • UPDATE: Widget name changed from “Flattr Widget” to “Flattr Shortcode Widget”

0.1.1

  • UPDATE: Major updates to readme.txt
  • NEW: Added to WordPress Plugin Directory
  • BUG FIX: Bug that interfered default size of widget for official plugin has been corrected

Bugs

Please report bugs in the comments

Known Bugs

  • None

Features

If there are any features you would like then please request them in the comments

Features in development

  • More development on the Settings pages to allow default setting for the shortcode widget to be set
  • Separation from the official widget
  • Graphical shortcode generator

Download

Click here to go to the download page.