こんにちは(?)。今回はプラグイン講座2回目ということで、実際にコードに触れながら、”どのように“コーディングしていくのかを勉強していこうと思います。

まずは環境の確認から。

サーバーが一度でも起動すると、前回作ったフォルダの中は以下の画像のようになると思います。

この状態でならしっかり起動すると思います。
それでは、ここからプラグイン開発者への第一歩を踏み出しましょう。

DevToolsの導入

DevTools.pharはプラグインです。
そのため、pluginsフォルダ内に入れないと動作しません。
とりあえず放り込みましょう。

起動した後、コンソールに 「plugins」 と打ち込むと、しっかり読み込まれているのがわかると思います。

これでプラグインを開発するための準備が整いました。
それでは早速作っていきましょう。

と、言いたいところだが...

この記事をだらだら書いているうちに、1.5.3から1.6.0へMinecraftがアップデートしてしまったので、PocketMine-MP.pharの更新が必要になりました。
最新版はこちらからダウンロードできます。
ダウンロードしたら、サーバーフォルダの中にあるPocketMine-MP.pharを新しくダウンロードしたものと置き換えてください。
サーバーのバージョンが 3.2.x (xは数字) になっていれば Minecraft 1.6.0 でサーバーに入ることが出来ます。

何を作る?

まず、プラグインを作るときに何を作りたいのか構想を練ります。
「ブロックの名前を見たい」、「ゾンビを動くようにしよう」…などなど。

今回は、初回なので簡単なメッセージプラグインを作りましょう。
プラグインの仕様は以下の通りです。

  • "プレイヤーがサーバーに入ってきたとき"に、「○○さんが参加しました!」と表示する

これだけ?と思ったら、次の記事を待っている間に他の方が書いたプラグインを眺めてみてください。いろいろ発見があると思います。

プラグイン開発開始

まずは、DevToolsが何をしてくれるか思い出してください。

DevToolsは、「ソースコードのままプラグインとして読み込んでくれるスグレモノ」でした。
つまり、DevToolsが私達が書いたプラグインを読み込んでくれるように、プラグインの構造、pharの中身を知る必要があります。
pharは解凍、圧縮が簡単にできますが、それについては今後説明します。

プラグインのフォルダを作る

サーバーフォルダ内の、DevTools.pharが入っているpluginsフォルダ内に、プラグイン名のフォルダを作りましょう。
今回は入るときにメッセージを出すプラグインなので、「JoinMessage」としておきます。

次に、JoinMessageフォルダ内で「plugin.yml」ファイルを作ります。
内容は以下のように書きます。

各要素の解説です。
name: プラグインの名前

main: 核となるファイルの場所
今回は私は fuyutsuki なので「fuyutsuki\JoinMessage\Main」とします。

version: プラグインのバージョン

api: 対応しているpmmpのバージョン
例えば、pmmp v3.0.11に対し api 3.0.0のプラグインは読み込めます。
しかし、pmmp v3.0.7に対し、api 3.0.8のプラグインは読み込めません。
つまり、apiの欄には対応したいpmmpのバージョンと同じか、それ以下のバージョンを書けば読み込むことが出来ます。


author(省略可): 開発に携わった人の名前

それでは、mainの部分に書いた通りにフォルダを作ります。
今回は上記で但し書きした通りに、「fuyutsuki\JoinMessage\Main」にphpファイルを作ります。

src フォルダ???と思った人はよく見ていると思います。
srcとは、source (英語: ソース, 訳: 出典、出処など)の略称で、pmmpのプラグインを開発している方々の間でよく使われます。

「それのソースコード見せて」、と言われたらpharファイルではなく、phpファイル(つまり、コードがすぐ見れる状態)で送るのが適切ですね。

脱線しましたが、Main.php まで作れたと思います。
この状態ではもちろんエラーしか出ず、読み込んでくれないので Main.phpを編集していきましょう。

Main.php ファイルをコーディング

Main.phpファイルには今のところ何もありませんが、とりあえず以下のコードをコピーしてご自分のファイルに貼り付けてみてください。

pmmpを起動すると、もう読み込めているのが分かります。

もちろんながら、これではただ読み込めているだけです。
次は、Mainクラスに継承させたPluginBaseクラスを見てみましょう。
PluginBaseクラスは、pmmpのsrc(= ソースコード)を見れば出るので、PocketMine-MPのリポジトリをGitHubに見に行きます

それでは、PluginBaseクラスを探してみましょう。

pmmpもsrcフォルダがあって、その中に…

プラグインのuseで使うパスはsrcフォルダ内の構造と同じ…

見つかりましたか?
PluginBaseはここにあります

私達は、PluginBaseを継承したMainクラスを作ったので、PluginBaseに書いてある関数を自由に使うことが出来ます。
実際にやってみましょう。PluginBaseに書いてある関数、getName()を使います。

この関数を見てみましょう。
まず、@return string とあります。
stringとは文字列型のことで、’日本’、”あいうえお” などの文字列を指します。そのままですね。
つまり、この getName() という関数は文字列を取得することが出来ます。
また、関数の名前、getName からも分かる通り、恐らくプラグインの名前を取得できるんだろう、と予測することが出来ます。

そこで、それを踏まえて次の例を見てみましょう。
またコピーして貼り付けてみてください。

この例では、PluginBaseに書いてある関数、onEnable() を上書きして実装しています。
onEnableの名前からも分かる通り、プラグインが有効になったときにこの関数が呼び出されます

また、その関数の中で
$name = $this->getName();
var_dump($name);
としています。

まず、$name というのは変数です。
これは、値を保持できるファイルだと思ってください。

 

次に、name という名前のファイルに $this->getName() で取得した文字列を代入しています。

$this->getName() は、先程のgetName関数を呼び出すためのコードです。
$this は、自分自身、つまりこのコードを実行している Mainクラスということになります。
しかし、MainクラスはPluginBaseクラスを継承しているため、MainクラスにgetName関数がなければ、PluginBaseクラスにgetName関数を探しに行きます。

最後に、var_dump($name); とありますが、これは $name に代入した値を出力する PHP標準の関数です。
関数の引数(ひきすう = 関数に渡す、カッコの中の値や変数)は、$name を入れている為、先程取得した文字列がvar_dump関数の引数として使われます。

それでは、実際の処理を見てみましょう。
pmmpを起動してみてください。

Enabling JoinMessage v1.0.0
の後(= プラグイン有効時)にしっかりgetNameで取得した文字列、”JoinMessage”が取得、var_dump()で出力できていますね。

本題:JoinMessage

それでは、基礎を押さえたところで実際に今回作るプラグインのコードを書いていきましょう。
仕様は以下の通りでした。

  • "プレイヤーがサーバーに入ってきたとき"に、「○○さんが参加しました!」と表示する

まず、「“プレイヤーがサーバーに入ってきたとき“」呼び出されるpmmpの関数を見つける必要があります。
今回は、pmmpが用意してくれたイベントリスナーを使います。
イベントリスナーとは、プレイヤーやサーバーの動きに応じてイベントを発生させて、そのイベントが起きたときに特定の処理を実行させることができるものです。

今回は「”プレイヤーがサーバーに入ってきたとき”」なので、こちらの、\pocketmine\event\player\PlayerJoinEvent を使います。

イベントリスナーの使い方

イベントリスナー(EventListener)は、Listenerインタフェースを実装したクラスで使用することが出来ます。

インタフェース(interface)は、関数の実装を強制することができるものです。
例えば、
interface Humanで、run関数の実装を強制した場合、

class Tanaka implements Human
(= TanakaクラスHuman実装する)

としたときにTanakaクラスでrun関数を実装しなければエラーが出るようになります。

ということで、イベントリスナの使い方をお教えします。
以下のコードをご覧ください。

まず、先程の説明であった通り、
class Main extends PluginBase implements Listener
(= MainクラスPluginBase継承し、Listener実装する)

とし、MainクラスにListenerを実装させます。
ですが、Lisnterインタフェースは実装する関数がないので、実装しなければならない関数はありません。

次に、onEnable(プラグイン有効時に実行)関数の中で、
$this->getServer()->getPluginManager()….
と、つらつら書いてありますが、これの意味を説明すると、

このクラス($this)からServerインスタンスを取得(getServer())し、
ServerインスタンスからPluginManagerインスタンスを取得(getPluginManager())、
PluginManagerインスタンスに実装されているregisterEvents関数を実行しています。

registerEvents()は、イベントリスナーとして、このクラスをサーバーに登録し、今回書いたPlayerJoinEventが発生したときに***Eventのみを引数に持ったプラグインの関数を呼び出してくれるようにする関数です。

とりあえず、動作するかどうか確かめるためにMain.phpにコードをコピー&ペースト(以後”コピペ”といいます)してみてください。

スクショのように、プレイヤー名を取得できていれば成功です。

今の状態だと、
〇〇 joined the game
という素っ気ない英語のメッセージが出ていますが、これを変更しましょう。

ここで、PlayerJoinEventに実装されている(= 使える)関数を見てみます。

すると、setJoinMessage()という関数を見つけることが出来ます。
関数名的に、参加時のメッセージを設定する関数だな、と予想が付きます。

それでは、この関数を使ってみましょう。
まず、関数が public (= 公開されている)で、プラグインから呼び出せることを確認します。

次に、引数を確認します。
PHPDoc (関数の上のコメントアウトされている部分)に、
@param string|TextContainer $joinMessage
とあります。
これは引数の型、変数名を表しています。
今回は簡単な文字列型、string型を使います。

前のコードと変わっているのは、onJoin関数の最後の行、18行目がvar_dump関数から$event->setJoinMessage()となった部分ですね。

まず、PlayerJoinEventのsetJoinMessage関数に、取得した名前を引数として渡します。
$event->setJoinMessage($name);
これだけだと、参加したとき名前だけ表示されるのは目に見えます。
私達が表示したいのは、
〇〇さんが参加しました!
というメッセージです。

つまり、変数 $nameと、文字列 “さんが参加しました!”
を連結してやれば望み通りのメッセージが出せますね。

そこで、上のコードでは結合演算子(. = ドット)を用いて変数と文字列を連結しています。

それでは、本当に望み通りのメッセージが出てくるか試してみましょう。

確かに望み通りのメッセージが出ました!

仕上げに

今、このプラグインはDevToolsを使って読み込んでいます。
つまり、他の人に配布するときにも相手がDevToolsを使っていなければ読み込んで使ってもらうことが出来ません。

そこで、プラグインが完成したら pharファイルに圧縮して、DevToolsなしでも読み込めるようにします。

やり方は簡単で、DevToolsと圧縮したいソース状態のプラグインを入れてからサーバーを起動して、
makeplugin 〇〇(プラグイン名)
とするだけです。
完成すると、pluginsフォルダ内のDevToolsフォルダにプラグイン名.pharが出来上がっています。

〆(締め)

プラグイン開発は、基本的にはPMMPのAPIを叩く(呼ぶ出す)だけ、というのがわかったでしょうか。
そこまで難しいものではないので、尻込みしないで挑戦してもらえると幸いです。
また、今回は分量が多めになってしまったので、ちょっと読みづらかったかな、と反省しています。
なにか誤字脱字などなどありましたらコメントやTwitterでリプライお願いします。
お疲れ様でした。

次回までの宿題: 参加したときだけじゃなく、退出したときのメッセージも変えてみよう

次回予告: 他の人のプラグインを読んでみよう