104 | Well, I guess, this is the 5th or 6th version of PocketMine plugin tutorials from
105 | me?
106 | I must admit that the versions before had not been very successful, so I guess we should start all over
107 | again.
108 | This time, I created the tutorials with GitHub sites. Hopefully more customizable pages will help make
109 | the tutorials better.
110 |
113 | So, first of all, let's get to know clearly what we are planning to do.
114 | Wait, aren't we going to code PocketMine plugins? Isn't that clear enough?
115 | Then what exactly does a PocketMine plugin do? The answer could be quite vague.
116 | Basically, a plugin has unlimited power (including root access if you are running the server with root)
117 | on your server. It is the commander of your server. Plugins instruct PocketMine to get everything done.
118 |
121 |
122 | So I know that the plugin is the god. But how does knowing that help me?
123 |
124 | The problem that made most people unable to code is that most people don't know what they want.
125 | I know very clearly. I want to make a hunger games plugin.
126 | But then, what is a hunger games plugin?
127 |
131 | +-----------------+ +--------------------------+ 132 | | Player tap sign | ==> | Teleport player to lobby | ---+ 133 | +-----------------+ +--------------------------+ | 134 | | +-------------------------+ 135 | +-----------------+ +--------------------------+ | | Timer reached 0 second | +-----------------+ +---------------+ +------------------------+ +------------------------------+ 136 | | Player tap sign | ==> | Teleport player to lobby | + ===> +-- WHEN EITHER HAPPENS --+ ===> | Start the match | ===> | Refill chests | ===> | Timer reached 0 second | ===> | Teleport to deathmatch arena | 137 | +-----------------+ +--------------------------+ | | Enough players | +-----------------+ +---------------+ +------------------------+ +------------------------------+ 138 | | +-------------------------+ | | 139 | +-----------------+ +--------------------------+ | +-------------------------------------------------------------------------------------+ 140 | | Player tap sign | ==> | Teleport player to lobby | ---+ ===> +-------------------+ +---------------------------------------+ | 141 | +-----------------+ +--------------------------+ | When player moves | ==> | Don't let player move (teleport back) | | 142 | +-------------------+ +---------------------------------------+ V +----------------------------------+ 143 | 。 +----------------+ +-----------------------+ | If there is just one player left | 144 | 。 | If player dies | ==> | Teleport him to spawn | ==> | Let that player win (add coins) | 145 | 。 +----------------+ +-----------------------+ +----------------------------------+ 146 | 147 | +--------------+ +------------------------+ 148 | | Player joins | ==> | Load player statistics | 149 | +--------------+ +------------------------+ 150 | 151 | +--------------+ +------------------------+ 152 | | Player quits | ==> | Save player statistics | 153 | +--------------+ +------------------------+ 154 | 155 | +---------------------------+ +------------------------+ 156 | | Player type command /stat | ==> | Show player statistics | 157 | +---------------------------+ +------------------------+ 158 |159 |
162 | The outline for a hunger games plugin actually shows three of the most important components of plugins: 163 |
164 |-
165 |
- Commands 166 |
- Events (when something happens) 167 |
- Timer 168 |
170 | Of course, we are nowhere near the complexity of a good hunger games plugin. But at least now we know 171 | better what we are going to do. 172 |
173 | 174 |
175 | In Chapters 3-5 of this website, we will go through the principles of these three
176 | components, as well as some fundamental ways of doing various actions on the server.
177 | But before that, we would start by creating a useless plugin that works.
178 |
-
189 |
- A PocketMine server that you can directly change its plugin files.
190 | For testing plugins, obviously. 191 |
192 | -
193 | A virtual/hard keyboard that can let you type symbols like
194 |
,.;!?$/\|()[]{}
. 195 |
196 |
199 | Here is a list of recommended tools: 200 |
-
201 |
- Text editor
202 |-
203 |
- Windows
204 |
-
205 |
-
206 | If you are thinking about Microsoft Word, get rid of that thought
207 | immediately. Microsoft Word is a rich text editor, and it simply cannot open nor
208 | output any text files. Same applies to WordPad that came in Windows'
209 | Accessories.
210 |
211 | - 212 | You may be thinking about NotePad that came in the Accessories 213 | with Windows. Well, it is the best option if you can't install anything on your 214 | computer. (But then how did you install PocketMine?) 215 | 216 |
- 217 | The recommended tool is Notepad++. It is a powerful 219 | text editor for many types of files and for different programming languages. 220 | 221 |
- 222 | Some would recommend NetBeans, but I wouldn't want you to waste time doing all 223 | the setup stuff. Believe me, setup for a program always makes anything 224 | interesting into boring. 225 | 226 |
- 227 | If you have heard of PhpStorm, again, same with NetBeans, setup trouble 228 | (although there isn't a lot). Moreover, it is paid software, although there are 229 | some ways to legitimately get it for free. Nevertheless, it is an all-powerful 230 | IDE that completes the code for you when you have provided a little hint, and 231 | can also be used for other things like coding websites, etc. Actually, this 232 | website was written using PhpStorm (although there is no PHP here). 233 | 234 |
- Browser + GitHub 235 | The GitHub editor for code is not bad, at least better than Windows Notepad, but 236 | it is far not as good as PhpStorm. If you don't like installing anything, this 237 | is a good alternative to Notepad++. 238 | 239 |
241 | -
206 | If you are thinking about Microsoft Word, get rid of that thought
207 | immediately. Microsoft Word is a rich text editor, and it simply cannot open nor
208 | output any text files. Same applies to WordPad that came in Windows'
209 | Accessories.
- OS X
242 |
-
243 |
- 244 | Some would recommend NetBeans, but I wouldn't want you to waste time doing all 245 | the setup stuff. Believe me, setup for a program always makes anything 246 | interesting into boring. 247 | 248 |
- 249 | If you have heard of PhpStorm, again, same with NetBeans, setup trouble 250 | (although there isn't a lot). Moreover, it is paid software, although there are 251 | some ways to legitimately get it for free. Nevertheless, it is an all-powerful 252 | IDE that completes the code for you when you have provided a little hint, and 253 | can also be used for other things like coding websites, etc. Actually, this 254 | website was written using PhpStorm (although there is no PHP here). 255 | 256 |
- Browser + GitHub 257 | The GitHub editor for code is not bad, at least better than Windows Notepad, but 258 | it is far not as good as PhpStorm. If you don't like installing anything, this 259 | is a good alternative to Notepad++. 260 | 261 |
- TextMate 262 | TextMate (Use the beta!) is an powerful free Editor, 263 | with Syntnax highlighing. It has some realy neat functions, and works perfectly with git. 264 | It is a powerful text editor for many types of files and for different programming languages. 265 | 266 |
268 | - iOS
269 |
-
270 |
- I have never used iOS, so don't ask me :( 271 |
273 | - Android
274 | I would not advise coding on phones or tablets, but if you don't have an alternative, 275 | well... 276 |-
277 |
- Normal text editors
278 | Whatever editor you like, as long as it disables autocorrect. You can try Text 279 | Editor embedded in the File Manager app.
280 | BTW, you need a file explorer since plugins consist of more than one file when 281 | you are developing. 282 |
283 | - Vim Touch
284 | It is an imitation of Vim for Linux. It is an odd choice, but it has 285 | good things if you 286 |
287 | - Chrome + GitHub 288 | Many mobile users found GitHub's direct edit interface good, although it isn't 289 | at all. 290 | 291 |
293 | - Normal text editors
295 | - Windows
204 |
- A browser
296 | For you to look for documentation (and this website) anytime you have trouble. Believe me, 297 | nobody memorizes all the functions in PHP. 298 |
299 |
301 | Yes, this simple. That's all you need. But again, I strongly encourage you to get a computer and a
302 | hard keyboard, or you can hardly develop anything big without finding all your $this
303 | becoming $thos
.
304 |
308 | I would assume that you have PocketMine setup already. I hope I don't need to teach you how to find
309 | that directory.
310 | Fine. For Android it is ~/PocketMine
, where ~
is something
312 | like /mnt/sdcard
, etc.
313 | Navigate to the plugins
directory (a.k.a. folder) in the server directory
314 | and install the DevTools plugin.
316 | For our first plugin, we are going to call it FirstPlugin
. Now, create a
317 | directory in
318 | the plugins
directory called FirstPlugin
. So now
319 | we have /plugins/FirstPlugin
.
320 | For convenience, in the future we are going to call this path ~
. E.g.
321 | ~/plugin.yml
322 | refers to /plugins/FirstPlugin/plugin.yml
.
323 |
326 | Now, it is time to create the very first file of our plugin. But it is not PHP code. It is a YAML
327 | file that describes your plugin, located at ~/plugin.yml
.
328 |
330 | name: FirstPlugin
331 | author: PEMapModder
332 | version: 1.0.0
333 | api: 1.13.0
334 | main: FirstPlugin\FirstPlugin
335 |
336 | Before you try to copy, please read my explanation for them, line by line.
337 |name: FirstPlugin
338 | This line, apparently, defines your plugin name. Replace FirstPlugin
with
339 | your plugin name, and you will see it showing up in the startup messages when the server starts.
author: PEMapModder
341 | This line, apparent as well, tells the server who wrote this plugin. Of course, replace
342 | PEMapModder
with your own name. It can contain spaces. However, if you
343 | have
344 | more than one author, change author
to authors
345 | and
346 | put down all the author names, separated by commas ,
, and put square
347 | brackets
348 | [ ]
around them.
version: 1.0.0
350 | This line defines the plugin's version. It is purely internal with no rules, and the server will not 351 | try to understand what you are trying to say in the version. Just type whatever you like here as 352 | long as 353 | users and yourself can understand it.
354 |api: 1.13.0
355 |
356 | API means "application program interface". It is basically the things from PocketMine that
357 | lets plugins interact with it. It is like how a microwave oven has buttons to let people adjust
358 | it.
359 | This refers to the minimum API version your plugin supports. You can find the current API version
360 | of your server from the startup messages:
361 |
362 | The first number refers to a complete change in API (major version). The plugin and the server must
363 | have the same number here to be loaded.
364 | The second number refers to additions in the API (minor version). The plugin must have the same or
365 | smaller number here to be loaded.
366 | The third number refers to minor API changes (patches). Any numbers work here, but you should use
367 | the number you tested for.
368 | All these information aside, what you have to know is, you'd better use the number you see in
369 | your server's startup.
370 |
main: FirstPlugin\FirstPlugin
372 |
373 | Here finally comes the part related to the plugin code.
374 | Short and unclear explanation:
375 | This is the fully-qualified name of your plugin's
376 | main class.
377 | This obviously explains nothing to someone who doesn't know what a class is. Let's
378 | just go through step-by-step.
379 |
381 | In PHP (especially in PocketMine-related PHP), code is contained in units called "classes". You can
382 | think a class as a "file" (and it is indeed true that we would normally put only one class in one
383 | file).
384 | And what's even more exciting, since we have files, we have directories (folders) that contain the
385 | files. They are called "namespaces". Actually, we normally put a PHP file with the proper filename
386 | in the proper directory according to their namespace and class name. I said "normally" because it
387 | sometimes works if you don't, but just forget it and assume that it doesn't.
388 | Usually, just like you put similar files in the same directory, we put classes of the same plugin in
389 | the same namespace. We can also have "sub-namespaces" just like we have sub-directories,
390 | but that isn't important; just forget about it.
391 |
393 | By convention, we use Pascal-case for class names. That is, we would
394 | WriteLikeThis
if we all write in Pascal-Case.
395 | Note that you can only use alphabets, the 10 numbers (0-9) and the underscore (_
) in
397 | class names. Also, class names cannot start with numbers.
398 | For namespaces, the same rule applies. However, to create "sub-namespaces", just like file paths
399 | in Windows, we separate two parts by a backslash \
.
400 | Now, to get a fully-qualified name of the class, which is like the full file path
401 | on Windows, we use NamespaceName\ClassName
. In our example,
402 | FirstPlugin\FirstPlugin
is the fully-qualified name of the namespace
403 | FirstPlugin
and the class name also FirstPlugin
.
404 |
406 | So what is a class? We will get it discussed in the next chapter. 407 |
408 |
413 | I have already explained about the meaning of namespaces and classes in the previous chapter -
414 | namespaces are like directories, and classes are like files. But to what extent are they alike?
415 | Files that contain PHP code (source code) are called "source files". In your plugin, source files should
416 | be located inside a directory called "sources root", which should be at ~/src
.
417 | A source file ends with .php
. In front of that, it is the fully-qualified name
418 | of the class inside the source file.
419 | Now we have the fully-qualified name FirstPlugin\FirstPlugin
, we should create
420 | our source file at ~/src/FirstPlugin/FirstPlugin.php
. Simple. What's not so
421 | simple that gave the magical power to plugins is the things inside the file.
422 |
Hold your breath and scroll through all these.
425 | 426 |427 | STOP. Don't copy it into your file. Oh, did I say "just copy"? Forget that. 428 | Instead, try to understand it and write it yourself when you know what you are writing. 429 |
430 |
432 | This line, <?php
, seriously does nothing at all. It doesn't help
433 | you in any ways. It is only here to tell people that this is a PHP file.
434 |
436 | Sadly, the human race is the best species at finding trouble for themselves. We must 437 | put this line at the very beginning of every PHP file, and better on an 438 | independent line. 439 |
440 |
443 | Yes. Honestly. These lines are purely decorative. You can add spaces and tabs and break code
444 | into new lines literally anywhere in your PHP file (but after the
445 | <?php
line!), as long as they don't cut one word into two.
446 | (But it is not reasonable to change function
into
447 | fun ct ion
, is it?)
448 |
450 | Nevertheless, programmers have a general habit of talking things in terms of "lines", but when 451 | we talk about a "line" of code, we generally refer to a statement. I will explain more 452 | about what a statement is later. 453 |
454 |
457 | This is pretty obvious. When discussing the main
attribute in our
458 | plugin.yml
, we have already mentioned that the namespace of this
459 | class is FirstPlugin
.
460 |
462 | We have to declare the namespace in every PHP file, unless it doesn't have a namespace 463 | (but this SHOULD NOT happen in a plugin!). As you can observe, the syntax to declare a namespace 464 | is: 465 |
466 |namespace namespace_for_this_file;467 |
468 | namespace_for_this_file
should be the whole namespace, including the
469 | backslashes (\
) and the subnamespaces.
470 |
472 | Don't forget the semicolon at the end. A rule for PHP is that all statements would end with
473 | ;
(semicolons), unless they end with a {
,
474 | then enclose other lines of code, and finally a }
. (Of course, except
475 | <?php
, which is not code at all)
476 |
'
478 | Keep in mind that the namespace statement must be the very first statement in
479 | every PHP file (of course after <?php
)
480 |
484 | There are two types of use
statements:
485 |
use Fully\Qualified\ClassName;
487 | use Fully\Qualified\ClassName as AnAlias;
489 | Quite self-expanatory, isn't it? Actually, the first type is just a simplified form of the second 490 | type. We can change the first line into:
491 |use Fully\Qualified\ClassName as ClassName;
493 | They basically mean the same thing.
494 |OK. But what are use
statements for?
496 | use
statements tells the PHP compiler that when you later say
499 | AnAlias
in this file, you are talking about
500 | Fully\Qualified\ClassName
. In this way, even though the namespace is
501 | very long, we can use
the class as a short alias. If you don't say
502 | as
what, as in the first type, the PHP compiler will use the
503 | simple class name as the alias. In fact, programmers usually only use the first type to
504 | avoid confusion, unless they are coding something real quickly and short and use
506 | aliases to shorten the class
507 | name (but don't do this in code where you expect other people to read, or yourself to
508 | read after a few months - people will have a hard time understanding it).
509 |
In the dummy class above, we used:
511 |use pocketmine\plugin\PluginBase;
512 |
513 | On line 7, we mentioned PluginBase
, but because of the
514 | use
statement from line 5, it actually means
515 | pocketmine\plugin\PluginBase
rather than merely
516 | PluginBase
.
517 |
519 | Remember that use
statements must be directly after the
520 | namespace
statement.
521 |
523 | Pro tip: apart from class names, use statements can also register aliases for namespaces. This 524 | is handy when you are using a lot of classes from that namespace. 525 |
526 |
527 | For convenience, I am going to refer use
statements as "imports" in the future.
529 |
533 | Now, we have finally come to the most important part of our code. (Actually, the only part that 534 | does something meaningful). 535 |
536 |537 | Before I start explaining what this line (line 7) does, let's have an overview on the syntax of 538 | the PHP language. Yes, an overview, a very brief and general one. Really general one, you'd 539 | probably think that this is useless, but it lets you automatically understand a lot of things 540 | in the future. 541 |
542 |Let's look at this text. Don't worry, it is written in English :)
543 |544 | When a player moves, if he is not an op, teleport him to jail. Take money from him. Send him a 545 | message. When the server stops, if the server owner is not online, notify him. Delete all 546 | worlds. 547 |
548 |
549 | This describes what happens in the plugin in English. I hope that you notice the
551 | ambiguity in this text
552 | I said "Take money from him.", but does this mean take money from him if he is not an op? Or
553 | whenever he moves?
554 | "Delete all worlds.", does this happen only if the server owner is not online, or whenever the
555 | server stops?
556 | To clarify my meaning, let's format my text into this:
557 |
559 | When a player moves: 560 | { 561 | If the player is an op: 562 | { 563 | Teleport him to jail. 564 | Take money from him. 565 | } 566 | Send him a message. 567 | } 568 | When the server stops: 569 | { 570 | If the server owner is not online: 571 | { 572 | Notify him. 573 | } 574 | Delete all worlds. 575 | } 576 |577 |
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,
579 | this is how PHP understands what you say.
580 |
583 | In the PHP syntax, it main consists of two compoenents - statements and statement
584 | groups.
586 | A statement is like a sentence saying what to do, like "Teleport him to jail". Just like how
587 | we end every sentence in English with a full stop .
, we end every
588 | PHP statement with a semicolon ;
.
589 |
591 | A statement group consists of a line that explains what this statement group is about, then
592 | followed by a group of statements. For example, in the text above, "When the server stops"
593 | explains what the following group of statements is about.
594 | Yes, a statement group is a statement too. Therefore, we can have a statement group inside a
595 | statement group.
596 | Usually, a statement group looks like this:
597 |
599 | group_type{ 600 | many statements; 601 | and nested statement groups{ 602 | here; 603 | } 604 | } 605 |606 |
607 | Sometimes, group_type
can contain more information than merely the
608 | group type. Let's go back to our dummy class for an example.
609 |
This was our class
statement group:
613 | class FirstPlugin extends PluginBase{ 614 | # some code was here 615 | } 616 |617 |
618 | This declares a class called FirstPlugin
. we have
619 | previously decided that our fully-qualified class name should be FirstPlugin\FirstPlugin
, where the first FirstPlugin
is the namespace and the second FirstPlugin
623 | is the simple class name. We have already declared the namespace for this file on line 3, so we
624 | don't need to mention it again.
625 |
627 | The next part of this line says that the class FirstPlugin
628 | extends PluginBase
. What does that mean?
629 | Remember what we did on line 5? PluginBase
actually means
630 | pocketmine\plugin\PluginBase
, which is a class provided by PocketMine
631 | itself.
632 |
634 | So what? What does this class do? What is meant by extends
?
635 |
637 | The concept of "extend" is more complicated. But for the moment, you can assume that it means 638 | that this class is the main class of a plugin.
639 |640 | There are two types of statements inside a class. They are class properties and 641 | functions. Class properties are the "memory" of a class, but you can ignore that for 642 | the moment. We are going to talk about functions first. 643 |
644 |
647 | function
is another kind of statement group. It declares a
648 | function.
649 |
Have you ever learnt functions from mathematics? OK, if you haven't, learn it now.
652 |
653 | A function is like a crafting table. You add ingredients (parameters/arguments)
654 | into it, and it will give you some product (return value). Furthermore, the
655 | order of how you put the input matters.
656 | For example, you have three diamonds and two sticks. If you put the three diamonds on the
657 | top, you get a diamond pickaxe. But if you put one diamond on the side of the middle, you
658 | get a diamond axe.
659 | The same thing goes to functions. A function accepts some arguments (sometimes none,
660 | though). It expects each argument to be something. For example, a function that sets a block
661 | in a world would accept two arguments, the first argument being the position to change, and
662 | the second argument being the type of block to change into.
663 | Functions are also like commands. Say, the /effect
command. You
664 | have to provide a player in the first argument. The second argument is the effect type. You
665 | can optionally also provide the third and fourth argument for duration and amplitude, but
666 | the command will assume default values for you if you didn't provide them.
667 |
670 | Just like commands, apart from arguments and return values, a function also has a name,
671 | description and permission, although we instead call description
672 | documentation and permission visibility.
673 | The function's name has the same rules as classes, except that it starts with a
674 | small letter
675 | instead of a capital letter. That is, we use camelCase
rather than
676 | PascalCase
.
677 | There are three types of visibility for a function, namely public,
678 | protected and private. Public functions can be used from anywhere. Private functions
681 | can only be used when you are writing code from that class. As for protected functions, they are
682 | like private functions, but also accessible by subclasses. What are subclasses? You
683 | won't need to know that until you are making really complicated or high-quality plugins (e.g.
684 | SimpleAuth).
685 |
687 | When a function is inside a class, we also call it a "class method". 689 | But let's call it "function" to avoid confusion. 690 |
691 |As you may have already noticed, this is the syntax of declaring a function:
692 |693 | function_visibility function function_name(arguments){ 694 | code_inside_the_function 695 | } 696 |697 |
For instance:
698 |699 | public function myFunction($arg1, $arg2){ 700 | // some code here 701 | } 702 |703 |
704 | You might be asking what the //
means. It is the line comment
705 | symbol. This means that everything on that line after the //
will
706 | be ignored. This is useful when you want other people, or yourself a few months (or a few days)
707 | later to easily understand what you are writing.
708 |
715 | Server: chat.freenode.net:6667
716 | Private message: PEMapModder
717 | Channel: #pmplugins
718 |
This page is mainly authored by PEMapModder,
733 |
734 | This webpage uses the highlight.js
735 | library (and its rainbow theme) for syntax highlighting.
736 |