【Minecraft】(Java未経験者対応)Bukkit/Spigot対応プラグインの作り方講座【基礎編②】
閉じる
閉じる

新しい記事を投稿しました。シェアして読者に伝えましょう

×

【Minecraft】(Java未経験者対応)Bukkit/Spigot対応プラグインの作り方講座【基礎編②】

2016-02-17 13:04
  • 2
今回は、実際にコマンドを実装し、自分にアイテムを渡すプラグインを作成します。
基礎編①で記述した public int a = 3; や、onCommand()の中身はもう使わないので、1回消して下画像のような、準備編の状態に戻してしまいましょう。




1.コマンドの実装
Bukkit/Spigotには、コマンド操作を受け付けるためのプログラムが予め用意されているので、それを作るプラグインに実装してあげます。
実装はとても簡単です。

TutorialPlugin.javaの8行目の
public class TutorialPlugin extends JavaPlugin {
に、以下のように書き加えます。
public class TutorialPlugin extends JavaPlugin implements CommandExecutor {
これだけです。

Bukkit/Spigotには、コマンドを制御するクラスの仕様書である「CommandExecutor.class」が用意されており、この仕様書を使いますよ~ということを示す宣言をクラス宣言の部分に書き加えました。
このように、仕様書をクラスに用いる宣言をすることを実装(implements)といい、この仕様書(ここではCommandExecutor)のことをインターフェースと呼びます。

ちなみに extends JavaPlugin という文章もありますが、実はここではBukkit(Spigot)に用意されている「JavaPlugin.class」の機能を全て使わせていただきますという意味になっています。
CommandExecutorとJavaPluginの大きな違いは、前者が仕様書であるのに対し、後者は完成されているプログラムの一部であるということです。
このような、完成されたクラスの機能を引き継ぐことを継承(extends)といい、継承元であるJavaPluginのことをスーパークラス(親クラス)、継承先であるTutorialPluginのことをサブクラス(子クラス)といいます。

実装(implements)は、
public class classA implements classB, classC, classD ... {
のように、1つのクラスに複数のインターフェースを実装することができますが、
継承(extends)は、
public class classA extends classF {
のように、1つのクラスに対して、1つのスーパークラスしか継承することができません。

この継承と実装をどのように使い分けるかについては詳しい説明は省きます。


さて、implements CommandExecutor と記述したら、なんだか赤い波線が引かれてしまいました。

この赤い破線にマウスカーソルを持って行くと、
「CommandExecutorを型に解決できません。」と表示されるのではないかと思います。

これは「CommandExectorって何ぞや、ワイそんなん知らんで」
ということを暗に示しています。
実は、JavaPluginやCommandExecutorなど、他のプログラムを借りる際には、そのプログラムの場所を教えてあげなければいけません。
実は、JavaPluginは既にその記述がされていて3行目に書かれている
import org.bukkit.plugin.java.JavaPlugin;
がそれにあたります。このように、プログラムの場所を示してあげることをインポートといいます。
基本的に、同じパッケージに含まれていないクラスは全てインポートしてあげなければプログラムは正常に動作しません。なぜならば、プログラムには違うパッケージの中に同じ名前のクラスが存在する可能性があり、その場合、どちらのパッケージのクラスを使うのが正しいのか分からなくなっていしまうからです。

例えば、この後でてくるItemStackというクラスは、
net.minecraft.server.v1_8_R3 というパッケージと
org.bukkit.inventory というパッケージにそれぞれ1つずつ入っています。
この時、import文がないと、どちらのパッケージからプログラムを借りてくればいいのか判別できずに、エラーになってしまうのです。

CommandExecutorも、Spigot自体には1つしか存在しませんが、仮にもし別のプラグインのパッケージの中にCommandExecutorというクラスが入っていたら、競合してしまいます。だからクラスが1つしか存在しなくても、import文が必要なのです。

CtrlとShiftキーを押した状態でOキーを押すと、自動的ににクラスを探してインポートしてくれます。この時、ItemStackのように、同じクラスが複数のパッケージで見つかった場合は、どれを使いますか?と出てくるので、選択してあげれば良いだけです。
赤い破線が消えたら、次のStepに進みましょう。


2.処理の記述
CommandExecutorは仕様書なので、実装しただけでは何も起こりません。
コマンドを受け付けるためには、コマンドを受け付けた際の処理を書かなければいけないので、それを記述していきます。

メニューバーから ソース -> メソッドのオーバーライド/実装 を選択し、
onCommand() にチェックを入れてOKをクリックします。


すると、プログラムに以下のメソッドが記述されます。
@Override
public boolean onCommand(CommandExecutor sender, Command command, String label, String[] args) {
  return super.onCommand(sender, command, label, args)
}
メソッドの宣言の仕方は前回やったとおりですね。この関数は
戻り値(計算結果)としてboolean型(trueまたはfalse)を算出する。
引数は
CommandSender型(変数名:sender)
Command型(変数名:command)
String型(変数名:label)
String[]型(変数名:args)
の4つです。

このメソッドは、コマンドを受け付けた時に自動的に実行されます。
senderには、コマンドを使った人の情報
commandには、コマンドの情報が入ります。

labelとargsには、実際にコマンドの内容が入ってきます。例えば
/give player diamond 1
というコマンドを受け付けた場合、最初の"give"がlabelに格納されます。
残りの"player", "diamond", "1"はargsに全て入ります。
[]というのは配列を表します。
配列はある特定の型をいくつも入れることができるまとまった箱のことで
String[] というのは、String型の変数がいくつか入った箱ということを表します。
箱の最初からn番目の内容を取り出したいときは
変数名[n-1]
と記述します。[]内の数字は0から始まるので、3番目の箱から取り出す際には[2]としなければなりません。
上記の場合args[0]に"player"、args[1]に"diamond"、args[2]に"1"が格納されます。

今回は、コマンドが受け付けられるかどうかの確認のため、コマンドを使った人にメッセージを送るよう処理してもらいます。
以下の画像の通りに、メソッドの中身を書き換えてください。
return super.onCommand(sender, command, label, args); は、
return false; に書き換えてください。



3.コマンドのロード
処理を書くことで、コマンドを受け付けた際の処理を書きましたが、実はプラグインをロードする際、Spigotサーバーに、このコマンドを受け付けたらこのプラグインで処理しますよ、ということを教えてあげなければいけません。
そこで、onEnable()メソッドに
getCommand("コマンド名").setExecutor(this);
と記述します。コマンド名は他のプラグインと競合しないように注意しなければなりません。
thisというのは、自分自身のこと、つまりTutorialPluginのことを指しています。
指定したコマンドを受け付けたら、私が処理するようセットするということですね。

今回はコマンド名を /tutorial にすることとします。最初の/は省いて記述します。
onEnable()メソッドは以下のようになります。



また、プラグインの使用書であるplugin.ymlにも、コマンドについて教えてあげなければいけませんので、plugin.ymlを開きます。


4行目~8行目に追加します。
5行目は頭に半角スペース2つ
6~8行目は頭に半角スペースを4つを入れないと、起動時にエラーが出てしまいます。
追加したら、上書き保存します。




4.動作確認
では、完成したプラグインをエクスポートしてサーバーを起動します。
サーバーを起動したらMinecraftでサーバー内にログインし、/tutorialと打ってみましょう。

このように、「コマンドを受け付けました!」という文章と、「/tutorial」という文章が表示されると思います。

こうなれば正常にプラグインが作成されていますので次のStepに移ります。
サーバーは一旦終了しましょう。

5.プレイヤーにアイテムを渡す
では、まずは/tutorialと打ち込んだプレイヤーにダイヤモンドを渡すプラグインを作ります。

Step1:コマンドの使用者がプレイヤーであるかどうかを確かめる

31行目、33行目を追加します。
if(!(sender instanceof Player)) return false;
ここでは、コマンドの送信者がプレイヤーであるかどうかを確かめています。
コマンドは、Minecraftのゲーム上でプレイヤーがコマンドを打ち込む場合と、コンソール上にコマンドを打ち込む場合とがあります。
アイテムはプレイヤーにしか渡せませんので、今回はコマンドの送信者がプレイヤー(Player型)でなかった場合はコマンドの実行を異常終了させてしまいます。(return false;)

この処理が通ったら、プレイヤーデータを格納するPlayer型の変数を用意し、初期値としてコマンド送信者を代入します。
ただし、senderはCommandSender型の変数で、Player型に直接代入することができません。そこで、
(Player)sender;
と記述します。これは、CommandSender型の変数senderを、Player型に変換してねという意味です。「(変換したい型名)変換したい変数」のように記述することをキャストといいます。ただし、Itemデータが格納されている変数を無理矢理Player型にキャストするといったようなことはできません。あくまで、型変換ができるのは数が限られており、CommandSender→Playerへの変換は可能であるから使用できるということです。


Step2:アイテムを用意する

35行目を追加し、赤い破線が引かれたのを確認し Ctrl+Shift+Oを押します。
ItemStackクラスとMaterialクラスは2つあるので、どれを選択しますか?ときかれます。

まずItemStackは org.bukkit.inventory.ItemStack をダブルクリックします。


次にMaterialは org.bukkit.Material をダブルクリックします。


ItemStack item = new ItemStack(Material.DIAMOND);
ItemStack型の変数itemを用意し、初期化の宣言をしています。
new ItemStack(Material.DIAMOND);
とは、ダイヤモンドアイテムデータの含まれるItemStack型の値を新しく作成するといった意味合いです。
これをインスタンスの生成と言ったりしますが、これについての詳しい解説は少し先になると思います。


Step3:アイテムを渡す命令文を作成

39行目を追加します。また、41行めの false を true に変更します。
player.getInventory().addItem(item);
この命令文は2つの命令を組み合わせたものになっています。
player.getInventory()
Player型の変数playerに入っているプレイヤーデータから、インベントリのデータを取り出してこいという命令文です。これに従って、プレイヤーのインベントリデータが抽出されます。

addItem(item);

抽出されたインベントリデータの中に()内のアイテムを追加しろという命令文です。
()内にはItemStack型の変数itemが入っているので、先ほど用意したダイヤモンドのデータが入ったアイテムを渡すことになります。

また、最後のreturn false;をreturn true;に書きかえました。
このメソッドは戻り値にbooleanが指定されているので、関数の実行終了時(計算の終わり)にtrueかfalseを返してあげなければなりません。
onCommand()メソッドでは、コマンドの処理が正常に終了した際にはtrueを、正常に終了しなかった場合にはfalseを返すようになっています。
falseが返されると、plugin.ymlに指定した usage: の文章が表示されます。
usageには usage: /<command> と記述されているおり、先ほどのコマンド動作確認の際にfalseが戻された際に /tutorial と表示されたわけです。
(<command>の部分にはコマンド名が代入されるようになっています)

6.動作確認
作成したプログラムを再度エクスポートし、サーバーを起動します。
Minecraftを起動し、/tutorialと打ち込みましょう。


「コマンドを受け付けました!」というチャットと同時に、手元にダイヤモンドが入ってくれば成功です!

次回はいよいよ本格的なプログラムになっていきます。
次は条件分岐(if文、switch文)について解説しながら、コマンドによって渡すアイテムを変えるプラグインを作りたいと思います。



7.よくある質問

①次のエラーが表示され、プラグインが動作しない
Error occurred while enabling TutorialPlugin v1.0.0 (Is it up to date?)
java.lang.NullPointerException

ガッ
有名なぬるぽエラーです。plugin.ymlに記述されたコマンドが見つからないのでエラーになってしまっています。
plugin.ymlに記述した tutorial のスペルが間違っているか
getCommand("tutorial").setExecutor(this); の tutorial のスペルが間違っています。


②次のようなエラーが表示される


plugin.ymlの半角スペースの数が正しくなかったり、全角スペースがどこかに入っていたり、
: が必要な箇所に入っていない、あるいは余分な場所にあったりするとこのようなエラーがでます。
もう一度上にあるplugin.ymlの画像を見直し、入力ミスがないか確認しましょう。



広告
×
JavaPluginはもともとCommandExecutorを実装してるのでTutorialPluginには実装しなくていいと思うのですが...
39ヶ月前
×
ナルホドワカラン
もう1回見てきまーすw
11ヶ月前
コメントを書く
コメントをするには、
ログインして下さい。