LoginSignup
4

More than 3 years have passed since last update.

posted at

updated at

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

前提条件

Eclipseを用いたSpigotプラグイン作成で作成したプラグインに追加する形でプラグインの開発を行なっていきます.

STEP1: 基本的なコマンドの実装

plugin.ymlの設定

自作プラグインのコマンドがコマンドに応答する機能を追加するためにplugin.ymlの編集を行います.

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

ここでは基本的な要素しか追加していません.
description,usage以外を追加する事で色々いじる事が可能です.他の詳しい設定を行いたい場合はこのサイトを参考にしてください.

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

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>

メインクラスの編集

メインクラスに以下の要素を追加します.

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

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

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

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

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

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;
    }
}

これを実行するとこんな風になります.
スクリーンショット 2019-08-13 23.45.28.png
Qiitaと言うコマンドが実行されるとonCommandメソッド内のプログラムが実行されてfalseが返されているのでplugin.yml内のUsageに記載された内容が表示されていますね.

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

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

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へ変更しています.

実行結果は以下の通りです.
スクリーンショット 2019-08-14 0.22.35.png

STEP2: 複数のコマンド

plugin.ymlの設定

複数のプラグインを設定するには以下のようにCommand下に追加していきます.
こんな風な感じです.

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>

メインクラスの編集

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

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

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型で返すメソッドです.

これを実行すると以下のようになります.
スクリーンショット 2019-08-14 15.30.19.png

Tips

メソッドは return が実行された,それ以降の処理は実行されずに強制終了します.

STEP3: サブコマンド

plugin.yml の設定

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

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から始まり,1ずつ増えて行きます。

> qiita a wa ka

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

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

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

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

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と表示された後に第一引数で入力された文字列を表示します.
これを実行すると結果は以下のようになります.
スクリーンショット 2019-08-14 17.21.11.png

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

STEP4: サンプルプラグイン(じゃんけん)

最後に今回の知識を使ったサンプルプラグインを作成します.

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

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

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

の2つです.

plugin.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クラス

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;
    }
}

乱数の生成

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

このライブラリをインポートすることで乱数を生成するための以下で使用するクラスを使用することができます.

// 相手の手を格納する変数
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配列の三つの要素からランダムで一つを取得可能です.

じゃんけんを行う

// 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;
}

そして次がぱっと見すごい難しそうに見えますが,条件式が複雑なだけで内容は単純です.
じゃんけんで勝つパターン,負けるパターンを全てを一つ一つ定義しています(アイコだけはenemyargs[0]が等しいで判断しています).

相手の手を表示

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

enemyを表示しているだけです.
特に難しい箇所はないと思います.

実行結果

スクリーンショット 2019-08-14 20.11.54.png

参考文献

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
4