Tutorials/Tutorial 1

Simple Plugin

In this tutorial we will look into the necessary things for a super simple plugin that does barely anything at all, but i will also go about a few convenient shortcuts for later on

So what goes into a plugin?

Soruce File Basics

As opposed to a java plugin, which mostly consist of one .jar that you throw into the /plugins folder, for a python plugin you have a few more options (thank you masteroftime/lahwran :) )
Things you can throw into the plugin folder that are formally recognized as plugins by Python Loader:

  • A single .py file
  • your plugin packed as .zip and renamed to .py.zip or .pyp
  • a subdirectory containing your plugin files, with a name ending on .py.dir or _py_dir One thing to note is, that in contrast to java, where you have your .java source files, and the compiled .class files, that are inside the .jar, with a python plugin there is no compiled version, your source .py file is used directly. In case you want to keep your source closed, tough luck, but plugins for an open source project should be open source anyways :D

Plugin description

In every case you need a plugin description to tell bukkit about your plugin. For java plugins, this is a plugin.yml inside the .jar, an option that works for python too, but only for the latter 2 options (since if you use multiple plugins consisting of a single .py file, you can't have multiple different plugin.yml files in the /plugins folder)
So when you use a plugin.yml, your filesystem would look like one of these

/plugins/yourplugin.pyp

and inside the archive .pyp:

/plugin.yml
/plugin.py

or alternatively you use a folder instead of an archive, and it looks like this

/plugins/yourplugin.py.dir/plugin.yml
/plugins/yourplugin.py.dir/plugin.py

The plugin.py can actually be named whatever you want, as long as you specify the filename as the 'main' option inside the plugin.yml
As far as i know, there are a variety of fallbacks if 'main' doesn't point to anything useful, it first searches for main.py and then for plugin.py, or the other way around, but better just specify 'main' correctly.
So your plugin.yml would look something like this

name: SimpleDemoPlugin
main: plugin.py
version: 0.1

In contrast to java, there is another option though, and that is to just skip the plugin.yml and add the relevant plugin description directly into your main .py file, in form of a header consisting of 3 special variables
This way you can distribute a plugin as one single .py file, that just needs to be put into the /plugins folder

/plugins/yourplugin.py

with yourplugin.py starting with

1
2
3
__plugin_name__ = "SimpleDemoPlugin"
__plugin_version__ = "0.1"
__plugin_mainclass__ = "SimpleDemoPlugin"

download source

And that, in its entirety is actually the shortest plugin you could write. It has all relevant information set to be recognized by both Python Loader and bukkit, and would run without any problem, although it wouldn't do anything yet.
Note that __plugin_mainclass__ is not the same as main: inside the plugin.yml, as the description variables have to be inside the main.py anyways, instead it points to the main class to instantiate if you use a main class inheriting from PythonPlugin, otherwise it is just ignored.

Basic Hooks

As a plugin that does nothing but exist is fairly boring, let's go over the most basic things a plugin can do

For our first simple plugin, we will not use a main class (we will not use classes at all actually) and just use the handy descriptor API lahwran has created :)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
__plugin_name__ = "SimpleDemoPlugin"
__plugin_version__ = "0.1"
__plugin_mainclass__ = "SimpleDemoPlugin"

@hook.enable
def onEnable():
    print "SimpleDemoPlugin enabled!"

@hook.disable
def onDisable():
    print "SimpleDemoPlugin disabled!"

download source

A few things to note:

  • The thing with the '@' in front is a so called decorator, it modifies the function defined below
  • There are a few special decorators defined inside the 'hook' interface provided by the Python Loader, that allow you to easily interact with bukkit
  • Any function decorated with @hook.enable is called when your plugin is enabled
  • You may have guessed it already, any function decorated with @hook.disable is called when your plugin is disabled

What the plugin now does, is print a simple message to the server console when it is enabled and disabled. So now at least it makes its existence known, even if its still not very interesting.

Another thing worth mentioning is that while only the last function to be decorated with @hook.enable or @hook.disable is called (masteroftime, if you read this, how about extending the multiple event/command listener handling to this too? :) ), the decorated function doesn't need to have any special name, you could just as well make something like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
__plugin_name__ = "SimpleDemoPlugin"
__plugin_version__ = "0.1"
__plugin_mainclass__ = "Trololo"

@hook.enable
def foo():
    print "This will never see the light of day :("

@hook.enable
def bar():
    print "SimpleDemoPlugin enabled!"

@hook.disable
def baz():
    print "SimpleDemoPlugin disabled!"

download source

In this case, as there are no classes used, __plugin_mainclass__ is just ignored and doesn't do anything

This concludes the tutorial for making a extremely simple and totally useless plugin. Check out the next one to actually do stuff.


Comments

Posts Quoted:
Reply
Clear All Quotes