Spigotプラグイン作成の流れと、Eventを扱ってみる

前回作成したプラグインはゲーム内で確認できる機能がありませんでした。

今回は、もう少し実用性のプラグインの一例として「Event」という仕組みの使い方を紹介していきます!ついでに、私がプラグイン作成するときのフローも合わせて紹介します。

目次(制作のフロー)

計画する#

まずはどんなプラグインを作りたいか考えます。
一番考えやすいのは、トリガーと処理に分けて考える方法です。
つまり、「〜が〜をした時に」「〜をする」と分けて考えます。

今回は、へくしょんさんの企画「シノビロワイヤル」にも使用している、短縮チャット機能の簡易版を作ってみましょう。

例えばですが、プレイヤーがチャット欄で「hello」と送った時に「こんにちは、<プレイヤーの名前>です!」に置き換えて送信する、という処理を作りたいとします。

その際、トリガーは
「プレイヤーがチャットをする」という動作

処理は、

①「そのチャットの内容が”hello”かチェック」

②「プレイヤーの名前を取得し、文を成型し、チャットの内容を置き換える」

という流れになります。

コードを調べる#

私がいつも使うのは、Spigotの公式ドキュメントです。

このサイトにはSpigotのプラグインに使える全ての情報が書いてあります✨

トリガーを調べる#

今回のように、何かをトリガーにする際、その動作が起きたことを検知するために使うのがEventというシステムです。

私のプラグインでも毎回使っています!

ページにアクセスすると下の画像のようになっています。

このページのDirect Known Subclassesというところに、プレイヤーやブロックなどとジャンル分けされたEventが並んでいます。

今回はプレイヤーに関するEventなので、PlayerEventを確認します。

ここにも、Direct Known SubclassesというところにPlayerから始まる、より細かいEventが並んでいます。チャット欄で話したことを検知したいので、AsyncPlayerChatEventを使用します!

処理を調べる#

さきほどのAsyncPlayerChatEventのページを少し下にスクロールすると、Method Summaryという項目があります。

この部分に、利用できるメソッド(関数、処理)がずらっと書いてあります。左から、Modifier and Typeがその関数の返り値のデータ型、Methodが関数名(Methodの括弧内はその関数の引数のデータ型と名前)、Descriptionがその説明です。

今回使うのはハイライトしてあるgetMessage()、setMessage()、getPlayer()です。

先ほど、行いたい処理は、

①「そのチャットの内容が”hello”かチェック」

②「プレイヤーの名前を取得し、文を成型し、チャットの内容を置き換える」

と書きましたが、

「チャットの内容が”hello”かチェック」するためにgetMessage()してチャットの内容を取得、

「チャットの内容を置き換える」ためにsetMessage()します。

プレイヤーの名前を取得するためには、まずgetPlayer()でプレイヤーを取得、そしてgetDisplayName()でプレイヤーの表示名を取得します。

プレイヤーに関してできる処理はPlayerのMethod Summaryを見るとたくさんあります🏃‍♀️

体力/空腹度を変更・テレポート・アイテム付与・ゲームモード変更…など色々あるので見てみてください!

今回の表示名取得は、ハイライトされているgetDisplayName()です。

コードを書いていく#

さて、トリガーや処理などを色々調べてきましたが、情報がそろったのでそろそろコードを書いていきましょう!

前回同様、まずはIntellij IDEAでプロジェクト作成をし、もしプラグイン名が「Testplugin」だとすると、

1
2
3
4
5
6
7
8
9
10
11
12
public final class TestPlugin extends JavaPlugin {

@Override
public void onEnable() {
// Plugin startup logic
}

@Override
public void onDisable() {
// Plugin shutdown logic
}
}

ここまで自動で書かれている前提で話します。

まずはextends Javapluginと{の間に以下を追記します。

1
implements Listener

すると以下のようにListenerに赤い下線がひかれると思います。

なので「Listener」にマウスをのせ、「Alt+Enter」を押します。そしてImport classをクリックします。

そして「Listener(org.bukkit.event)」をクリックします。

すると必要なorg.bukkit.event.Listenerがインポートされます。

次にonEnable()の関数の中に以下の処理を入れます。これによりイベント処理を行えるようになります。

1
getServer().getPluginManager().registerEvents(this, this);

そして、onDisable()の関数の下に以下の関数を追記します。

1
2
3
4
5
6
@EventHandler
public void onChat(AsyncPlayerChatEvent event) {
if(event.getMessage().equals("hello")){
event.setMessage("こんにちは、"+event.getPlayer().getDisplayName()+ "です!");
}
}

「AsyncPlayerChatEvent」という部分も赤い下線が出るので同様に「Alt+Enter」でインポートします。

では、この関数で何をしているか解説していきます。

まず最初の@EventHandlerは続く関数がEventを使用しているよ!と示すものです。

そして次のpublicは外からでも見える、 voidは戻り値が無いことを示します。ここまでは何も考えずに書いておけば大丈夫です。😂

onChatの部分は関数の名前です。実際何でもよいですが、on+処理の概要が(慣例として)一般的に使われています。

そのあとに続くカッコ内()にはEventの正式名(クラス名)、関数内で使用するeventの変数名を書きます。

Eventの正式名はハイライトされた部分どちらかをコピペすれば正確です。 変数名は何でもよいですがeventやeが一般的で、何の変数かわかりやすいです。

関数内はこうなっていますね。

1
2
3
if(event.getMessage().equals("hello")){
event.setMessage("こんにちは、"+event.getPlayer().getDisplayName()+ "です!");
}

いろいろ「.」で繋がっていますが、このように繋げる(パイプ処理)と、いちいち結果を変数に格納しなくて済むので見た目がすっきりします😎

まずifの条件を見ます。まず小文字のeventはEventが格納された変数です。それにドットで挟むとEventに対して行う処理を繋げて書くことができます。さらにequals(“文字列の内容”)で、event.getMessage()と”文字列の内容”が等しいかどうかをチェックします。

つまり、以下と同じです。

1
if(event.getMessage() == "hello")

もし、そのEvent(チャット)のメッセージ内容が”hello”なら、true、異なるならfalseです。trueならカッコ内の処理が実行されます。

“hell”でも”helloo”でも、異なるのでfalseです。正確に”hello”の時のみtrueになります。

メッセージが”hello”のときに実行されるのが以下の処理です。

1
event.setMessage("こんにちは、"+event.getPlayer().getDisplayName()+ "です!");

event.setMessage(“メッセージ内容”)は送られるメッセージの内容を書き換える処理でしたね。

何に書き換えているかというと、

「こんにちは、」という文字、プレイヤーの表示名、「です!」という文字を連結したものに置き換えています。

プレイヤーの名前を取得するために、eventからgetPlayer()でプレイヤーを、プレイヤーからgetDisplayName()で表示名を取得しています。

この処理を分けて書くと以下のように長くなります。

1
2
3
4
Player player = event.getPlayer();
String name = player.getDisplayName();
String message = "こんにちは、"+name+ "です!"
event.setMessage(message);

短いのがいい人もいれば、長いけどわかりやすくてこっちがいいって人もいると思います。そこは好みのほうで書けば大丈夫です👌

応用編#

“hello”以外にも、以下のようにif文を繰り返せば短縮コマンドを増やすことができます。

1
2
3
4
5
6
if(event.getMessage().equals("短縮コマンド1")){
event.setMessage("コマンド1の代わりに送信される文");
}
if(event.getMessage().equals("短縮コマンド2")){
event.setMessage("コマンド2の代わりに送信される文");
}

また、今までの処理はメッセージが指定した文字列に完全に一致しているのが条件でしたが、

もし文中のある文字を入れ替えたいのであれば、以下のような処理で実装できます。

1
2
3
4
5
6
7
8
String message = event.getMessage();
if(message.contains("置き換え前の文字列1")){
message = message.replace("置き換え前の文字列1", "置き換え後の文字列");
}
if(message.contains("置き換え前の文字列2")){
message = message.replace("置き換え前の文字列2", "置き換え後の文字列");
}
event.setMessage(message);

contains(“含むか判定する文字列”)は含んでいるとtrueを、含まないとfalseを返します。

replace(“old”, “new”)で、文字列中の全ての”old”を”new”に置き換えることができます。

ビルドする#

ウィンドウ右上の緑の▶ボタンをクリックしてビルド開始。

エラーがあればウィンドウ下部のコンソールにエラー内容が出るので修正後、ビルドしなおしましょう。

(次の記事からはビルド方法は省略して大丈夫ですよね?😅)

ビルドされたjarファイルは[プロジェクトフォルダ]\プラグイン名\targetフォルダ内にあります。

動作テストをする#

Spigotサーバー内pluginsフォルダにjarを配置し、サーバーを起動します。

Minecraftを起動し、正常に動作するか確認しましょう。

このように自己紹介文が送信されれば成功です!

不具合対応#

では、もし正常に動作しなかったら…?😨

1
Bukkit.getLogger.info("ログ出力したい文");

このような処理を入れるとサーバーのコンソールにログが流れるので、これを活用するなどして不具合が出ている箇所を特定し、修正します☠

まとめ#

今回はチャット検出のEventを例に挙げましたが、ほかにも様々なEventがあります。今後少しずつ紹介していく予定です。

気になる機能があればTwitterなどで言っていただければそちらも記事にします!

次の記事としてはコマンドをトリガーに使用する方法を予定しています。お楽しみに。😊