Densyakunのブログ

高校生プログラマの雑なブログです。ゲームを開発しています。

【Spigot】Bukkitプラグインの作り方講座 第2回 - コマンドの追加とEventシステムの活用

こんにちは、電車君です。

前回プラグインの基本的な作り方について説明しました。

今回は第2回ということで、コマンドの追加とEventシステムを活用していきます。

 

  • 追記(2018/03/13): SpigotMCによる公式の解説を追加しました。

 

今回やること

コマンドを使いプラグインに指示を送る
Eventシステムを使うことで「サーバーにプレイヤーがログインした」、「プレイヤーがブロックを破壊した」などのイベントを、プラグインに連動させる事ができる。

 

 

 

 

コマンドの追加

コマンドを追加する方法は二種類あります。

plugin.ymlを編集する方法と、プログラムで動的にコマンドを追加する方法があります。

SpigotMCによる公式の解説はこちら(英語)

 

今回はplugin.ymlを編集してコマンドを追加します。

まず、plugin.ymlを編集します。

plugin.ymlの詳しい書き方についてはこちら: https://bukkit.gamepedia.com/Plugin_YAML

 

name、mainなどの下にcommandsを設定します。

 

書き方:

name: プラグイン名
main: パッケージ.メインクラス
version: バージョン
description: プラグインの説明
# 作者が複数いる場合はauthorsを使用し、一人の場合はauthorを使用して下さい。
author: 作者名
authors: [作者1, 作者2, 作者3]
website: サイトのURL

commands:
  コマンド名:
    description: コマンドの説明
    aliases: [他のコマンド名1, 他のコマンド名2]
    permission: コマンドの権限
    usage: コマンドの使い方
  コマンド名:
    description: コマンドの説明
    aliases: [他のコマンド名1, 他のコマンド名2]
    permission: コマンドの権限
    usage: |
      コマンドの使い方1行目
      2行目
      3行目...
permissions:
  権限名1.*:
    description: 権限の説明
    children:
      権限名1.権限名2: true
      権限名1.権限名3: true
      権限名1.権限名3.権限名4: true
  権限名1.権限名2:
    description: 権限の説明
    default: true
  権限名1.権限名3:
    description: 権限の説明
    default: true
  権限名1.権限名3.権限名4:
    description: 権限の説明
    default: op
    children:
      権限名1.権限名3: true

青色の文字が新しく記入した文です。name、main、versionの他に色々追加していますが、好きなものを追加して下さい。

 

 

記載例:

name: TestPlugin
main: io.github.densyakun.bukkit.test.Main
version: 0.2
description: This plugin is test plugin.
author: Densyakun
website: https://github.com/Densyakun

commands:
  flagrate:
    description: Set yourself on fire.
    aliases: [combust_me, combustMe]
    permission: inferno.flagrate
    usage: Syntax error! Simply type /command to ignite yourself.
  burningdeaths:
    description: List how many times you have died by fire.
    aliases: [burning_deaths, burningDeaths]
    permission: inferno.burningdeaths
    usage: |
      /command [player]
      Example: /command - see how many times you have burned to death
      Example: /command CaptainIce - see how many times CaptainIce has burned to death
permissions:
  inferno.*:
    description: Gives access to all Inferno commands
    children:
      inferno.flagrate: true
      inferno.burningdeaths: true
      inferno.burningdeaths.others: true
  inferno.flagrate:
    description: Allows you to ignite yourself
    default: true
  inferno.burningdeaths:
    description: Allows you to see how many times you have burned to death
    default: true
  inferno.burningdeaths.others:
    description: Allows you to see how many times others have burned to death
    default: op
    children:
      inferno.burningdeaths: true

インデントは空白二個ですが、三個でも出来ます。間違えると動きません。(インデントは揃えて下さい)

今回はversionを0.2に書き換えました。

 

 

まず、commandsを書き、その中にコマンド名を書きます。

name: TestPlugin
main: io.github.densyakun.bukkit.test.Main
version: 0.2
author: Densyakun
commands:
  test:

これで /test コマンドを追加できます。

commands:コマンド名だけでも動きますので、書くのがめんどくさい方はこれで大丈夫です。

 

 

他にも、コマンドの説明を書きたい場合はdescriptionを書いて下さい。

aliasesを使って他のコマンド名を使えます。

例えば、/flagrateコマンドを/combust_meや/combustMeでも出来るようにした場合は、

/flagrateコマンドの中にaliases: [combust_me, combustMe]と書きます。

 

使い方の説明は二種類あり、一行だけで書く場合は

usage: コマンドの使い方

で出来ます。

 

複数行で表示したい場合は

usage: |
  コマンドの使い方1行目
  2行目
  3行目...

で出来ます。(「...」は消して下さい)

 

 

 

プラグインの権限

コマンドのpermissionを書くと権限を持っていない場合はコマンドが実行できなくなります。

権限を付与するにはOP権限を与えるか、PermissionExなどを使って権限を付与します。

細かく権限を設定するには、permissions:を追加します。

permissions:
  権限名1.*:
    description: 権限の説明
    children:
      権限名1.権限名2: true
      権限名1.権限名3: true
      権限名1.権限名3.権限名4: true
  権限名1.権限名2:
    description: 権限の説明
    default: true
  権限名1.権限名3:
    description: 権限の説明
    default: true
  権限名1.権限名3.権限名4:
    description: 権限の説明
    default: op
    children:
      権限名1.権限名3: true

permissions:の中に権限の名前を書きます。

通常、権限の名前はプラグイン名.権限名という風に書きます。

コマンド用にプラグイン名.command.コマンド名と書く場合などもありますので、お好みの書き方をして構いません。

 

権限の名前を書いたら、その中にdescriptionで権限の説明を書きます。

defaultは、誰がこの権限を持っているか設定します。trueにすると誰でも使えます。opにするとOP権限を持っていればPermissionExなどで付与していなくても使えます。falseにするとOP権限を持っていてもPermissionExなどで設定しないと権限が付与できません。

 

権限にchildrenを記入すると、権限の子権限を設定でき、権限の親子関係を定義できます。

例えば権限test.command.testと、その親権限のtest.command、更にその親のtest.*があります。

その場合はtest.*の子権限にtest.command

test.commandの子権限にtest.command.testを追加します。

子権限の名前の後にtrueと書いてありますが、これはtrueだと通常の親子関係を定義し、falseだと親子関係が逆になるように定義できます。

 

 

 

コードを書く

次に前回作成したメインクラスを編集します。

メインクラスはplugin.ymlに書かれているmainと同じです。

以下のコードを追加します。

@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
	if (label.equalsIgnoreCase("test")) {
		sender.sendMessage("コマンドが実行されました");
	}
	
	return true;
}

 

onCommandは自分のプラグインのコマンドが打たれると実行されるメソッドです。

引数のlabelはコマンド名、argsはコマンドの引数です。

例えば「/tp Densyakun Steve」の場合、labelは"tp"、argsには["Densyakun", "Steve"]と言う配列が入ります。

 

 

senderのCommandSenderクラスは、プレイヤーやコンソールなどの「コマンドを実行できる者」のクラスです。

例えばプレイヤーはPlayerクラスですが、CommandSenderインターフェースを継承していますし、プレイヤーでない場合もコマンドブロック、サーバーコンソールなどからコマンドが実行できるためこれもCommandSenderになります。

 

senderについての詳しい使い方はあとで説明します。

 

このコードではsender.sendMessage(str)を使ってコマンド送信元にメッセージを送り返しています。

 

 

if(label.equalsIgnoreCase("test"))を使って、testコマンドが実行されたかどうかを判別しています。

JavaではequalsIgnoreCase(str)を使って文字列と文字列を大文字小文字を気にせず判定することが出来ます。

 

booleanを返さなくてはいけないため、return trueと書いています。コマンドを間違えた場合にfalseを返すとplugin.ymlにて設定したコマンドの使い方が表示されます。trueを返すと何も起きません。

 

 

実際はこんな感じになります。

package io.github.densyakun.bukkit.test;

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

public class Main extends JavaPlugin {
	
	@Override
	public void onEnable() {
		System.out.println("プラグインが有効になりました");
	}
	
	@Override
	public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
		if (label.equalsIgnoreCase("test")) {
			sender.sendMessage("コマンドが実行されました");
		}
		
		return true;
	}
	
	@Override
	public void onDisable() {
		System.out.println("プラグインが無効になりました");
	}
}

 

実際に使ってみましょう。前回と同じようにエクスポートして下さい。

サーバーにプラグインを入れて、サーバーを起動したら、

plコマンドを実行してプラグインが正しく導入されているか確認して下さい。

入れてもプラグインが読み込まれていない場合はplugin.ymlが間違っている可能性があります。

 

 

f:id:Densyakun:20180211191238p:plain

/ver TestPluginと入れると、バージョンが変わっているはずです。

 

 

f:id:Densyakun:20180211191259p:plain

/help TestPluginを実行すると追加されたプラグインが載っています。

 

 

f:id:Densyakun:20180211191335p:plain

/help testと入力するとtestコマンドについての説明や使い方が表示されますが、今回は書いていないので出ていません。

 

 

f:id:Densyakun:20180211191404p:plain

コマンドを実行してみましょう。

実行すると「コマンドが実行されました」と言うメッセージが表示されます。

 

 

f:id:Densyakun:20180211191431p:plain

/tとだけ入力してTABキーを押すと追加したtestコマンドがリストに載っています。

 

 

コマンド以外の権限について

plugin.ymlで設定した権限はコマンド以外にも使用できます。

権限を所有しているかどうか判定するには以下のコードを使用して下さい。

if (sender.hasPermission("権限名"))

 

 

 

Eventシステムを使う

次は、Eventシステムを活用していきます。

 

 

まず、org.bukkit.event.Listenerインターフェースを継承したクラスを作成して下さい。

(メインクラスに継承しても構いません)

 

そしたら、onEnable()内に以下のコードを書いて下さい。

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

第一引数はListener、第二引数はJavaPlugin(メインクラス)です。

これでプラグインにEventシステムが使えるようになりました。

 

 

次に、「Listenerを継承したクラス」にイベントを追加します。

新しくメソッドを追加します。この時のメソッド名はなんでも良いです。

新しく追加したメソッドの引数にはイベントのクラスを書きます。

イベントの一覧はこちら http://www.jias.jp/blog/?85

 

最後にメソッドに@EventHandlerアノテーションを追加して下さい。

 

今回はPlayerJoinEventを使用してプレイヤーのログインメッセージを変更します。

@EventHandler
public void onPlayerJoin(PlayerJoinEvent e) {
	e.setJoinMessage("プレイヤーがログインしました: " + e.getPlayer().getName());
}

e.getPlayer()でプレイヤーを取得し、getName()でプレイヤー名を取得しています。

getName()はプレイヤーの本来の名前です。プレイヤーの表示名はgetDisplayName()で取得できます。

プレイヤーの表示名を設定するにはsetDisplayName(String)を使用します。

 

PlayerJoinEvent.setJoinMessage(String)でログインメッセージを変更しています。

 

 

メインクラスに書いた場合の例:

package io.github.densyakun.bukkit.test;

import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.java.JavaPlugin;

public class Main extends JavaPlugin implements Listener {
	
	@Override
	public void onEnable() {
		getServer().getPluginManager().registerEvents(this, this);
		
		System.out.println("プラグインが有効になりました");
	}
	
	@Override
	public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
		if (label.equalsIgnoreCase("test")) {
			sender.sendMessage("コマンドが実行されました");
		}
		
		return true;
	}
	
	@Override
	public void onDisable() {
		System.out.println("プラグインが無効になりました");
	}
	
	@EventHandler
	public void onPlayerJoin(PlayerJoinEvent e) {
		e.setJoinMessage("プレイヤーがログインしました: " + e.getPlayer().getName());
	}
}

 

 

これでイベントを追加することが出来ました。

 

 

エクスポートして、プラグインをサーバーに入れます。

f:id:Densyakun:20180211191510p:plain

このように表示されていればOKです。

 

 

 

Eventシステムの活用

最後に、Eventシステムを活用します。

 

このようなイベントを追加して下さい。

@EventHandler
public void onPlayerJoin(BlockBreakEvent e) {
	Block b = e.getBlock();
	if (b.getType() == Material.GRASS) {
		e.setCancelled(true);
		b.setType(Material.SAND);
	}
}

 

BlockBreakEventはプレイヤーがブロックを破壊した時に実行されるイベントです。

これを使って草ブロックを破壊すると砂に変わります。

 

ブロックに関係するイベントはBlockEventを継承しています。

BlockEvent.getBlock()でブロックを取得できます。

Block.getType()はブロックの素材をMaterial型で返します。

 

if (b.getType() == Material.GRASS)

Material.GRASSと判定して草ブロックであるかどうかを判別しています。

 

e.setCancelled(true);

イベントをキャンセルすることで砂に変える時にブロックを破壊されないようになります。

 

b.setType(material);

これを使ってブロックの素材を砂に設定します。

 

マテリアルの一覧はこちら(バージョンにより異なる可能性があります)

 

 

 

実際にやってみます。

 

 

f:id:Densyakun:20180211191535p:plain

※暗い。

 

 

f:id:Densyakun:20180211191609g:plain

 

 

 

おわりに

今回はコマンドの追加とEventシステムの活用について解説しました。

次回については未定ですので、コメント欄にて次回の話題を募集します!

 

お楽しみに!

f:id:Densyakun:20180211191630p:plain

 

次回:

 

前回:

densyakun.hateblo.jp