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" |
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!" |
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!" |
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