[MineCraftプラグイン]コマンドを受け付けてイベントを発生させる

## 前提条件
[Eclipseを用いたSpigotプラグイン作成](https://qiita.com/kubo_programer/items/314134851766844342ee)で作成したプラグインに追加する形でプラグインの開発を行なっていきます．

## STEP1: 基本的なコマンドの実装
### plugin.ymlの設定
自作プラグインのコマンドがコマンドに応答する機能を追加するために`plugin.yml`の編集を行います．

```yml
command:
  コマンド名:
    description: コマンドの概要をここに記載します
    usage: コマンドの使用方法の記載
```
- description – コマンドの説明文.
- usage – コマンドの使い方.もし,ここで onCommand() でfalseを返したときにこの使用方法が表示されます．

ここでは基本的な要素しか追加していません．
`description`,`usage`以外を追加する事で色々いじる事が可能です．他の詳しい設定を行いたい場合は[このサイト](https://mcmodding.jp/modding/index.php/Plugin.yml%E3%81%AE%E8%A8%AD%E5%AE%9A%E4%B8%80%E8%A6%A7)を参考にしてください．

例としては以下のような感じです.

```yml
name: "QiitaTest"
version: "${project.version}"
main: "com.github.kubota.qiitatest.QiitaTest"
api-version: "1.13"

commands: #自作プラグインのコマンドを宣言
  qiita:
    description: this is a sample command.
    usage: /<command>
```

### メインクラスの編集
メインクラスに以下の要素を追加します．

```java
@Override
  public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
    return false;
}
```

ここで `onCommand` メソッドに関して軽く説明します．
このメソッドは`plugin.yml`の`Command`で定義されたコマンドが実行される際に実行されます．

その引数は４つありそれぞれ以下の通りです．
- CommandSender sender – コマンドの発行元
- Command cmd – 実行されたコマンドの内容
- String commandLabel – 利用されたコマンドエイリアス
-  String[] args – コマンドの引数を格納した配列

そして，このメソッドの型は`Boolean`なので返す値は`true`か`false`かのいずれかです．
`true`であれば，正常に動作することを表します．
`false`であれば正常に動作しなかったことを表し, `usage` に記載された内容が表示されます．

このメソッドを既存のプログラムに追加すると以下のようになります．

```java
package com.github.kubota.qiitatest;

import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;

public class QiitaTest extends JavaPlugin{
    //↓ onEnableはロードされた時に実行されるメソッド
    @Override
    public void onEnable() {
        // ↓ サーバー上にログを残す
        getLogger().info("Hello, Qiita!");
    }

    // onCommand は plugin.yml に記載されたコマンドが呼ばれた時に実行
    @Override
    public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
    	return false;
    }
}
```

これを実行するとこんな風になります．
<img width="753" alt="スクリーンショット 2019-08-13 23.45.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274950/2d711211-77c5-44ba-af14-6c759124aa72.png">
`Qiita`と言うコマンドが実行されると`onCommand`メソッド内のプログラムが実行されて`false`が返されているので`plugin.yml`内の`Usage`に記載された内容が表示されていますね．

これだけだとわかりにくいので`sendMessage`メソッドを追加します．
このメソッドは`CommandSender`クラスのメンバメソッドです．
このメソッドの機能としてはこの対象者(インスタンスのユーザー)に引数内の文字列をメッセージとして送信すると言うものです．
前章で使用した`getLogger`メソッドとの違いはあちらはコンソールに文字列を表示し，こちらは対象者にのみ文字列を送信すると言う違いがあります．

以下が編集を加えたものです．

```java
package com.github.kubota.qiitatest;

import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;

public class QiitaTest extends JavaPlugin{
    //↓ onEnableはロードされた時に実行されるメソッド
    @Override
    public void onEnable() {
        // ↓ サーバー上にログを残す
        getLogger().info("Hello, Qiita!");
    }

    // onCommand は plugin.yml に記載されたコマンドが呼ばれた時に実行
    @Override
    public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
        sender.sendMessage("Command, Qiita!");
    	return true;
    }
}
```

`onCommand`メソッドの性質上，その第一引数である`sender`はコマンドを実行したユーザーとなっています．
なので，今回のプログラムではそのコマンドを実行したユーザーにのみメッセージを送信すると言うものになっています．
あと，戻り値による挙動の変更も確認するために`false`から`true`へ変更しています．

実行結果は以下の通りです．
<img width="736" alt="スクリーンショット 2019-08-14 0.22.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274950/286bf4bb-64bb-3018-d55a-76efae37db6a.png">

## STEP2: 複数のコマンド
### plugin.ymlの設定
複数のプラグインを設定するには以下のように`Command`下に追加していきます．
こんな風な感じです．

```yml
name: "QiitaTest"
version: "${project.version}"
main: "com.github.kubota.qiitatest.QiitaTest"
api-version: "1.13"

commands: #自作プラグインのコマンドを宣言
  qiita:
    description: this is 1st sample command.
    usage: /<command>
  sample:
    description: this is 2nd sample command.
    usage: /<command>
```

### メインクラスの編集
`onCommand` は `plugin.yml` に記載されたコマンドが呼ばれた時に実行されるメソッドです．
もし， `plugin.yml` に複数のコマンドが定義されていた場合はそのいずれかのコマンドが呼ばれれば実行されます．
既存のプログラムのままだと複数のコマンドを用意しても全て同じ動作を行ってしまいます．

これだと複数のコマンドを用意した意味がないので，実行されたコマンドによって処理を分岐させる必要があります．

```java
package com.github.kubota.qiitatest;

import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;

public class QiitaTest extends JavaPlugin{
    //↓ onEnableはロードされた時に実行されるメソッド
    @Override
    public void onEnable() {
        // ↓ サーバー上にログを残す
        getLogger().info("Hello, Qiita!");
    }

    // onCommand は plugin.yml に記載されたコマンドが呼ばれた時に実行
    @Override
    public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
        if(cmd.getName().equalsIgnoreCase("qiita")){
            // qiitaコマンド が実行された時に実行
            sender.sendMessage("Command, Qiita!");
            return true;
        }
        if(cmd.getName().equalsIgnoreCase("sample")){
            // sampleコマンド が実行された時に実行
            sender.sendMessage("Command, sample!");
            return true;
        }
    	return false;
    }
}
```

前述したようにcmdには実行されたコマンドの情報が格納されています．
このインスタンスの `getName`メソッド を実行することで実行されたコマンドが文字列として取得できます．
`equalsIgnoreCase`メソッド String型がもつメソッドで引数の文字列が実行した文字列を一致するかをBoolean型で返すメソッドです．

これを実行すると以下のようになります．
<img width="725" alt="スクリーンショット 2019-08-14 15.30.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274950/c4643612-5f65-24a5-c196-8383e5711970.png">

#### Tips
> メソッドは `return` が実行された，それ以降の処理は実行されずに強制終了します．

## STEP3: サブコマンド
### plugin.yml の設定
これはマストではないですが,qiitaコマンドの機能として引数を受け付けるようにするために以下のように`usage`をわかりやすく変更します．

```yml
name: "QiitaTest"
version: "${project.version}"
main: "com.github.kubota.qiitatest.QiitaTest"
api-version: "1.13"

commands: #自作プラグインのコマンドを宣言
  qiita:
    description: this is 1st sample command.
    usage: /<command> [text]
  sample:
    description: this is 2nd sample command.
    usage: /<command>
```

### メインクラスの編集
コマンド実行時の引数は`args`と言う変数に格納されます．これはString型の配列です．
配列なので`args[x]`などとすれば取得できます、`x`の部分は0から始まり，１ずつ増えて行きます。

```
> qiita a wa ka
```

と言うコマンドを実行した場合は

|引数|args[0]|args[1]|args[2]|
|---|---|---|---|
|値|"a"|"wa"|"ka"|

と言う風に格納されます．

これを利用して以下のようなコードを書いてみます．

```java
package com.github.kubota.qiitatest;

import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;

public class QiitaTest extends JavaPlugin{
    //↓ onEnableはロードされた時に実行されるメソッド
    @Override
    public void onEnable() {
        // ↓ サーバー上にログを残す
        getLogger().info("Hello, Qiita!");
    }

    // onCommand は plugin.yml に記載されたコマンドが呼ばれた時に実行
    @Override
    public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
    	if(cmd.getName().equalsIgnoreCase("qiita")) {
    		if(args.length == 0)return false;
    		sender.sendMessage("Command, Qiita by " + args[0]);
    		return true;
    	}
    	if(cmd.getName().equalsIgnoreCase("sample")) {
    		sender.sendMessage("Command, Sample");
    		return true;
    	}
    	return false;
    }
}
```

`args.length`には`args`の配列に格納されている要素数が格納されています．
それが0と言うことはコマンド実行時の引数が何も入力されていないと言う状態になります．
今回はそのような状態はふさわしくないので`onCommand`メソッドは`false`を返すようにします．

もし,その条件突破する(引数が存在した場合)は,`Command, Qiita by `と表示された後に第一引数で入力された文字列を表示します．
これを実行すると結果は以下のようになります．
<img width="727" alt="スクリーンショット 2019-08-14 17.21.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274950/603f8924-fb3f-0f9d-6a07-5071e943bac9.png">

と言うことで今回は以上です！

## STEP4: サンプルプラグイン(じゃんけん)
最後に今回の知識を使ったサンプルプラグインを作成します．

機能としてはコンピュータをじゃんけんを行うプログラムです．
相手の手はプラグインが有効になった際にランダムな手が決定され，それ以降は変更されません．

コマンドで実装する機能は

- じゃんけんを行う
- 相手の手を確認する

の２つです．

### plugin.yml
```yml
name: "QiitaTest"
version: "${project.version}"
main: "com.github.kubota.qiitatest.QiitaTest"
api-version: "1.13"

commands: #自作プラグインのコマンドを宣言
  janken:
    discription: play the game of scissors-paper-roc.
    usage: /<command> [your choice]
  enemy:
    discription: check enemy choice.
    usage: /<command>
    
```
実装するプラグインのコマンドの機能

|コマンド|機能|
|---|---|
|`/janken [出す手]`| じゃんけんを行う|
|`/enemy`| 相手の手を確認|

### mainクラス
```java
package com.github.kubota.qiitatest;

// 乱数生成用のライブラリ
import java.util.Random;

import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;

public class QiitaTest extends JavaPlugin{
	String enemy = "";

	// onEnableはロードされた時に実行されるメソッド
	// このメソッドではenemy(相手の手)をランダムで決定する
	@Override
	public void onEnable() {
		//手の情報が記載された配列
		String[] hand = {"goo","tyo","paa"};

		//乱数生成用のクラスをインスタンス化
		Random r = new Random();
		//nextIntメソッド で0以上3未満の乱数を生成し,対応する手をenemyに格納
		enemy = hand[r.nextInt(3)];
	}


    // onCommand は plugin.yml に記載されたコマンドが呼ばれた時に実行
    @Override
    public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {

    	// jankenコマンドを実行することでenemyとじゃんけんを行う
    	// 引数で自分の手を入力
    	if(cmd.getName().equalsIgnoreCase("janken")) {

    		// 引数が何も渡されない
    		if(args.length == 0)return false;

    		if(args[0].equalsIgnoreCase("paa") && enemy.equalsIgnoreCase("tyo") ||
    			args[0].equalsIgnoreCase("tyo") && enemy.equalsIgnoreCase("goo") ||
    			args[0].equalsIgnoreCase("goo") && enemy.equalsIgnoreCase("paa")){
    			//敗北のパターン
    			sender.sendMessage("俺の勝ち! 何で負けたか明日まで考えといてください");

    		}else if(args[0].equalsIgnoreCase("tyo") && enemy.equalsIgnoreCase("paa") ||
    			args[0].equalsIgnoreCase("goo") && enemy.equalsIgnoreCase("tyo") ||
        		args[0].equalsIgnoreCase("paa") && enemy.equalsIgnoreCase("goo")) {
    			//勝利のパターン
    			sender.sendMessage("やるやん! 明日は俺にリベンジさせて");

    		}else if(args[0].equalsIgnoreCase(enemy)) {
    			//あいこのパターン
    			sender.sendMessage("あいこやん! どうすんのこれ?");

    		}else {
    			// goo tyo paa 以外が入力されたパターン
    			return false;
    		}
    		return true;
    	}

    	// enemyコマンドで相手の手を表示する
    	if(cmd.getName().equalsIgnoreCase("enemy")) {
    		sender.sendMessage("Enemy choice is " + enemy + ".");
    		return true;
    	}

    	return false;
    }
}
```

#### 乱数の生成

```java
// 乱数生成用のライブラリ
import java.util.Random;
```
このライブラリをインポートすることで乱数を生成するための以下で使用するクラスを使用することができます．

```java
// 相手の手を格納する変数
String enemy = "";

// onEnableはロードされた時に実行されるメソッド
// このメソッドではenemy(相手の手)をランダムで決定する
@Override
public void onEnable() {
	//手の情報が記載された配列
	String[] hand = {"goo","tyo","paa"};

	//乱数生成用のクラスをインスタンス化
	Random r = new Random();
	//nextIntメソッド で0以上3未満の乱数を生成し,対応する手をenemyに格納
	enemy = hand[r.nextInt(3)];
}
```
ここが相手の手をランダムで決定しているプラグラムです．
まずは相手の手を格納する変数である`enemy`をmainクラスのフィールドとして用意します．

その後，このプログラムが有効になった時の処理として，`Random`クラスのインスタンスを初期化します．
これによりこのインスタンスを経由することで乱数を生成するためのメソッドを利用可能にすることができます．
次に`nectInt`メソッドを呼びだし乱数を取得します．このメソッドの引数が生成する乱数の最大値になります．
このプログラムではでは0以上、3未満の乱数を生成しています．

これを配列の添字とすることで0~2,すなわち`hand`配列の三つの要素からランダムで一つを取得可能です．

#### じゃんけんを行う
```java
// jankenコマンドを実行することでenemyとじゃんけんを行う
    // 引数で自分の手を入力
    if(cmd.getName().equalsIgnoreCase("janken")) {

    	// 引数が何も渡されない
    	if(args.length == 0)return false;

    	if(args[0].equalsIgnoreCase("paa") && enemy.equalsIgnoreCase("tyo") ||
    		args[0].equalsIgnoreCase("tyo") && enemy.equalsIgnoreCase("goo") ||
    		args[0].equalsIgnoreCase("goo") && enemy.equalsIgnoreCase("paa")){
    		//敗北のパターン
    		sender.sendMessage("俺の勝ち! 何で負けたか明日まで考えといてください");

    	}else if(args[0].equalsIgnoreCase("tyo") && enemy.equalsIgnoreCase("paa") ||
    		args[0].equalsIgnoreCase("goo") && enemy.equalsIgnoreCase("tyo") ||
        	args[0].equalsIgnoreCase("paa") && enemy.equalsIgnoreCase("goo")) {
    		//勝利のパターン
    		sender.sendMessage("やるやん! 明日は俺にリベンジさせて");

    	}else if(args[0].equalsIgnoreCase(enemy)) {
    		//あいこのパターン
    		sender.sendMessage("あいこやん! どうすんのこれ?");

    	}else {
    		// goo tyo paa 以外が入力されたパターン
    		return false;
    	}
    	return true;
}
```
そして次がぱっと見すごい難しそうに見えますが，条件式が複雑なだけで内容は単純です．
じゃんけんで勝つパターン,負けるパターンを全てを一つ一つ定義しています(アイコだけは`enemy`と`args[0]`が等しいで判断しています)．

#### 相手の手を表示
```java
// enemyコマンドで相手の手を表示する
if(cmd.getName().equalsIgnoreCase("enemy")) {
	sender.sendMessage("Enemy choice is " + enemy + ".");
	return true;
}
```
`enemy`を表示しているだけです．
特に難しい箇所はないと思います．

### 実行結果
<img width="715" alt="スクリーンショット 2019-08-14 20.11.54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274950/ae91d317-6046-a729-1983-6c5937d3c2cc.png">


# 参考文献
- [Plugin.ymlの設定一覧](https://mcmodding.jp/modding/index.php/Plugin.yml%E3%81%AE%E8%A8%AD%E5%AE%9A%E4%B8%80%E8%A6%A7)
- [[Bukkitプラグイン制作講座-其之三]コマンドに応答する](https://jyn.jp/bukkit-plugin-development-3/)
- [【Bukkit Plugin開発】コマンド入力を受け付ける](http://www.yk-lab.net/archives/%E3%80%90bukkit-plugin%E9%96%8B%E7%99%BA%E3%80%91%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E5%85%A5%E5%8A%9B%E3%82%92%E5%8F%97%E3%81%91%E4%BB%98%E3%81%91%E3%82%8B/)