Well, I guess, this is the 5th or 6th version of PocketMine plugin tutorials from me?
I must admit that the versions before had not been very successful, so I guess we should start all over again.
This time, I created the tutorials with GitHub sites. Hopefully more customizable pages will help make the tutorials better.

So, first of all, let's get to know clearly what we are planning to do.
Wait, aren't we going to code PocketMine plugins? Isn't that clear enough?
Then what exactly does a PocketMine plugin do? The answer could be quite vague.
Basically, a plugin has unlimited power (including root access if you are running the server with root) on your server. It is the commander of your server. Plugins instruct PocketMine to get everything done.

So I know that the plugin is the god. But how does knowing that help me?
The problem that made most people unable to code is that most people don't know what they want.
I know very clearly. I want to make a hunger games plugin.
But then, what is a hunger games plugin?

 +-----------------+     +--------------------------+
 | Player tap sign | ==> | Teleport player to lobby | ---+
 +-----------------+     +--------------------------+    |
                                                         |      +-------------------------+
 +-----------------+     +--------------------------+    |      | Timer reached 0 second  |      +-----------------+      +---------------+      +------------------------+      +------------------------------+
 | Player tap sign | ==> | Teleport player to lobby |    + ===> +-- WHEN EITHER HAPPENS --+ ===> | Start the match | ===> | Refill chests | ===> | Timer reached 0 second | ===> | Teleport to deathmatch arena |
 +-----------------+     +--------------------------+    |      |      Enough players     |      +-----------------+      +---------------+      +------------------------+      +------------------------------+
                                                         |      +-------------------------+                               |                                                                                     |
 +-----------------+     +--------------------------+    |                                                                +-------------------------------------------------------------------------------------+
 | Player tap sign | ==> | Teleport player to lobby | ---+ ===> +-------------------+     +---------------------------------------+                              |
 +-----------------+     +--------------------------+           | When player moves | ==> | Don't let player move (teleport back) |                              |
                                                                +-------------------+     +---------------------------------------+                              V                                            +----------------------------------+
                      。                                                                                                                                 +----------------+     +-----------------------+     | If there is just one player left |
                      。                                                                                                                                 | If player dies | ==> | Teleport him to spawn | ==> | Let that player win (add coins)  |
                      。                                                                                                                                 +----------------+     +-----------------------+     +----------------------------------+

 +--------------+     +------------------------+
 | Player joins | ==> | Load player statistics |
 +--------------+     +------------------------+

 +--------------+     +------------------------+
 | Player quits | ==> | Save player statistics |
 +--------------+     +------------------------+

 +---------------------------+     +------------------------+
 | Player type command /stat | ==> | Show player statistics |
 +---------------------------+     +------------------------+
				

The outline for a hunger games plugin actually shows three of the most important components of plugins:

  1. Commands
  2. Events (when something happens)
  3. Timer

Of course, we are nowhere near the complexity of a good hunger games plugin. But at least now we know better what we are going to do.

In Chapters 3-5 of this website, we will go through the principles of these three components, as well as some fundamental ways of doing various actions on the server.
But before that, we would start by creating a useless plugin that works.

It is hilarious for many times someone asks me to teach him/her plugin development, and after half an hour long talk of theory we decided to get our hands on getting something produced and realized that he/she did not have the necessary tools ready. Make sure you have everything in this basic checklist:
  • A PocketMine server that you can directly change its plugin files.
    For testing plugins, obviously.
  • A virtual/hard keyboard that can let you type symbols like ,.;!?$/\|()[]{}.
Yes, that's all. If that's all the resources you got, you could still code plugins, but with very hard time.
Here is a list of recommended tools:
  • Text editor
    • Windows
      • If you are thinking about Microsoft Word, get rid of that thought immediately. Microsoft Word is a rich text editor, and it simply cannot open nor output any text files. Same applies to WordPad that came in Windows' Accessories.
      • You may be thinking about NotePad that came in the Accessories with Windows. Well, it is the best option if you can't install anything on your computer. (But then how did you install PocketMine?)
      • The recommended tool is Notepad++. It is a powerful text editor for many types of files and for different programming languages.
      • Some would recommend NetBeans, but I wouldn't want you to waste time doing all the setup stuff. Believe me, setup for a program always makes anything interesting into boring.
      • If you have heard of PhpStorm, again, same with NetBeans, setup trouble (although there isn't a lot). Moreover, it is paid software, although there are some ways to legitimately get it for free. Nevertheless, it is an all-powerful IDE that completes the code for you when you have provided a little hint, and can also be used for other things like coding websites, etc. Actually, this website was written using PhpStorm (although there is no PHP here).
      • Browser + GitHub The GitHub editor for code is not bad, at least better than Windows Notepad, but it is far not as good as PhpStorm. If you don't like installing anything, this is a good alternative to Notepad++.
    • OS X
      • Some would recommend NetBeans, but I wouldn't want you to waste time doing all the setup stuff. Believe me, setup for a program always makes anything interesting into boring.
      • If you have heard of PhpStorm, again, same with NetBeans, setup trouble (although there isn't a lot). Moreover, it is paid software, although there are some ways to legitimately get it for free. Nevertheless, it is an all-powerful IDE that completes the code for you when you have provided a little hint, and can also be used for other things like coding websites, etc. Actually, this website was written using PhpStorm (although there is no PHP here).
      • Browser + GitHub The GitHub editor for code is not bad, at least better than Windows Notepad, but it is far not as good as PhpStorm. If you don't like installing anything, this is a good alternative to Notepad++.
      • TextMate TextMate (Use the beta!) is an powerful free Editor, with Syntnax highlighing. It has some realy neat functions, and works perfectly with git. It is a powerful text editor for many types of files and for different programming languages.
    • iOS
      • I have never used iOS, so don't ask me :(
    • Android
      I would not advise coding on phones or tablets, but if you don't have an alternative, well...
      • Normal text editors
        Whatever editor you like, as long as it disables autocorrect. You can try Text Editor embedded in the File Manager app.
        BTW, you need a file explorer since plugins consist of more than one file when you are developing.
      • Vim Touch
        It is an imitation of Vim for Linux. It is an odd choice, but it has good things if you
      • Chrome + GitHub Many mobile users found GitHub's direct edit interface good, although it isn't at all.
  • A browser
    For you to look for documentation (and this website) anytime you have trouble. Believe me, nobody memorizes all the functions in PHP.

Yes, this simple. That's all you need. But again, I strongly encourage you to get a computer and a hard keyboard, or you can hardly develop anything big without finding all your $this becoming $thos.

I would assume that you have PocketMine setup already. I hope I don't need to teach you how to find that directory.
Fine. For Android it is ~/PocketMine, where ~ is something like /mnt/sdcard, etc.
Navigate to the plugins directory (a.k.a. folder) in the server directory and install the DevTools plugin.
For our first plugin, we are going to call it FirstPlugin. Now, create a directory in the plugins directory called FirstPlugin. So now we have /plugins/FirstPlugin. For convenience, in the future we are going to call this path ~. E.g. ~/plugin.yml refers to /plugins/FirstPlugin/plugin.yml.

Now, it is time to create the very first file of our plugin. But it is not PHP code. It is a YAML file that describes your plugin, located at ~/plugin.yml.


					name: FirstPlugin
					author: PEMapModder
					version: 1.0.0
					api: 1.13.0
					main: FirstPlugin\FirstPlugin
				

Before you try to copy, please read my explanation for them, line by line.

name: FirstPlugin

This line, apparently, defines your plugin name. Replace FirstPlugin with your plugin name, and you will see it showing up in the startup messages when the server starts.

author: PEMapModder

This line, apparent as well, tells the server who wrote this plugin. Of course, replace PEMapModder with your own name. It can contain spaces. However, if you have more than one author, change author to authors and put down all the author names, separated by commas ,, and put square brackets [ ] around them.

version: 1.0.0

This line defines the plugin's version. It is purely internal with no rules, and the server will not try to understand what you are trying to say in the version. Just type whatever you like here as long as users and yourself can understand it.

api: 1.13.0

API means "application program interface". It is basically the things from PocketMine that lets plugins interact with it. It is like how a microwave oven has buttons to let people adjust it.
This refers to the minimum API version your plugin supports. You can find the current API version of your server from the startup messages:

The first number refers to a complete change in API (major version). The plugin and the server must have the same number here to be loaded.
The second number refers to additions in the API (minor version). The plugin must have the same or smaller number here to be loaded.
The third number refers to minor API changes (patches). Any numbers work here, but you should use the number you tested for.
All these information aside, what you have to know is, you'd better use the number you see in your server's startup.

main: FirstPlugin\FirstPlugin

Here finally comes the part related to the plugin code.
Short and unclear explanation:
This is the fully-qualified name of your plugin's main class.
This obviously explains nothing to someone who doesn't know what a class is. Let's just go through step-by-step.

In PHP (especially in PocketMine-related PHP), code is contained in units called "classes". You can think a class as a "file" (and it is indeed true that we would normally put only one class in one file).
And what's even more exciting, since we have files, we have directories (folders) that contain the files. They are called "namespaces". Actually, we normally put a PHP file with the proper filename in the proper directory according to their namespace and class name. I said "normally" because it sometimes works if you don't, but just forget it and assume that it doesn't.
Usually, just like you put similar files in the same directory, we put classes of the same plugin in the same namespace. We can also have "sub-namespaces" just like we have sub-directories, but that isn't important; just forget about it.

By convention, we use Pascal-case for class names. That is, we would WriteLikeThis if we all write in Pascal-Case.
Note that you can only use alphabets, the 10 numbers (0-9) and the underscore (_) in class names. Also, class names cannot start with numbers.
For namespaces, the same rule applies. However, to create "sub-namespaces", just like file paths in Windows, we separate two parts by a backslash \.
Now, to get a fully-qualified name of the class, which is like the full file path on Windows, we use NamespaceName\ClassName. In our example, FirstPlugin\FirstPlugin is the fully-qualified name of the namespace FirstPlugin and the class name also FirstPlugin.

So what is a class? We will get it discussed in the next chapter.

I have already explained about the meaning of namespaces and classes in the previous chapter - namespaces are like directories, and classes are like files. But to what extent are they alike?
Files that contain PHP code (source code) are called "source files". In your plugin, source files should be located inside a directory called "sources root", which should be at ~/src.
A source file ends with .php. In front of that, it is the fully-qualified name of the class inside the source file.
Now we have the fully-qualified name FirstPlugin\FirstPlugin, we should create our source file at ~/src/FirstPlugin/FirstPlugin.php. Simple. What's not so simple that gave the magical power to plugins is the things inside the file.

Hold your breath and scroll through all these.

STOP. Don't copy it into your file. Oh, did I say "just copy"? Forget that. Instead, try to understand it and write it yourself when you know what you are writing.

This line, <?php, seriously does nothing at all. It doesn't help you in any ways. It is only here to tell people that this is a PHP file.

Sadly, the human race is the best species at finding trouble for themselves. We must put this line at the very beginning of every PHP file, and better on an independent line.

Yes. Honestly. These lines are purely decorative. You can add spaces and tabs and break code into new lines literally anywhere in your PHP file (but after the <?php line!), as long as they don't cut one word into two. (But it is not reasonable to change function into fun ct ion, is it?)

Nevertheless, programmers have a general habit of talking things in terms of "lines", but when we talk about a "line" of code, we generally refer to a statement. I will explain more about what a statement is later.

This is pretty obvious. When discussing the main attribute in our plugin.yml, we have already mentioned that the namespace of this class is FirstPlugin.

We have to declare the namespace in every PHP file, unless it doesn't have a namespace (but this SHOULD NOT happen in a plugin!). As you can observe, the syntax to declare a namespace is:

namespace namespace_for_this_file;

namespace_for_this_file should be the whole namespace, including the backslashes (\) and the subnamespaces.

Don't forget the semicolon at the end. A rule for PHP is that all statements would end with ; (semicolons), unless they end with a {, then enclose other lines of code, and finally a }. (Of course, except <?php, which is not code at all)

' Keep in mind that the namespace statement must be the very first statement in every PHP file (of course after <?php)

There are two types of use statements:

use Fully\Qualified\ClassName;
use Fully\Qualified\ClassName as AnAlias;

Quite self-expanatory, isn't it? Actually, the first type is just a simplified form of the second type. We can change the first line into:

use Fully\Qualified\ClassName as ClassName;

They basically mean the same thing.

OK. But what are use statements for?

use statements tells the PHP compiler that when you later say AnAlias in this file, you are talking about Fully\Qualified\ClassName. In this way, even though the namespace is very long, we can use the class as a short alias. If you don't say as what, as in the first type, the PHP compiler will use the simple class name as the alias. In fact, programmers usually only use the first type to avoid confusion, unless they are coding something real quickly and short and use aliases to shorten the class name (but don't do this in code where you expect other people to read, or yourself to read after a few months - people will have a hard time understanding it).

In the dummy class above, we used:

use pocketmine\plugin\PluginBase;

On line 7, we mentioned PluginBase, but because of the use statement from line 5, it actually means pocketmine\plugin\PluginBase rather than merely PluginBase.

Remember that use statements must be directly after the namespace statement.

Pro tip: apart from class names, use statements can also register aliases for namespaces. This is handy when you are using a lot of classes from that namespace.

For convenience, I am going to refer use statements as "imports" in the future.

Now, we have finally come to the most important part of our code. (Actually, the only part that does something meaningful).

Before I start explaining what this line (line 7) does, let's have an overview on the syntax of the PHP language. Yes, an overview, a very brief and general one. Really general one, you'd probably think that this is useless, but it lets you automatically understand a lot of things in the future.

Let's look at this text. Don't worry, it is written in English :)

When a player moves, if he is not an op, teleport him to jail. Take money from him. Send him a message. When the server stops, if the server owner is not online, notify him. Delete all worlds.

This describes what happens in the plugin in English. I hope that you notice the ambiguity in this text
I said "Take money from him.", but does this mean take money from him if he is not an op? Or whenever he moves?
"Delete all worlds.", does this happen only if the server owner is not online, or whenever the server stops?
To clarify my meaning, let's format my text into this:

When a player moves:
{
	If the player is an op:
	{
		Teleport him to jail.
		Take money from him.
	}
	Send him a message.
}
When the server stops:
{
	If the server owner is not online:
	{
		Notify him.
	}
	Delete all worlds.
}
					

Now, it is crystal clear that I am referring to the things inside the curly braces ({}) when I say "if the player is an op". And as a matter of fact, this is how PHP understands what you say.

In the PHP syntax, it main consists of two compoenents - statements and statement groups.

A statement is like a sentence saying what to do, like "Teleport him to jail". Just like how we end every sentence in English with a full stop ., we end every PHP statement with a semicolon ;.

A statement group consists of a line that explains what this statement group is about, then followed by a group of statements. For example, in the text above, "When the server stops" explains what the following group of statements is about.
Yes, a statement group is a statement too. Therefore, we can have a statement group inside a statement group.
Usually, a statement group looks like this:

group_type{
	many statements;
	and nested statement groups{
		here;
	}
}
						

Sometimes, group_type can contain more information than merely the group type. Let's go back to our dummy class for an example.

This was our class statement group:

class FirstPlugin extends PluginBase{
	# some code was here
}
					

This declares a class called FirstPlugin. we have previously decided that our fully-qualified class name should be FirstPlugin\FirstPlugin, where the first FirstPlugin is the namespace and the second FirstPlugin is the simple class name. We have already declared the namespace for this file on line 3, so we don't need to mention it again.

The next part of this line says that the class FirstPlugin extends PluginBase. What does that mean?
Remember what we did on line 5? PluginBase actually means pocketmine\plugin\PluginBase, which is a class provided by PocketMine itself.

So what? What does this class do? What is meant by extends?

The concept of "extend" is more complicated. But for the moment, you can assume that it means that this class is the main class of a plugin.

There are two types of statements inside a class. They are class properties and functions. Class properties are the "memory" of a class, but you can ignore that for the moment. We are going to talk about functions first.

function is another kind of statement group. It declares a function.

Have you ever learnt functions from mathematics? OK, if you haven't, learn it now.

A function is like a crafting table. You add ingredients (parameters/arguments) into it, and it will give you some product (return value). Furthermore, the order of how you put the input matters.
For example, you have three diamonds and two sticks. If you put the three diamonds on the top, you get a diamond pickaxe. But if you put one diamond on the side of the middle, you get a diamond axe.
The same thing goes to functions. A function accepts some arguments (sometimes none, though). It expects each argument to be something. For example, a function that sets a block in a world would accept two arguments, the first argument being the position to change, and the second argument being the type of block to change into.
Functions are also like commands. Say, the /effect command. You have to provide a player in the first argument. The second argument is the effect type. You can optionally also provide the third and fourth argument for duration and amplitude, but the command will assume default values for you if you didn't provide them.

Just like commands, apart from arguments and return values, a function also has a name, description and permission, although we instead call description documentation and permission visibility.
The function's name has the same rules as classes, except that it starts with a small letter instead of a capital letter. That is, we use camelCase rather than PascalCase.
There are three types of visibility for a function, namely public, protected and private. Public functions can be used from anywhere. Private functions can only be used when you are writing code from that class. As for protected functions, they are like private functions, but also accessible by subclasses. What are subclasses? You won't need to know that until you are making really complicated or high-quality plugins (e.g. SimpleAuth).

When a function is inside a class, we also call it a "class method". But let's call it "function" to avoid confusion.

As you may have already noticed, this is the syntax of declaring a function:

						function_visibility function function_name(arguments){
							code_inside_the_function
						}
					

For instance:

						public function myFunction($arg1, $arg2){
							// some code here
						}
					

You might be asking what the // means. It is the line comment symbol. This means that everything on that line after the // will be ignored. This is useful when you want other people, or yourself a few months (or a few days) later to easily understand what you are writing.

Server: chat.freenode.net:6667
Private message: PEMapModder
Channel: #pmplugins

Please create a pull request on GitHub if you found mistakes in this webpage.

This page is mainly authored by PEMapModder,

This webpage uses the highlight.js library (and its rainbow theme) for syntax highlighting.