提供: Minecraft Modding Wiki
移動先: 案内検索

警告: ログインしていません。編集を行うと、あなたの IP アドレスが公開されます。ログインまたはアカウントを作成すれば、あなたの編集はその利用者名とともに表示されるほか、その他の利点もあります。

この編集を取り消せます。 下記の差分を確認して、本当に取り消していいか検証してください。よろしければ変更を保存して取り消しを完了してください。
最新版 編集中の文章
1行目: 1行目:
 
本ページの内容は、[http://wiki.bukkit.org/ Bukkit Wiki]の[http://wiki.bukkit.org/Plugin_Tutorial Plugin Tutorial]を和訳した物となります。(一部は省略しています)<br />
 
本ページの内容は、[http://wiki.bukkit.org/ Bukkit Wiki]の[http://wiki.bukkit.org/Plugin_Tutorial Plugin Tutorial]を和訳した物となります。(一部は省略しています)<br />
 
最新ではない可能性があるため、より新しい情報を確認する場合は、本家を参照するようにして下さい。<br />
 
最新ではない可能性があるため、より新しい情報を確認する場合は、本家を参照するようにして下さい。<br />
 
+
'''本項目は、和訳の最中です。最後まで読むことは出来ません。'''<br />
== 始めに ==
 
:'''重要''': 当ページには、原文の翻訳ではない、日本語読者向けの独自の記述を行っている箇所が少量あります。そのような内容を含む節ではNoteにて通知しています。
 
:'''重要''': 当ページでは、技術的な解説やたとえ話の原意を理解し易くするために、一部意訳を行っています。
 
:'''重要''': 当ページは訳文であるため、訳文自体に対する文責は原著者にありません。当ページの内容を受けて原著者へ何らかのアクションを行う場合、その点を考慮して必ず原文にも目を通して下さい。
 
 
 
このチュートリアルは、Bukkitプラグインを開発するための基本的なノウハウを網羅しております。
 
 
 
Javaを習得する、IDEで開発環境を構築する、などの非常に基本的な部分から説明が始まっていますが、既にご理解頂いている場合は読み飛ばしていただいて構いません。
 
 
 
== Javaの習得 ==
 
:'''Note''': 当記事の一部は原文の訳ではありません、日本語読者向けに独自の内容を記述しています。
 
 
 
このチュートリアルの読者には、Java言語プログラミングの基礎がわかる方を対象としています。<br/>
 
Javaの基礎知識が少ない方は、下記の情報に触れてください。
 
 
 
*[http://docs.oracle.com/cd/E26537_01/tutorial/index.html Oracleの記事] (現在のJavaの公式サイト)
 
*[http://www.tohoho-web.com/java/index.htm とほほのJava入門] - 基礎をみっちり解説している
 
*[http://www.kab-studio.biz/Programing/OOPinJava/ Javaのオブジェクト指向入門] - 継承や実装等のオブジェクト指向用語が分からない人向け
 
 
 
Javaがどうしても理解できない場合は、この他にも様々な資料があるので探して触れてください。
 
 
 
== Javaの開発環境 ==
 
:'''Note''': 当記事の一部は原文の訳ではありません、日本語読者向けに独自の内容を記述しています。
 
 
 
プラグインを開発する(またはJavaを学ぶ)前に、開発環境(IDE (Integrated Development Environment))をインストールして下さい。<br/>
 
開発環境は、プラグインのコンパイルとデバッグを行うために使います。<br/>
 
Javaの主要なIDEには、[http://www.eclipse.org/ Eclipse], [http://netbeans.org/ Netbeans], [http://www.jetbrains.com/idea/ IntelliJ IDEA] の3つがあります。<br/>
 
EclipseはBukkit開発者の中では最も人気があり、IntelliJの方は業界内で広く利用されています。
 
 
 
あなたがJavaの初心者なら、当チュートリアルが解説に利用しているEclipseを利用する事をお勧めします。<br/>
 
Eclipseのお勧めのバージョンの配布元は、[http://mergedoc.sourceforge.jp/ 日本語 Eclipse / Pleiades All in One 日本語ディストリビューション]です。<br/>
 
これはMergedocProjectが配布する拡張されたパッケージであり、Eclipseの一次配布元が提供するパッケージではありません。
 
 
 
Pleiadesを利用する場合、「開発対象用 JDK」と、ビルドツールMavenが実行できるプラグイン「m2e」が同梱されているものを選択してください。<br/>
 
(Eclipseを既に利用している場合でも、m2eを後から追加インストールすることは可能です。)
 
 
 
spigotなどのBukkitサーバーの実行環境を利用する場合、BuildTools.jar を利用してサーバー実行環境をビルドする必要がありますが、Mavenが利用できる場合は、Mavenが開発用のライブラリを自動でダウンロードするため、BuildTools.jar を使わなくても開発環境を構築することが可能です。<br/>
 
ただし、当然ですが、デバッグ実行するための実行環境は必要になりますから、BuildTools.jar を利用して実行環境も準備しておいてください。このチュートリアルでは、BuildTools.jar を利用した実行環境の構築は割愛いたします。
 
<!--
 
もし、BuildTools.jar を利用した実行環境の構築について、きれいにまとめられている資料があれば、ここにリンクを置いてください。
 
-->
 
  
 
== Plugin用プロジェクトを始めるために ==
 
== Plugin用プロジェクトを始めるために ==
  
 
=== プロジェクトの作成 ===
 
=== プロジェクトの作成 ===
始めるために、新しいワークスペースを作成する必要があります。<br />
+
始める前にEclipseのワークスペースとファイルの設定を行う必要があります。<br />
Eclipseを起動し、ファイル>新規>プロジェクト... と選択して下さい。<br />
+
Eclipseを起動し、ファイル>新規>Java プロジェクトと選択して下さい。<br />
  
[[Image:create_project.png]]
+
[[Image:NewJavaProject.png]]
  
新規プロジェクトのダイアログが開きます。Mavenフォルダを開いて、Mavenプロジェクト を選択し、次へ を押してください。
+
プロジェクト名を入力し、新規プロジェクトウィザード画面の指示に従って、プロジェクトを作成してください。
  
[[Image:create_project1.png]]
+
=== Bukkit APIの参照 ===
 +
開発を始める前にbukkit APIライブラリをプロジェクトに追加する必要があります。
 +
使用したい他のAPIも同じように追加することが可能です。
  
次のダイアログで、「シンプルなプロジェクトの作成」にチェックを入れて、次へ を押してください。
+
最新のBukkit APIはここからダウンロードが可能です。 {{BDownload}}
  
[[Image:create_project2.png]]
+
画面の左手にあるパッケージエクスプローラの(先ほど名前を付けた)プロジェクトを右クリックし、プロパティーを選択します。<br />
 +
開いた画面のJavaビルド・パスを選択し、ライブラリータブの中から、外部 Jar 追加ボタンを押して、ダウンロードしたBukkit APIを指定します。<br />
  
次のダイアログで、作成するプラグインの「グループID」と「アーティファクトID」を入力します。<br/>
+
[[Image:BuildPathPic.png|800px]]
(アーティファクトIDとは、これから作ろうとするプラグインの名前と同義と思っていただいて構いません。)
 
  
グループIDは下記の方法で命名して下さい:
+
=== BukkitのJavadocの利用方法 ===
<blockquote>
 
* ドメインを持っているなら、そのドメインの逆引き名にしましょう。
 
** ドメイン名が'''i-am-a-bukkit-developer.com'''の場合、パッケージ名は'''com.i_am_a_bukkit_developer'''となります。
 
* ドメイン名を持っていない場合、下記の選択肢があります。お勧め順です。
 
** '''Option 1''' githubやsourceforgeのようなソース管理サイトにアカウント登録します。
 
*** githubの場合: [http://pages.github.com/ こちら]から作成したユーザページのURLを元に、'''com.github.<username>'''と命名します。
 
** '''Option 2''' emailアドレスを元に命名します。('''<username>@gmail.com'''であれば'''com.gmail.<username>'''とします)
 
** '''Option 3''' 重複しなさそうなパッケージ名を指定します(他者の開発物と重複する可能性が高いので非推奨)
 
</blockquote>
 
  
 +
Eclipseを用いたJavaプログラミングの経験がある方なら、<br/>
 +
Eclipseのエディタ上でクラスやメソッドにマウスカーソルを重ねた時に、<br/>
 +
クラスやメソッドに関するドキュメントがポップアップで表示される事をご存知でしょう。<br/>
 +
これは、[http://download.oracle.com/javase/6/docs/api/ Oracleのウェブサイト]から得る事ができるJavadocの内容が表示されています。<br/>
  
下記の名前で始まるような、他者の開発物と重複するパッケージで命名すべきでは'''ありません''':
+
Bukkitもまた、BukkitのAPIが提供するクラスやメソッドの各々のコードに[http://jd.bukkit.org/apidocs/ 同種のドキュメント]を含んでおり、ポップアップで表示させる事ができます。<br/>
<blockquote>
+
Eclipse上で、Bukkitのクラスやメソッドにマウスを重ねたタイミングでポップアップを表示できるようにするためには、下記の手順を行います。
* org.bukkit
 
* net.bukkit
 
* com.bukkit
 
* net.minecraft
 
</blockquote>
 
  
ベースとなるグループIDを決めたら、次にプラグイン名を決めましょう。ここでは例として、TutorialPlugin と名付けます。
+
# プロジェクトエクスプローラ上で、Bukkitのjarファイルを右クリックして、メニューを開く。
 +
# "プロパティ"を選択し、表示されるポップアップ左側の"Javadoc ロケーション"項目を選択する。
 +
# "Javadoc URL"の下部にあるテキストボックスに、"http://jd.bukkit.org/apidocs/" (ダブルクォートは除く)を貼り付ける。
 +
# "検証"ボタンを押下し、URLがJavadocとして正しく識別される事をチェックしてから、OKボタンを押す。
  
ダイアログには次のように入力し、完了 を押してください。
+
:次ような画面になります:<br/>
 +
:[[Image:Bukkitjavadocs.png]]
  
[[Image:create_project3.png]]
+
=== Plugin開発の開始 ===
  
Eclipseの画面に戻ると、左側に TutorialPlugin プロジェクトが作成されているはずです。ここまで、うまく作成できましたか?
+
[[Image:MakePackage.png]]
  
「ビルドプランを計算できませんでした。」と出た場合、作成したパッケージを右クリックし「実行」から「Maven install」をクリックすることにより、
+
== onEnable() and onDisable() ==
Mavenのインストールが始まりエラーが出なくなります。
+
このファンクションは、プラグインが有効/無効になったときに呼ばれます。<br />
 +
デフォルトでは、プラグインは自動的に読み込まれたときに、イベントを登録やデバッグ出力を行うことが出来ます。<br />
 +
onEnable()は、プラグインがBukkitから読み込まれるときに最初に呼ばれ、プラグインを実行するために必須です。<br />
  
=== Bukkit API の参照設定 ===
+
=== onEnable()とonDisable()の基本 ===
 +
前のセクションで作成したメインクラスに、onEnable()とonDisable()のメソッドを作成します。<br />
 +
<blockquote><source lang="java">
 +
public void onEnable(){
 +
 +
}
 +
 +
public void onDisable(){
 +
 +
}
 +
</source></blockquote>
  
次に、左側に作成された TutorialPlugin プロジェクトの中にある、「pom.xml」というファイルをダブルクリックしてください。そして、画面右下のあたりにある「pom.xml」というタブをクリックしてください。
 
  
[[Image:create_project4.png]]
+
現時点では、このメソッドは何も行いません。また、エラーが発生する事にも気付くでしょう。このエラーは、メインクラスが、プラグインの機能を継承(extends)する必要がある事を示しています。当クラスの定義文を、下記のように変更しましょう。
  
まず、Java開発環境(JDK)の参照設定をします。<br/>
+
これを・・・
一番最後の行に '''</project>''' というタグがありますが、その1行上に、次の内容を挿入してください。<br/>
+
<blockquote><source lang="java">Class <classname> {}</source></blockquote>
(なお、これは Java 7 を参照してビルドするための設定です。もし Java 6 を参照してビルドしたい場合は、sourceタグとtargetタグに書かれている 1.7 のところを 1.6 に変更してください。また、Java 8を参照したい場合は、1.7を1.8に変更してください。)
 
  
<pre lang="xml">
+
このように変更する。
  <build>
+
<blockquote><source lang="java">Class <classname> extends JavaPlugin {}</source></blockquote>
    <plugins>
 
      <plugin>
 
        <groupId>org.apache.maven.plugins</groupId>
 
        <artifactId>maven-compiler-plugin</artifactId>
 
        <configuration>
 
          <source>1.7</source>
 
          <target>1.7</target>
 
        </configuration>
 
      </plugin>
 
    </plugins>
 
  </build>
 
</pre>
 
  
次に、Bukkit APIを実装しているSpigotのリポジトリがどこにあるかURLで示します。<br/>
+
すると、前述の追加コードが赤の下線でハイライト表示され、何かが間違っていることを通知してくるはずです。このハイライト部にマウスを重ねると、下記のようなポップアップが表示されるので、「'JavaPlugin'をインポートします(org.bukkit.plugin.java)」を選択します。
下記の内容を追記してください。
 
  
<pre lang="xml">
+
<blockquote>[[ファイル:to_need_import_package.png]]</blockquote>
  <repositories>
 
    <repository>
 
      <id>spigot-repo</id>
 
      <url>https://hub.spigotmc.org/nexus/content/groups/public</url>
 
    </repository>
 
  </repositories>
 
</pre>
 
  
最後に、Bukkit API の参照設定を追加します。<br/>
+
もしくは、
下記の内容を追記してください。
+
<blockquote><source lang="java">import org.bukkit.plugin.java.JavaPlugin;</source></blockquote>
 +
をコード上部の定義部に記述する事でも同様の事が行えます。
  
<pre lang="xml">
+
=== Loggerを利用したメッセージ出力 ===
  <dependencies>
 
    <dependency>
 
      <groupId>org.bukkit</groupId>
 
      <artifactId>bukkit</artifactId>
 
      <version>1.10.2-R0.1-SNAPSHOT</version>
 
    </dependency>
 
  </dependencies>
 
</pre>
 
  
この設定では、Bukkit API 1.10.2-R0.1-SNAPSHOT が参照されます。<br/>
+
始めに、プラグインが実際に動作するかどうかを確認するため、シンプルなメッセージをサーバコンソールに表示させてみましょう。この処理として、ログ出力機能(Logger)をメインクラスに定義して初期化します。
別のバージョンを参照したい場合は、versionタグの中を変更してください。<br/>
+
<blockquote><source lang="java">Logger log = this.getLogger();</source></blockquote>
設定が可能なバージョン番号の一覧は、[https://hub.spigotmc.org/nexus/content/groups/public/org/bukkit/bukkit/ こちら] を参照してください。
+
その後、onEnable()メソッドに、プラグインが動作している事を通知するメッセージを出力する処理を記述します。
 +
<blockquote><source lang="java">log.info("Your plugin has been enabled.");</source></blockquote>
  
ここまで編集をすると、pom.xmlは次のようになっているはずです。確認してみてください。
+
onDisable()メソッドについても同等の記述を行います。ここまでのコーディングによって、メインクラスは下記の様な内容になっているはずです。
 +
<blockquote><source lang="java">
 +
package me.<yourname>.<pluginname>;
 +
 +
import java.util.logging.Logger;
 +
import org.bukkit.plugin.java.JavaPlugin;
 +
 +
public class <classname> extends JavaPlugin {
 +
 +
Logger log;
 +
 +
public void onEnable(){
 +
log = this.getLogger();
 +
log.info("Your plugin has been enabled!");
 +
}
 +
 +
public void onDisable(){
 +
log.info("Your plugin has been disabled.");
 +
}
 +
}
 +
</source></blockquote>
  
<pre lang="xml">
+
== イベントとリスナ ==
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 
  <modelVersion>4.0.0</modelVersion>
 
  <groupId>my.test.plugin</groupId>
 
  <artifactId>TutorialPlugin</artifactId>
 
  <version>0.0.1-SNAPSHOT</version>
 
  <build>
 
    <plugins>
 
      <plugin>
 
        <groupId>org.apache.maven.plugins</groupId>
 
        <artifactId>maven-compiler-plugin</artifactId>
 
        <configuration>
 
          <source>1.7</source>
 
          <target>1.7</target>
 
        </configuration>
 
      </plugin>
 
    </plugins>
 
  </build>
 
  <repositories>
 
    <repository>
 
      <id>spigot-repo</id>
 
      <url>https://hub.spigotmc.org/nexus/content/groups/public</url>
 
    </repository>
 
  </repositories>
 
  <dependencies>
 
    <dependency>
 
      <groupId>org.bukkit</groupId>
 
      <artifactId>bukkit</artifactId>
 
      <version>1.10.2-R0.1-SNAPSHOT</version>
 
    </dependency>
 
  </dependencies>
 
</project>
 
</pre>
 
  
pom.xmlの編集が完了したら、Ctrl + S でファイルを保存してください。
+
Minecraft1.1向けのBukkit API以降、新しいイベントの仕組みが提供されています。<BR />
 +
この新しい仕組みは、シンプルでかつ、汎用性・高速性・可読性等に優れています。<BR />
  
次に、プロジェクトを右クリックして、Maven>プロジェクトの更新... と選択してください。
+
=== チュートリアル ===
 +
当項目の、翻訳元記事で紹介されている動画を参照して下さい。<BR />
 +
http://wiki.bukkit.org/Introduction_to_the_New_Event_System#Video_Tutorial
  
[[Image:Create_project7.png]]
+
=== 基礎 ===
  
Mavenプロジェクトの更新ダイアログが開きます。そのまま OK を押してください。
+
PlayerLoginEventについて説明します。<BR />
 +
このイベントは最低限動作するための処理のみを記述するよう心がけ、<BR />
 +
極力シンプルに保ちつつ編集していきましょう。
  
[[Image:Create_project5.png]]
+
==== イベントリスナ ====
 +
まず、イベントを待ち受ける処理(Event Listenerと呼ばれます)が必要です:
 +
<blockquote><source lang="java">public void onPlayerLogin(PlayerLoginEvent event) {
 +
    // Your code here...
 +
}</source></blockquote>
 +
次に、発生するイベント(Event Handlerと呼ばれます)が必要になります。
  
Eclipseが、Bukkit API のダウンロードを開始します。<br/>
+
==== イベントハンドラ ====
しばらく待つと、プロジェクトが更新され、「Maven依存関係」というところにダウンロードされたBukkit APIが表示されます。<br/>
+
イベントハンドラはイベントリスナに対する注釈であり、次のような書き方をします:
また、JREシステム・ライブラリ のところも、指定したJavaビルドバージョンが反映されていることを確認して下さい。
+
<blockquote><source lang="java">@EventHandler // EventPriority.NORMAL がデフォルト値</source></blockquote>
 +
この記述は、メソッドがイベント優先度がNORMALのイベントハンドラである事を指定します。
  
[[Image:Create_project6.png]]
+
イベントハンドラには優先度を指定でき、次のような書き方をします:
 +
<blockquote><source lang="java">@EventHandler(priority = EventPriority.HIGHEST) // 高優先度のイベントとする
 +
@EventHandler(priority = EventPriority.LOW) // 低優先度のイベントとする</source></blockquote>
  
:'''訳者補記''': ダウンロードされた bukkit-x.x.x-Rxx.jar を右クリックし、Maven > Javadoc のダウンロード を実行しておくとよいでしょう。
+
以上をまとめると、次のようになります:
 +
<blockquote><source lang="java">@EventHandler
 +
public void onPlayerLogin(PlayerLoginEvent event) {
 +
    // Your code here...
 +
}</source></blockquote>
  
=== パッケージの作成 ===
+
==== リスナの追加 ====
 +
"PlayerListener"として拡張する場合は、"Listener"インタフェースを実装する必要があります。<BR />
 +
この時点では、次のような形のメソッドになりそうです:
 +
<blockquote><source lang="java">public class myPlayerListener implements Listener {
 +
    @EventHandler
 +
    public void onPlayerLogin(PlayerLoginEvent event) {
 +
        // Your code here...
 +
    }
 +
}</source></blockquote>
  
次に、作成したプラグインのプロジェクトに、パッケージを追加します。<br/>
+
リスナ内部のメソッドは任意の名前を付けて呼び出する事が可能であり、<BR />
「src/main/java」のところを右クリックして、新規>パッケージ と選択してください。
+
"onPlayerLogin()"のような、メソッドの名称が重要ではない事に言及しておきましょう。<BR />
 +
「Bukkitは、どのEventを識別可能でどうやってListenするのか?」と不思議に思うかもしれませんが・・・<BR />
 +
Bukkitは、あなたが指定したイベントからそれら(識別可能なEventと、そのListenの方法)を読み込みます。<BR />
 +
上記の例で言えば、PlayerLoginEventから読み込みます。
  
[[Image:Create_package1.png]]
+
:'''Note''': 特定のイベントまたはBukkitが登録しないイベントに関しては、手動で指定しなければなりません。(訳が不適切か)
  
パッケージ名は、先ほど設定したグループIDに、プラグイン名を小文字に変換した名前を後ろに付けたものが望ましいです。<br/>
+
==== イベントハンドラの設定 ====
ここでは例として、パッケージIDに '''my.test.plugin'''、プラグイン名に '''TutorialPlugin''' を使っているので、'''my.test.plugin.tutorialplugin''' と設定します。
+
イベントハンドラには、様々な内容を指定可能です。<BR />
 +
現時点では次のような指定が行えます:
 +
<blockquote>
 +
{| class="wikitable"
 +
|型
 +
|項目名
 +
|デフォルト値
 +
|概要
 +
|指定できる値
 +
|-
 +
|EventPriority
 +
|priority
 +
|EventPriority.NORMAL
 +
|リスナに指定する優先度。
 +
|
 +
* EventPriority.MONITOR
 +
* EventPriority.HIGHEST
 +
* EventPriority.HIGH
 +
* EventPriority.NORMAL
 +
* EventPriority.LOW
 +
* EventPriority.LOWEST
 +
|-
 +
|boolean
 +
|ignoreCancelled
 +
|false
 +
|この値にTrueを指定したメソッド場合は、イベントがキャンセルされた際にイベントを受け付けない。
 +
|
 +
* true
 +
* false
 +
|}
 +
</blockquote>
  
[[Image:Create_package2.png]]
+
=== イベントの登録 ===
 +
イベントを記述するクラスは、<BR />
 +
Listenerインタフェースを実装(implements)し、かつイベントハンドラを含んでいなければなりません。
  
=== メインクラスの作成 ===
+
<blockquote><source lang="java">import org.bukkit.event.Listener;
  
次に、プラグインのメインクラスを作成します。<br/>
+
public class LoginListener implements Listener {
メインクラスは、JavaPlugin を継承する必要があります。<br/>
+
}</source></blockquote>
(逆に、メインクラス以外のクラスは、直接的にも間接的にも、JavaPlugin を継承しないようにしてください。CraftBukkit 1.7.2-R0.3 以降では、プラグインが正しく動作しなくなります。)<br/>
 
メインクラスは、プラグイン名と同じ名前にすることが望ましいです。
 
  
先ほど作成したパッケージを右クリックして、新規>クラス と選択してください。
+
イベントの登録処理は、PluginManagerインスタンスのregisterEventsメソッドとして、プラグインとリスナに記述します。
 +
<blockquote><source lang="java">getServer().getPluginManager().registerEvents(Listener, Plugin);</source></blockquote>
  
[[Image:Create_package3.png]]
+
==== リスナの例 ====
 +
このリスナは、2つのイベントハンドラを含んでいます。<BR />
 +
1つは高優先度のもの、もうひとつは通常の優先度のものです。
 +
<blockquote><source lang="java">import org.bukkit.event.Listener;
 +
import org.bukkit.event.EventHandler;
 +
import org.bukkit.event.EventPriority;
 +
import org.bukkit.event.player.PlayerLoginEvent;
 +
 +
public class LoginListener implements Listener {
 +
    @EventHandler
 +
    public void normalLogin(PlayerLoginEvent event) {
 +
        // 何かの処理
 +
    }
 +
 +
    @EventHandler(priority = EventPriority.HIGH)
 +
    public void highLogin(PlayerLoginEvent event) {
 +
        // 何かの処理
 +
    }
 +
}</source></blockquote>
  
名前の欄にクラス名を入力してください。<br/>
+
==== プラグインへのイベントの登録 ====
スーパークラスの欄に「org.bukkit.plugin.java.JavaPlugin」と入力してください。<br/>
+
イベントの登録処理は、リスナとプラグインが必要です。<BR />
(参照... ボタンを押して、開いたダイアログに「JavaPlugin」と入力して該当クラスを検索して選択しても構いません。)
+
丁度よい事に、既にLoginListenerを作成していますので、これを利用してLoginPluginを作りましょう!
 +
<blockquote><source lang="java">import org.bukkit.plugin.java.JavaPlugin;
  
完了 を押して、新規クラスが作成されたことを確認して下さい。ソースコードは次のようになっているはずです。
+
public class LoginPlugin extends JavaPlugin {
 +
    public void onEnable() {
 +
        getServer().getPluginManager().registerEvents(new LoginListener(), this);
 +
    }
 +
}</source></blockquote>
  
<pre lang="java">
+
==== プラグインへのイベントのリスナとしての登録 ====
package my.test.plugin.tutorialplugin;
 
  
import org.bukkit.plugin.java.JavaPlugin;
+
メインとなるクラスもイベントを持つ事ができます。<BR />
 +
例:
  
public class TutorialPlugin extends JavaPlugin {
+
<blockquote><source lang="java">import org.bukkit.plugin.java.JavaPlugin;
 
+
import org.bukkit.event.Listener;
}
+
import org.bukkit.event.EventHandler;
</pre>
+
import org.bukkit.event.player.PlayerLoginEvent;
 
+
{{warning}} メインクラスは、コンストラクタを実行したり、新しいインスタンスを作成したりしないでください。
+
public class LoginPlugin extends JavaPlugin implements Listener {
 
+
    public void onEnable() {
=== plugin.ymlの作成 ===
+
        getServer().getPluginManager().registerEvents(this, this);
 
+
    }
メインクラスが作成できたら、次は plugin.yml ファイルを作成します。<br/>
+
plugin.yml ファイルは、プラグインとしてBukkitに読み込みされるときに、プラグインの設定を記述しておくファイルです。<br/>
+
    @EventHandler
必須のファイルですから、必ず作成してください。
+
    public void normalLogin(PlayerLoginEvent event) {
 
+
        // 何かの処理
プロジェクトの ''src/main/resources'' を右クリックして、新規>ファイル を選択してください。
+
    }
 
+
}</source></blockquote>
[[Image:Create_pluginyml1.png]]
 
 
 
開いたダイアログの ファイル名 の欄で、「plugin.yml」と入力し、完了を押してください。
 
 
 
[[Image:Create_pluginyml2.png]]
 
 
 
''src/main/resources'' のところに、''plugin.yml'' が作成されたことを確認してください。<br/>
 
作成された ''plugin.yml'' を、画面の右側へドラッグアンドドロップしてください。<br/>
 
画面右側で ''plugin.yml'' の編集画面が開きます。
 
 
 
''plugin.yml'' に、下記の3行を書いてください。
 
 
 
<syntaxhighlight lang="yaml">
 
name: (あなたのプラグイン名)
 
main: (作成したパッケージ名).(作成したメインクラス)
 
version: (あなたのプラグインのバージョン)
 
</syntaxhighlight>
 
 
 
このチュートリアルでは、次のように作成します。
 
 
 
<syntaxhighlight lang="yml">
 
name: TutorialPlugin
 
main: my.test.plugin.tutorialplugin.TutorialPlugin
 
version: 0.0.1
 
</syntaxhighlight>
 
 
 
{{note}} メインクラスの設定は、大文字小文字が区別されるので、大文字小文字に注意して設定してください。
 
{{note}} コロン(:)のあとにワンスペース( )あるのに注意してください。
 
 
 
 
 
plugin.yml の詳細な内容一覧は、[[plugin.ymlの設定一覧]] をご参照ください。
 
  
== onEnable()メソッドとonDisable()メソッド ==
+
==== リスナへのイベントの登録 ====
このメソッドは、プラグインが有効/無効になったときに、Bukkitから呼び出しされます。<br />
+
イベントの登録には複数の方法があります。リスナクラスでイベントを登録する例を記述します。
デフォルトでは、プラグインは自動的に読み込まれたときに、イベントを登録やデバッグ出力を行うことが出来ます。<br />
+
<blockquote><source lang="java">import org.bukkit.event.Listener;
onEnable()は、Bukkitが起動するときに、プラグインが有効化されたときに呼び出されます。onDisable()は、Bukkitが停止するときに、プラグインが無効化されたときに呼び出されます。<br />
+
import org.bukkit.event.EventHandler;
 
+
import org.bukkit.event.EventPriority;
=== onEnable()とonDisable()の基本 ===
+
import org.bukkit.event.player.PlayerLoginEvent;
前のセクションで作成したメインクラスに、onEnable()とonDisable()のメソッドを作成します。<br />
 
<blockquote><source lang="java">
 
package my.test.plugin.tutorialplugin;
 
 
   
 
   
import org.bukkit.plugin.java.JavaPlugin;
+
public class LoginListener implements Listener {
 +
    public LoginListener(LoginPlugin plugin) {
 +
        plugin.getServer().getPluginManager().registerEvents(this, plugin);
 +
    }
 
   
 
   
public class TutorialPlugin extends JavaPlugin {
+
    @EventHandler
 +
    public void normalLogin(PlayerLoginEvent event) {
 +
        // Some code here
 +
    }
 
   
 
   
     @Override
+
     @EventHandler(priority = EventPriority.HIGH)
     public void onEnable() {
+
     public void highLogin(PlayerLoginEvent event) {
         // TODO ここに、プラグインが有効化された時の処理を実装してください。
+
         // Some code here
 
     }
 
     }
 +
}</source></blockquote>
 +
 +
LoginPluginは次のようになります:
 +
<blockquote><source lang="java">import org.bukkit.plugin.java.JavaPlugin;
 
   
 
   
    @Override
+
public class LoginPlugin extends JavaPlugin {
     public void onDisable() {
+
     public void onEnable() {
         // TODO ここに、プラグインが無効化された時の処理を実装してください。
+
         new LoginListener(this);
 
     }
 
     }
}
+
}</source></blockquote>
</source></blockquote>
 
  
 +
=== イベントの自作 ===
 +
Bukkit自体が利用しているイベント記述の仕組みと全く同一の仕組みを利用して、
 +
イベントを自作する事ができます。
 +
この方法は、従来のような、
 +
自作イベントである事に起因する固有のチェックが不要な点、
 +
Bukkitの処理方法をそのまま利用するためにパフォーマンスを犠牲にしないという点で、
 +
従来のイベント自作の方法よりも優れています。
  
現時点では、このメソッドは何も行いません。
+
イベントを自作する際は、次の2点に留意して下さい。
 +
:* Eventクラスを継承する必要がある
 +
:* static(静的)なハンドラとして作成する必要がある
  
=== Loggerを利用したメッセージ出力 ===
+
staticハンドラは、自作イベント中に次のように記述して下さい。
 +
<blockquote><source lang="java">private static final HandlerList handlers = new HandlerList();
 +
 +
public HandlerList getHandlers() {
 +
    return handlers;
 +
}
 +
 +
public static HandlerList getHandlerList() {
 +
    return handlers;
 +
}</source></blockquote>
  
始めに、プラグインが実際に動作するかどうかを確認するため、シンプルなメッセージをサーバコンソールに表示させてみましょう。<br/>
+
上記のコードを実際に自作のイベント処理の中に記述する事で、
ログを出力するには、''getLogger()''メソッドを実行してLoggerを取得し、そのinfoメソッドを呼び出します。
+
処理は疎結合となり、実行速度が改善します。
  
<blockquote><source lang="java">
+
==== 自作イベントの例 ====
getLogger().info("onEnableメソッドが呼び出されたよ!!");
+
<blockquote><source lang="java">import org.bukkit.event.Event;
</source></blockquote>
+
import org.bukkit.event.HandlerList;
 
+
onDisable()メソッドについても同等の記述を行います。<br/>
+
public class CustomEvent extends Event {
メインクラスに、次のように実装してみてください。
+
    private static final HandlerList handlers = new HandlerList();
 
+
    private String message;
<blockquote><source lang="java">
 
package my.test.plugin.tutorialplugin;
 
 
   
 
   
import org.bukkit.plugin.java.JavaPlugin;
+
    public CustomEvent(String example) {
 +
        message = example;
 +
    }
 
   
 
   
public class TutorialPlugin extends JavaPlugin {
+
    public String getMessage() {
 +
        return message;
 +
    }
 
   
 
   
    @Override
+
     public HandlerList getHandlers() {
     public void onEnable() {
+
         return handlers;
         getLogger().info("onEnableメソッドが呼び出されたよ!!");
 
 
     }
 
     }
 
   
 
   
    @Override
+
     public static HandlerList getHandlerList() {
     public void onDisable() {
+
         return handlers;
         getLogger().info("onDisableメソッドが呼び出されたよ!!");
 
 
     }
 
     }
}
+
}</source></blockquote>
</source></blockquote>
 
  
ここまで作ったところで、[[#プラグインの配布|プラグインのJarファイルの発行]] を行ってプラグインを作成し、実際にCraftBukkitのpluginsフォルダへ導入して、コンソールに設定したログメッセージが表示されることを確認してみてください。
+
==== 自作イベントの呼び出し ====
  
=== Reloadを制御する ===
+
イベントの呼び出し方法は、従来の方法と同様です:
  
サーバーが終了処理をするときや、開始処理をするときに限らず、
+
<blockquote><source lang="java">// イベントのインスタンス化
サーバーが /reload コマンドにより、プラグインがdisableされenableされる動作について理解しておくことも重要です。<br/>
+
CustomEvent event = new CustomEvent("Sample Message");
サーバーが開始したときについてだけ初期化処理を考慮することは危険です。<br/>
+
// イベントの実行
なぜなら、プレイヤーは既にオンライン状態で接続していますし、ワールドデータやチャンクは既にロードされていますし、他にもいろいろ想定していない違いがあります。
+
Bukkit.getServer().getPluginManager().callEvent(event);
 +
// イベントから得たメッセージの出力処理
 +
Bukkit.getServer().broadcastMessage(event.getMessage());</source></blockquote>
  
* /reload が実行されると、プラグインとしては、onDisable() が実行されて、onEnable() が実行されます。
+
==== 自作イベントの待ち受け ====
* staticで保持していないデータは、全て失われます。
+
イベントはどのようにListen(待受,受付などとも表記)すれば良いでしょう?
* 上記に書いてあるように、プレイヤーやワールドやチャンクは既にロード済みの状態です。
+
簡単です。通常のイベントと同様に待ち受けして下さい。
 
+
<blockquote><source lang="java">import org.bukkit.event.Listener;
== イベントとリスナ ==
+
import org.bukkit.event.EventHandler;
 
+
:: ''[[新しいEventSystemの使い方]]を参照して下さい''
+
public class CustomListener implements Listener {
 +
    @EventHandler
 +
    public void normalLogin(CustomEvent event) {
 +
        // 何かの処理
 +
    }
 +
}</source></blockquote>
  
 
== コマンド ==
 
== コマンド ==
365行目: 372行目:
 
さて、どのようにイベントを登録しいつ発生するかについて理解しました。
 
さて、どのようにイベントを登録しいつ発生するかについて理解しました。
 
しかし、コマンドを利用して何かを起こしたい場合はどのようなデータ型を利用すればよいのでしょうか?それには、onCommand()メソッドを利用します。
 
しかし、コマンドを利用して何かを起こしたい場合はどのようなデータ型を利用すればよいのでしょうか?それには、onCommand()メソッドを利用します。
このメソッドは、plugin.ymlに設定したプラグインのコマンドが実行されたときに呼び出されます。
+
このメソッドは、プレイヤーが文字"/"を入力する度に実行されます。
 +
具体的には、"/do something"とコマンドを実行した場合にonCommand()が呼び出されます。
 
今のところ、onCommand()はまだプログラムしていないので何も起こらないでしょう。
 
今のところ、onCommand()はまだプログラムしていないので何も起こらないでしょう。
  
373行目: 381行目:
 
具体的には、"give"コマンドは既にいくつかのプラグインで利用されています。
 
具体的には、"give"コマンドは既にいくつかのプラグインで利用されています。
 
もし独自に"give"コマンドを実装した場合は、
 
もし独自に"give"コマンドを実装した場合は、
"give"コマンドを実装している他のプラグインとの互換性は無くなります。<ref group="注">実際には、相互のコマンドを呼び分けるために特定のプレフィクスがコマンドの前に付与されます。しかしそれでも、単にgiveコマンドを呼んだだけではどのコマンドが呼ばれるかわからないことには変わりありません。</ref>
+
"give"コマンドを実装している他のプラグインとの互換性は無くなります。
  
onCommand()は、常にboolean型の値<ref group="注">trueかfalseのどちらか</ref>を戻り値として返さねばなりません。
+
onCommand()は、常にboolean型の値としてtrue,falseのどちらかを戻り値として返さねばなりません。
 
trueを返した場合は、情報表示のためのイベントは発生しません。
 
trueを返した場合は、情報表示のためのイベントは発生しません。
 
falseを返した場合は、プラグインファイルを"usage: property"に戻し、コマンドを実行したプレイヤーに、コマンドの利用方法を通知するメッセージを表示します。
 
falseを返した場合は、プラグインファイルを"usage: property"に戻し、コマンドを実行したプレイヤーに、コマンドの利用方法を通知するメッセージを表示します。
384行目: 392行目:
 
* Command cmd - 実行されたコマンドの内容
 
* Command cmd - 実行されたコマンドの内容
 
* String commandLabel - 利用されたコマンドエイリアス
 
* String commandLabel - 利用されたコマンドエイリアス
* String[] args - コマンドの引数を格納した配列(例:/hello abc defコマンドが入力された場合の内容は、args[0]がabc、args[1]がdefとなる)<ref group="注">半角空白 (U+0020)で分割されて、配列に格納される</ref>
+
* String[] args - コマンドの引数を格納した配列(例:/hello abc defコマンドが入力された場合の内容は、args[0]がabc、args[1]がdefとなる)
  
 
=== コマンドの設定 ===
 
=== コマンドの設定 ===
413行目: 421行目:
 
       description: This is a demo command.
 
       description: This is a demo command.
 
       usage: /<command> [player]
 
       usage: /<command> [player]
       permission: tutorialplugin.basic
+
       permission: <plugin name>.basic
 
       permission-message: You don't have <permission>
 
       permission-message: You don't have <permission>
 
</source>
 
</source>
* basic - コマンド名。
+
* basic - コマンド名
* description - コマンドの説明文。
+
* description - コマンドの説明文
* usage - コマンドの使い方。onCommand() でfalseを返したときに、コマンド実行ユーザに向けて表示されるメッセージの内容。あなたの作ろうとしているコマンドの使い方を、わかりやすく説明してください。
+
* usage - onCommand()がfalseを返した際に、コマンド実行ユーザに向けて表示されるメッセージの内容。コマンドの使い方を明解に書いてください。
* permission - コマンドの実行権限。このコマンドの実行に必要なパーミッションノードを設定します。あなたのプラグイン名と、コマンド名を、ピリオド(.)でつなげたパーミッションノードを設定することを推奨します(例:myplugin.test)。
+
* permission - 当コマンドの動作に必要なプラグインの設定を、コマンド実行ユーザに知らせるメッセージ。(主に、コマンド実行に必要なpermissionを書きます)
* permission-message - 上で設定したコマンド実行権限を持たないユーザがコマンドを実行した場合に、実行権限が無いことを同ユーザに知らせるメッセージ。
+
* permission-message - コマンド実行権限を持たないユーザがコマンドを実行した場合に、その旨を同ユーザに知らせるメッセージ。
 
</blockquote>
 
</blockquote>
  
なお、usage の欄では <command>、permission-message の欄では <permission> というキーワードをそのまま指定できます。それぞれ、設定したコマンド名と、設定したパーミッションノードに置き換えられます。<br>
+
:'''Note''': ymlファイルには、1個タブを2個のスペースで記述する必要があります。タブ文字は構文エラーとなるため利用できません。
詳しい書き方は、[[plugin.ymlの設定一覧#コマンドのオプション設定|plugin.ymlの書き方の、コマンドのオプション設定の節]] を参照してください。
 
 
 
:'''Note''': ymlファイルには、インデントに2個以上の半角スペースを記述する必要があります。タブ文字は構文エラーとなるため利用できません。
 
  
 
=== コンソールコマンドとプレイヤーコマンド ===
 
=== コンソールコマンドとプレイヤーコマンド ===
440行目: 445行目:
 
記述例:  
 
記述例:  
 
<blockquote><source lang="java">
 
<blockquote><source lang="java">
@Override
 
 
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
 
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (cmd.getName().equalsIgnoreCase("basic")) {  
+
Player player = null;
// プレイヤーが /basic を実行すると、この部分の処理が実行されます...
+
if (sender instanceof Player) {
 +
player = (Player) sender;
 +
}
 +
 
 +
if (cmd.getName().equalsIgnoreCase("basic")){ // If the player typed /basic then do the following...
 +
// do something...
 
return true;
 
return true;
 
} else if (cmd.getName().equalsIgnoreCase("basic2")) {
 
} else if (cmd.getName().equalsIgnoreCase("basic2")) {
                // プレイヤーが /basic2 を実行すると、この部分の処理が実行されます...
+
if (player == null) {
if (!(sender instanceof Player)) {
+
sender.sendMessage("this command can only be run by a player");
sender.sendMessage("このコマンドはゲーム内から実行してください。");
 
 
} else {
 
} else {
Player player = (Player) sender;
+
// do something else...
// コマンドの実行処理...
 
 
}
 
}
 
return true;
 
return true;
457行目: 464行目:
 
return false;
 
return false;
 
}
 
}
</source> </blockquote>
+
</source> </blockquote>  
  
 
この例では、'''basic''' コマンドはログインプレイヤーとサーバコンソールのどちらからでも実行できます。しかし、'''basic2''' コマンドは、ログインプレイヤーしか実行できません。
 
この例では、'''basic''' コマンドはログインプレイヤーとサーバコンソールのどちらからでも実行できます。しかし、'''basic2''' コマンドは、ログインプレイヤーしか実行できません。
466行目: 473行目:
 
凝ったコマンドを作りたい場合、コマンドのパラメタ(上記例では <code>'''args'''</code>パラメタ)を利用して独自の処理実装を行うことができます。例えば、プレイヤー名を指定したテレポートコマンドのみが、サーバコンソールから実行できる実装にする等が考えられます。
 
凝ったコマンドを作りたい場合、コマンドのパラメタ(上記例では <code>'''args'''</code>パラメタ)を利用して独自の処理実装を行うことができます。例えば、プレイヤー名を指定したテレポートコマンドのみが、サーバコンソールから実行できる実装にする等が考えられます。
  
:'''訳者補記''': コマンド実装方法には、プレイヤー向け・サーバコンソール向けの2種類があり、それぞれの区別はどのような考え方で行うべきかについて説明しています。
+
=== CommandExecutorクラスの分離利用 ===
  
=== CommandExecutorのクラス分割 ===
 
  
上記の例では、onCommand()メソッドをプラグインのメインクラスに記述していました。小さなプラグインでは良い方法ですが、大きなプラグインに拡張していくのであれば、適切なクラスを作成してそちらに配置するべきです。幸い、難しい事ではありません:
 
  
* プラグインのpackage内に、'''MyPluginCommandExecutor''' のような名前で新規のコマンド実行クラスを作成する(当然、MyPluginはあなたのプラグイン名に合わせて変えましょう)。
+
The examples above just put the onCommand() method into the plugin's main class. For small plugins, this is fine, but if you're writing something more extensive, it may make sense to put your onCommand() method into its own class. Fortunately, this isn't too hard:
* MyPluginCommandExecutorに、BukkitのCommandExecutorインタフェースを実装(implements)させる。
 
* プラグインのonEnable()メソッドの処理で、MyPluginCommandExecutorクラスのインスタンスを生成する。
 
* MyPluginCommandExecutorインスタンスをパラメタとして、処理<code>'''getCommand("basic").setExecutor(myExecutor);'''</code>を実行させる。
 
  
:'''Note''': <code>'''"basic"'''</code>は実行されたコマンドであり、<code>'''myExecutor'''</code>はMyPluginCommandExecutorインスタンスです。
+
    Create a new class within your plugin's package. Call it something like MyPluginCommandExecutor (although of course replacing MyPlugin with your plugin's actual name). That class must implement the Bukkit CommandExecutor interface.
とっても良い具体例:
 
  
MyPlugin.java (プラグインのメインクラス):
+
    In your plugin's onEnable() method, you need to create an instance of your new command executor class, and then make a call like getCommand("basic").setExecutor(myExecutor);, where "basic" is the command we want to handle, and myExecutor is the instance we created.
<blockquote><source lang="java">
 
@Override
 
public void onEnable() {
 
// plugin.yml に basic というコマンドを定義していないと、
 
        //実行した時にNullPointerExceptionが発生します。注意してください。
 
getCommand("basic").setExecutor(new MyPluginCommandExecutor(this));
 
}
 
</source></blockquote>
 
  
MyPluginCommandExecutor.java:
+
Best explained by example:
<blockquote><source lang="java">
 
public class MyPluginCommandExecutor implements CommandExecutor {
 
  
        // メインクラスの参照です。処理の中でメインクラスのメソッドを利用しない場合は、省略して構いません。
+
MyPlugin.java (the main plugin class):
private final MyPlugin instance;
 
  
public MyPluginCommandExecutor(MyPlugin plugin) {
+
    private MyPluginCommandExecutor myExecutor;
this.plugin = plugin;
+
    @Override
}
+
    public void onEnable() {
 +
    // ....
 +
   
 +
    myExecutor = new MyPluginCommandExecutor(this);
 +
    getCommand("basic").setExecutor(myExecutor);
 +
   
 +
    // ...
 +
    }
  
@Override
+
MyPluginCommandExecutor.java:
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
 
// コマンドの実行内容...
 
}
 
}
 
</source></blockquote>
 
どのように、メインプラグインのインスタンスが'''MyPluginCommandExecutor'''のコンストラクタを実行するかに注目しましょう。
 
  
この節で紹介した方法により、メインのonCommand()メソッドが巨大で複雑になったとしても簡単に整理する事ができ、結果として、プラグインのメインクラスを複雑化させずに、処理分割する事ができます。
+
    public class MyPluginCommandExecutor implements CommandExecutor {
 
+
   
:'''Note''': プラグインが複数のコマンドを持つ場合、個々のコマンドに対応する'''CommandExecutor'''をコーディングする必要があります。
+
    private MyPlugin plugin;
 
+
   
:'''訳者補記''': 積極的に、大きな処理は小さく分割していきましょう。そのための仕組みをBukkitが用意しています。という事を教示しています。
+
    public MyPluginCommandExecutor(MyPlugin plugin) {
 
+
    this.plugin = plugin;
== 堅牢なonCommandの記述 ==
+
    }
onCommand()メソッドを記述する際、パラメタの利用に関して、<br/>
+
   
決め付けて掛かってはいけない事がありますので念頭において下さい。<br/>
+
    @Override
これらに留意した処理を記述する事で、堅牢なonCommand()をコーディングする事ができます。
+
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
 
+
    // ... implementation exactly as before ...
=== senderの内部データ型をチェックする ===
+
    }
senderの内部データがPlayer型であるとは限らない事を念頭において、チェックを行って下さい。<br/>
 
処理例:
 
<blockquote><source lang="java">
 
@Override
 
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args){
 
    if (sender instanceof Player) {
 
        Player player = (Player) sender;
 
        // ここに、処理を実装する。
 
        return true;
 
    } else {
 
        sender.sendMessage(ChatColor.RED + "ゲーム内から実行してください!");
 
        return false;
 
 
     }
 
     }
    return false;
 
}
 
</source> </blockquote>
 
  
このように、'''<code>if (sender instanceof Player)</code>''' で必ずPlayerであることをチェックしないと、プレイヤーでないコマンド実行者(例えばコンソール)がコマンドを実行したときに、'''<code>Player player = (Player) sender</code>''' のところで処理が失敗してしまいます。
+
Notice how we pass an instance of the main plugin to the constructor for MyPluginCommandExecutor. This allows us easy access to the main plugin's methods if we need to.
  
=== コマンドのパラメタ長をチェックする ===
+
By doing this, we can better organise our code - if the main onCommand() method is large and complex, it can be split into submethods without cluttering up the plugin's main class.
senderインスタンスは、妥当なパラメタを持っているとは限りません。パラメタ長をチェックして下さい。<br/>
 
処理例:
 
<blockquote><source lang="java">public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args){
 
if (args.length > 4) {
 
          sender.sendMessage(ChatColor.RED + "パラメタが多すぎます!");
 
          return false;
 
        }
 
        if (args.length < 2) {
 
          sender.sendMessage(ChatColor.RED + "パラメタが足りません!");
 
          return false;
 
        }
 
}</source> </blockquote>
 
  
=== プレイヤーがオンラインである事を確認する ===
+
Note that if your plugin has multiple commands, you will need set the command executor for each command individually.
特定のプレイヤーのPlayerインスタンスを利用したい場合、必ずそのプレイヤーがオンラインである必要があります。<br/>
 
オンラインであるかどうかをチェックして下さい。<br/>
 
Bukkit.getPlayer(プレイヤー名) または、Bukkit.getPlayerExact(プレイヤー名) で、オンラインのプレイヤーを取得できます。<br/>
 
(Bukkit.getPlayer はプレイヤー名と前方一致で、Bukkit.getPlayerExact は完全一致で、プレイヤーを取得します。)<br/>
 
もし、指定したプレイヤーがオフラインだった場合は、nullが返されます。<br/>
 
処理例:
 
  
<blockquote><source lang="java">
+
== 堅牢なonCommandの記述 ==
@Override
 
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
 
    if (args.length < 1) {
 
        sender.sendMessage("コマンドの後にプレイヤー名を指定してください!");
 
        return false;
 
    }
 
    Player target = Bukkit.getPlayerExact(args[0]);
 
    if ( target == null ) {
 
        sender.sendMessage(ChatColor.RED + args[0] + "さんはオフラインです!");
 
        return true;
 
    } else {
 
        sender.sendMessage(ChatColor.AQUA + args[0] + "さんはオンラインです!");
 
        return true;
 
    }
 
}
 
</source> </blockquote>
 
 
 
オンラインではないプレイヤーのインスタンスに操作を加えたい場合は、一般的には<code>'''OfflinePlayer'''</code>クラスを利用して行う事ができます。
 
  
 
== プラグインのConfiguration/Settings ==
 
== プラグインのConfiguration/Settings ==
:: ''[[新しいConfigurationの使い方]]を参照して下さい ''
 
 
== 権限 ==
 
:'''Note''': この節は、日本語読者向けに独自の内容を記述しています。
 
 
Bukkitにおける権限の利用は、とっても簡単です!
 
 
権限がセットされているか、いない(Javaの'''null'''と同等)かを調べるには以下のメソッドを利用します:
 
<blockquote><source lang="java">boolean isPermissionSet(String name)</source></blockquote>
 
 
また、権限を持っているかどうかを調べるには以下のメソッドを利用します:
 
<blockquote><source lang="java">boolean hasPermission(String name)</source></blockquote>
 
 
これを利用してプレイヤーが特定の権限を持っているかどうかを調べる処理は次のようになります:
 
<blockquote><source lang="java">if(player.hasPermission("some.pointless.permission")) {
 
  player.sendMessage("あなたは権限を持っています。");
 
}else{
 
  player.sendMessage("あなたは権限を持っていません。");
 
}</source></blockquote>
 
 
2メソッドの違いは、権限がセットされていなくてもデフォルトで与えられていれば権限を持っているという扱いになるかどうかです。<br>
 
hasPermissionでは デフォルトで与えられていればtrueが返ります。
 
 
PermissionsExなどで 権限はグループとして扱われることが多いですが、Bukkitには権限をグループとして扱う機能はありません。<br/>
 
グループとして扱う場合は、別途 上記のようなプラグインを使うか、自分で作る必要があります。
 
 
=== 権限の設定 ===
 
 
デフォルトで権限を付与させたり、OPにのみデフォルトで付与させたい場合は、<br>
 
''plugin.yml''を使うと簡単にできます。
 
 
下記は、''plugin.yml''の最後に追加する形で設定する権限です:
 
<blockquote>
 
<syntaxhighlight lang="yaml">
 
permissions:
 
    doorman.*:
 
        description: Gives access to all doorman commands
 
        children:
 
            doorman.kick: true
 
            doorman.ban: true
 
            doorman.knock: true
 
            doorman.denied: false
 
    doorman.kick:
 
        description: Allows you to kick a user
 
        default: op
 
    doorman.ban:
 
        description: Allows you to ban a user
 
        default: op
 
    doorman.knock:
 
        description: Knocks on the door!
 
        default: true
 
    doorman.denied:
 
        description: Prevents this user from entering the door
 
</syntaxhighlight>
 
</blockquote>
 
  
 
+
== パーミッション ==
まず、プラグインが利用する各権限を、''permissions''ノードの子ノードとして定義します。<br/>
 
それぞれの権限はオプションとして、概要(description)、デフォルト値、子ノードを持ちます。
 
 
 
==== デフォルト権限 ====
 
 
 
プレイヤーが権限を持たない場合、&nbsp;''hasPermission''&nbsp;はデフォルトではfalseを返します。<br/>
 
''plugin.yml''中のデフォルトのノードに対して、下記の4つのどれか1つを設定する事で、<br/>
 
この挙動を変更する事ができます:
 
*'''true''' - デフォルトで、権限を持つ(=hasPermissionがtrueを返す)。
 
*'''false''' - デフォルトで、権限を持たない(=hasPermissionがfalseを返す)。
 
*'''op''' - プレイヤーがOPであれば、権限を持つ(=hasPermissionがtrueを返す)。
 
*'''not op''' - プレイヤーがOPでなければ、権限を持つ(=hasPermissionがtrueを返す)。
 
 
 
==== 子権限 ====
 
 
 
権限を設定するときに''* 権限''を利用すると、その権限の子権限すべてを操作することができます。<br/>
 
これは、変更されたBukkit APIと、子権限の定義によって実現した機能であり、<br/>
 
高い柔軟性を提供しています。<br/>
 
下記はその実装例です:
 
<blockquote>
 
<syntaxhighlight lang="yaml">
 
permissions:
 
    doorman.*:
 
        description: Gives access to all doorman commands
 
        children:
 
            doorman.kick: true
 
            doorman.ban: true
 
            doorman.knock: true
 
            doorman.denied: false</source>
 
</syntaxhighlight>
 
''doorman.*''権限は、いくつかの子権限を含んでいます。
 
''doorman.*''権限がtrueである場合に、
 
その子権限は''plugin.yml''に定義された値(trueかfalse)をデフォルト権限として機能します。
 
''doorman.*''権限がfalseである場合は、
 
その子権限のデフォルト権限は、全て反転(trueが定義値ならfalseになる)された状態で機能します。
 
</blockquote>
 
 
 
ねっ、簡単でしょ?
 
 
 
=== 独自の権限設定 ===
 
 
 
独自に権限の仕組みを提供するプラグインを開発したい場合、&nbsp;[[権限プラグインの開発方法]]を参考にして下さい。
 
  
 
== スケジューリングタスクとバックグラウンドタスク ==
 
== スケジューリングタスクとバックグラウンドタスク ==
 
現在、Minecraftサーバはゲームロジックのほとんどがシングルスレッドで稼動しています。<br/>
 
このため、発生する個々の処理はごく小さいものにする必要があります。<br/>
 
プラグイン中に複雑なコードが存在して、それが適切に処理されないような場合は、<br/>
 
ゲームロジックに多大なラグや処理遅延を発生させる原因となります。<br/>
 
 
幸運なことに、Bukkitはプラグインに対してスケジューリングのためのコーディング方法を提供しています。<br/>
 
どこかのタイミングで一度だけRunnableタスクを実行したり、<br/>
 
小さなタスクに分けた定期的な繰り返しであったり、<br/>
 
新規に独立したスレッドを派生させたり・・・<br/>
 
といった複数の方法で、長大なタスクをゲームロジックと並行で処理させる事ができます。
 
 
詳しくは、[[スケジューラのプログラミング]]中の、同期タスクと非同期タスクのスケジューリング方法に関する解説を参考にして下さい。
 
  
 
== ブロックの操作 ==
 
== ブロックの操作 ==
 
ブロックを生成する簡単な方法は、既存のブロックを取得して変更する事です。<br/>
 
例えば、あなたの5ブロック上方にあるブロックを変更したい場合、<br/>
 
まずはそのブロックを取得した上で、変更を加えることになります。<br/>
 
PlayerMoveイベントの処理中でこれを行う例を示します:
 
<blockquote><source lang="java">
 
@EventHandler
 
public void onPlayerMove(PlayerMoveEvent evt) {
 
    // プレイヤーの位置を取得します。
 
    Location loc = event.getPlayer().getLocation();
 
    // 位置のY座標を+5します。位置情報を変更しているだけで、実際にプレイヤーの位置が移動するわけではないことに注意してください。
 
    loc.setY(loc.getY() + 5);
 
    // 指定位置のブロックを取得します。
 
    Block b = loc.getBlock();
 
    // ブロックの種類に石(STONE)を設定します。
 
    b.setType(Material.STONE);
 
}</source></blockquote>
 
 
このコードの処理は、プレイヤーが移動する(=PlayerMoveイベントが発生する)度に、<br/>
 
プレイヤーの5ブロック上方のブロックがStoneに変化する動作として見えるでしょう。<br/>
 
ブロック取得までの流れは・・・
 
# 取得したプレイヤーの位置から、ワールドを取得する
 
# 位置のY座標を+5する
 
# <code>'''loc.getBlockAt(loc);'''</code>で、指定位置に存在するブロックを得る
 
となります。<br/>
 
 
位置(''loc'')中のブロックインスタンス(''b'')に対して、<br/>
 
Materialを変えたり、ブロックデータ自体を変更する事もできます。
 
詳しくは、JavaDocを参照してください。<br/>
 
 
建物の生成や、一定のアルゴリズムに従ったブロック生成処理などを行う一例を示します。<br/>
 
例えば、固体ブロックによる立方体を生成する処理は、<br/>
 
3階層にネストしたforループ処理によって記述できます。
 
<blockquote><source lang="java">
 
    public void generateCube(Location loc, int length){
 
        // 与えられたLocationから、立方体の端の座標を取得します。
 
        // getN()メソッドを使うと intへキャストする必要がありますが、
 
        // getBlockN()メソッドを使えばそのままintで座標を取得できます。
 
        int x1 = loc.getBlockX();
 
        int y1 = loc.getBlockY();
 
        int z1 = loc.getBlockZ();
 
   
 
        // 一辺の長さを足すことで、立方体の反対側の座標を計算します。
 
        int x2 = x1 + length;
 
        int y2 = y1 + length;
 
        int z2 = z1 + length;
 
   
 
        World world = loc.getWorld();
 
   
 
        // x座標方向のループ
 
        for (int xPoint = x1; xPoint <= x2; xPoint++) {
 
            // y座標方向のループ
 
            for (int yPoint = y1; yPoint <= y2; yPoint++) {
 
                // z座標方向のループ
 
                for (int zPoint = z1; zPoint <= z2; zPoint++) {
 
                    // ループで処理する座標のブロックを取得します。
 
                    Block currentBlock = world.getBlockAt(xPoint, yPoint, zPoint);
 
                    // ダイアモンドブロックに設定します!
 
                    currentBlock.setType(Material.DIAMOND_BLOCK);
 
                }
 
            }
 
        }
 
    }
 
</source></blockquote>
 
 
このメソッドは、辺の長さと開始点の指定を受けて、任意のサイズと位置を持つ直方体を生成する処理です。<br/>
 
ブロックの削除処理の場合も、このロジックを真似て同様のアルゴリズムで実装する事ができます。<br/>
 
ただし、セットするブロックの種類はMaterial.AIRになりますね。
 
  
 
== プレイヤーインベントリの操作 ==
 
== プレイヤーインベントリの操作 ==
 
この節では、プレイヤーのインベントリ操作を特に扱っていますが、<br/>
 
チェストのインベントリの操作にも適用できますので、必要なら応用して下さい(゚∀゚)<br/>
 
インベントリ操作のシンプルな例:
 
<blockquote><source lang="java">public void onPlayerJoin(PlayerJoinEvent event) {
 
    Player player = event.getPlayer(); // Joinしたプレイヤー
 
    PlayerInventory inventory = player.getInventory(); // プレイヤーのインベントリ
 
    ItemStack diamondstack = new ItemStack(Material.DIAMOND, 64); // 山積みのダイヤモンド!
 
 
    if (inventory.contains(diamondstack)) {
 
        inventory.addItem(diamondstack); // プレイヤーインベントリに山積みのダイヤモンドを加える
 
        player.sendMessage(ChatColor.GOLD + "よく来たな!もっとダイヤモンドをくれてやろう、このとんでもない成金め!!");
 
    }
 
}</source> </blockquote>
 
 
さて、onPlayerJoin()メソッドの先頭で<br/>
 
'''player''', '''inventory'''、'''diamondstack'''変数を用意して下さい。<br/>
 
'''inventory'''はプレイヤーのインベントリで、'''diamondstack'''は(アイテムとしての)64個のダイヤモンドです。
 
 
次に、プレイヤーのインベントリがダイヤモンドを含んでいるかをチェックします。<br/>
 
プレイヤーがダイヤモンドをインベントリに所持している場合、<br/>
 
<code>'''inventory.addItem(diamondstack)'''</code>処理にて<br/>
 
同プレイヤーのインベントリに別のスタックを与え、黄金色のメッセージを送信します。<br/>
 
インベントリ操作は全然難しくありません。
 
 
ダイヤモンドのスタックを削除したい場合でも単純に、<br/>
 
<code>'''inventory.addItem(diamondstack)'''</code>を<br/><code>'''inventory.remove(diamondstack)'''</code>に置き換えるだけです。<br/>
 
(メッセージにも少しイタズラしておきましょう)
 
  
 
== アイテムの操作 ==
 
== アイテムの操作 ==
アイテムはスタックという単位で操作します。<br/>
 
スタックデータに対する全ての操作は、[http://jd.bukkit.org/apidocs/org/bukkit/inventory/ItemStack.html ItemStackクラスの仕様]を参照して下さい。
 
 
=== エンチャント ===
 
 
アイテムにエンチャントを付与するには、ItemStackクラスの '''addEnchantment(Enchantment enchant, int level)''' メソッドを使用します。
 
 
addEnchantment()メソッドでは、元々エンチャントが出来ないアイテムに対して、独自にエンチャントを付与する処理は書けません。<br/>
 
もし、通常ありえないエンチャントを設定したい場合は、addEnchantment()メソッドの代わりにaddUnsafeEnchantment()メソッドを使ってください。
 
 
Sharpness 1 エンチャントを石の剣に付与する例を示します。
 
<blockquote><source lang="java">
 
// 新しい石の剣を生成します。
 
ItemStack myItem = new ItemStack(Material.STONE_SWORD);
 
 
// エンチャントを付与します。
 
myItem.addEnchantment(Enchantment.DAMAGE_ALL, 1); 
 
</source></blockquote>
 
 
次に、火属性 100 を、木の棒に付与する例を示します。
 
<blockquote><source lang="java">
 
// 新しい木の棒を生成します。
 
ItemStack myItem = new ItemStack(Material.STICK);
 
 
// 木の棒にFireAspectレベル100を付与します。
 
// ただしFireAspectレベル100は通常存在しないので、addEnchantment を使うと失敗します。
 
// ありえないエンチャントを設定したい場合は、addUnsafeEnchantment を使ってください。
 
myItem.addUnsafeEnchantment(Enchantment.FIRE_ASPECT, 100); 
 
</source></blockquote>
 
 
=== ItemMeta ===
 
 
アイテムの表示名を変更するには、次のようにします。
 
<blockquote><source lang="java">
 
String myDisplayName = "すごい剣";
 
 
ItemStack myItem = new ItemStack(Material.DIAMOND_SWORD);  //アイテムを生成します。
 
ItemMeta im = myItem.getItemMeta(); //ItemStackから、ItemMetaを取得します。
 
im.setDisplayName(myDisplayName); //アイテム表示名を設定します。
 
myItem.setItemMeta(im); //元のItemStackに、変更したItemMetaを設定します。
 
</source></blockquote>
 
 
次に、loreを設定してみましょう。loreは、ゲーム内でアイテムにカーソルを合わせたときに表示される説明文のことです。
 
<blockquote><source lang="java">
 
List<String> lores = new ArrayList<String>();
 
lores.add("loreのテストです。");
 
lores.add("これは2行目です。");
 
 
ItemStack myItem = new ItemStack(Material.DIAMOND_SWORD);  //アイテムを生成します。
 
ItemMeta im = myItem.getItemMeta(); //ItemStackから、ItemMetaを取得します。
 
im.setLore(lores); //loreを設定します。
 
myItem.setItemMeta(im); //元のItemStackに、変更したItemMetaを設定します。
 
</source></blockquote>
 
  
== Metadata ==
+
== HashMapの応用 ==
  
Bukkit では、プラグインの開発をより簡単にするため、Playerクラス、Entityクラス、Worldクラスに紐づく追加データをMetadataという形式で管理できるようになっています。
+
== Map・Set・Listの応用 ==
今までは、それぞれのプラグイン内で、Player、Entity、World などをキーとしたHashMap型の変数内で管理していたと思いますが、それをMetadataで置き換えすることができます。
 
Metadataのデータは、全てMetadatableのメンバーで構成されます([http://jd.bukkit.org/doxygen/de/d59/interfaceorg_1_1bukkit_1_1metadata_1_1MetadataValue.html#ab49975fe013a0626dd29d3b85c63a82f javadoc]も参照してください)。
 
動作は非常に単純です。
 
Metadatableクラスは、それぞれのインスタンスが自分のMetadataのHashMapを持っています。
 
つまり例えば、経済プラグインを作る場合、HashMap<Player, Double> のようなデータをプラグイン内で持つ必要はありません。
 
プレイヤーにMetadataを直接設定すればよいのです!
 
 
 
=== Metadataを使うメリット ===
 
 
 
* Metadataは全てBukkit側で管理されます。プラグイン側で管理する必要がありません。
 
* プラグイン間で共通にアクセスできるので、データの共有に使用できます。
 
 
 
=== Metadataを使うデメリット ===
 
 
 
* データの取得・設定を行うときに、ひと手間が必要になります。
 
* Bukkitが停止すると、全てのMetadataが消えます。
 
 
 
=== Metadataの使い方 ===
 
 
 
<source lang="java">
 
 
 
    /**
 
    * PlayerにMetadataを設定するサンプルメソッドです。
 
    * @param player 対象プレイヤー
 
    * @param key Metadataのキー名
 
    * @param value Metadataの値
 
    * @param plugin プラグインクラス
 
    */
 
    public void setMetadata(Player player, String key, Object value, Plugin plugin) {
 
        player.setMetadata(key, new FixedMetadataValue(plugin, value));
 
    }
 
 
 
    /**
 
    * PlayerからMetadataを取得するサンプルメソッドです。
 
    * @param player 対象プレイヤー
 
    * @param key Metadataのキー名
 
    * @param plugin プラグインクラス
 
    * @return Metadataの値
 
    */
 
    public Object getMetadata(Player player, String key, Plugin plugin) {
 
        List<MetadataValue> values = player.getMetadata(key);
 
        for (MetadataValue value : values) {
 
            if (value.getOwningPlugin().getDescription().getName()
 
                    .equals(plugin.getDescription().getName())) {
 
                return value.value();
 
            }
 
        }
 
        return null;
 
    }
 
</source>
 
 
 
:'''Note''': もしあなたが、必ず boolean、int、String としてMetadataの値を取得したいのであれば、asBoolean()、asInt()、asString() メソッドを使うことで、キャストせずに直接取得が可能です。
 
  
 
== データベース ==
 
== データベース ==
時にフラットファイルは、データベースとして利用するには不足があるでしょう。
 
Linux/Mac/Windowsのマシンにおいて、もっとも汎用的なデータベースはSQL(Structured Query Language)です。
 
 
ソフトウェアとしてのSQLは、個々のデータを格納するセルと、それらを識別するための列およびヘッダから成るデータベースを生成します。
 
会計用ソフトウェア(たとえばエクセルのような)の表が、より便利になったモノを思い浮かべてください。
 
SQLは、この表形態のデータに、データ同士の整合性の確保を目的とした独自のルール付けが行え、
 
かつ、フラットなファイルよりも高速で高機能なデータ利用のための方法も提供します。
 
 
Bukkitは、SQLの標準的な機能を利用するための仕組みを提供しています。
 
残念なことに、SQLには複数の種類が存在し、それぞれの設定方法と利用方法が少しずつ異なっています。
 
各自のニーズに応じて、好きな種類のSQLを選んで利用してください。(プラグインについても、利用するデータベースの種類に応じて複数の接続・利用方法が利用できます)
 
 
=== SQLite  ===
 
 
Alta189は、ダウンロード・インポートによって導入や移動が容易に可能なSQLiteを、Bukkitのプラグインで利用するためのライブラリを使う方法のチュートリアル、[http://forums.bukkit.org/threads/lib-tut-mysql-sqlite-bukkit-drivers.33849/ fantastic SQLite tutorial]を書きました。
 
 
SQLの構文については、次に紹介する動画を一度見てみる事をお勧めします。簡単な内容なので短時間で済みます。[http://www.w3schools.com/sql/default.asp SQL Tutorials @W3Schools]
 
 
SQLiteは、その稼動のためにサーバを構築する必要がないため、シンプルさにおいて非常に優れています。
 
新規にデータベースとその中のテーブルを作成する手順は少量です。また、データのバックアップも、1個のデータベースファイルをバックアップするだけです。ただし、データ間の整合性の確保や柔軟性、データ件数が100万を超えるような膨大なデータの扱いにおいては、多少弱い面もあります。
 
 
とはいえSQLiteは、SQLデータベースを利用する新規プラグインの開発作業を、迅速で簡単にしてくれるメリットがあります。また、サーバ向けの大規模なSQLの予習のためにも有用です。
 
 
=== MySQL  ===
 
もうひとつ、人気があるSQLにMySQLというものがあります。
 
SQLiteよりもサーバ寄りの用途をもった種類のSQLで、多くの有名な企業の業務システムや、一日に100万アクセスを捌くようなウェブサイトが、この機能に依存しています。ただし、チューニング可能な範囲や機能が多岐に渡るため、セキュリティ上のリスクが、データベース管理者のMySQLへの習熟度に大きく左右されます。
 
 
プラグインからMySQLを利用する処理のコーディング自体は、小規模なSQLiteからMByte単位のOracleのデータベースに対するものと、大差ありません。しかし、サーバ用途のデータベースの管理作業は、どんどん増えていくものです。使い続ける内に、データベース利用者のアカウントや権限の設定作業を行う事になっていくでしょう。また、データのバックアップやバックアップからの復旧(Rollbackと呼ぶ)作業のために、SQL文のスクリプトを書く事にもなるはずです。
 
  
 
== プラグインの配布 ==
 
== プラグインの配布 ==
 
プラグインを実装し終わったら、Mavenを使ってビルドして、リリース用のJarファイルを作成してみましょう。
 
 
プロジェクトを右クリックして、実行>Maven install と選択してください。
 
 
[[Image:Plugin_deploy1.png]]
 
 
Eclipseのコンソールに、ビルド情報が流れます。<br/>
 
ビルドがうまくいけば、コンソールに「BUILD SUCCESS」と表示されてビルドが終了します。<br/>
 
もしビルドが失敗したなら、エラー情報を元に、エラーの解決を試みてください。
 
 
このチュートリアルで紹介したJDKが同梱のPleiadesを利用していない場合、MavenがJDKを見つけられずにエラーになっていることが多いです。<br/>
 
その場合は、Eclipseの設定を開いて、正しいJDKを選択しなおしてください。<br/>
 
Eclipseの設定は、「ウィンドウ」メニュー>設定 を選択し、開いたダイアログで、Java>インストール済みのJRE を選択します。<br/>
 
ここで、正しいバージョンのJDKが選択されていることを確認してください。
 
 
このチュートリアルで紹介したJDKが同梱のPleiadesを利用している場合で、
 
<blockquote>
 
[ERROR] Unable to locate the Javac Compiler in:<br/>
 
[ERROR] C:\pleiades\java\7\..\lib\tools.jar
 
</blockquote>
 
のようなエラーが出ることがあります。これは上記のメッセージの通り、最初から同梱されているJDKにtools.jarが含まれているのに参照設定されていないからです。<br/>
 
これを解決するには、次のようにします。
 
*Pleiadesのメニューから、ウィンドウ > 設定 と選び、設定ダイアログを表示します。
 
*設定ダイアログの左側で、java > インストール済みのJRE と選びます。
 
*使用しているJRE(先ほどのエラーメッセージに含まれるファイルパスと、ロケーションが、一致するもの)を選択し、「編集...」を押します。
 
*JREの編集ダイアログで、「外部Jar追加...」を押し、tools.jarを探して選択します。例えばエラーメッセージが「C:\pleiades\java\7\..\lib\tools.jar」なら、「C:\pleiades\java\7\lib\tools.jar」に見つかるはずです。
 
*「OK」を押して、設定ダイアログを閉じます。
 
*再度、「mvn install」を実行して、今度は正常にビルドができることを確認してください。
 
 
ビルドがうまくいった場合、プロジェクトのフォルダの中に target フォルダが作成されており、そのフォルダの中にビルドされたJarファイルがあります。
 
 
[[Image:Plugin_deploy2.png]]
 
 
 
プラグインのコードとplugin.ymlに不備が無ければ、エクスポートしたJarファイルはすぐにBukkitプラグインとして動作します。Jarファイルを、Bukkitサーバの'''"plugins"'''フォルダの中に配置し、Bukkitサーバを起動し、プラグインの動作確認をしてみましょう。なお、ローカルマシン上で起動するBukkitサーバへは、Minecraftクライアントのマルチプレイヤーサーバの接続先IPアドレスに'''"localhost"'''を指定して接続する事でログインできます。
 
 
もしプラグインが上手く動かず、それがどうしても自分で解決できない場合は、当Wikiやその原文をもう一度よく読み、それでも駄目なら[http://forums.bukkit.org/forums/plugin-development.5/ Bukkitプラグイン開発者フォーラム(英語圏)], [http://wiki.bukkit.org/IRC bukkitdev Bukkit公式サイトの開発者向けIRCチャンネル(英語圏)], [http://forum.minecraftuser.jp/viewforum.php?f=21 マインクラフト非公式日本ユーザフォーラムの関連トピック(日本語圏)], [http://minecraftjp.info/modding/index.php/Minecraft_Modding_Wiki#IRC 当WikiのMOD制作関連IRCチャンネル(日本語圏)]をたずねてみて下さい。有用なプラグインが作れたら、[http://dev.bukkit.org/ dev.bukkit]に登録し、プラグインを広く公開する事を検討してみて下さい。他のBukkitユーザ・開発者に貢献する事ができます。
 
  
 
== ヒントとノウハウ ==
 
== ヒントとノウハウ ==
CraftBukkit APIは、すばらしい機能をたくさん提供しています。
 
下記に、面白い効果を実現するコードを示します。
 
 
=== プレイヤーに着火する ===
 
下記は、指定されたプレイヤーに着火するサンプルです。例えば '''/ignite Notch''' と実行すると、Notchが燃えます!
 
<blockquote><source lang="java">
 
@Override
 
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
 
    // equals() の代わりに equalsIgnoreCase() を使うと、大文字小文字に関係なく、
 
    // 文字列の一致を確認できます。"ignite"でも"IgNiTe"でも指定可能になります。
 
    if (cmd.getName().equalsIgnoreCase("ignite")) {
 
        // コマンドのパラメータに、燃やすプレイヤーが指定されているかどうかを
 
        // 確認します。
 
        if (args.length != 1) {
 
            // onCommandでfalseを戻すと、plugin.ymlのusageに設定したメッセージを
 
            // コマンド実行者の画面に表示します。
 
            return false;
 
        }
 
   
 
        // 燃やすプレイヤーを取得します。
 
        Player target = Bukkit.getPlayerExact(args[0]);
 
   
 
        // 対象プレイヤーが、オンラインかどうかを確認します。
 
        if (target == null) {
 
            sender.sendMessage(args[0] + " というプレイヤーが見つかりません!");
 
            return true;
 
        }
 
   
 
        // 対象プレイヤーを、1000tick(=50秒) の間、燃えるようにします。
 
        target.setFireTicks(1000);
 
        return true;
 
    }
 
    return false;
 
}
 
</source> </blockquote>
 
 
=== プレイヤーを殺す ===
 
 
同じ要領で、プレイヤーを殺害するコマンドの例を紹介します。
 
onCommand()メソッドに記述します:
 
<blockquote><source lang="java">
 
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args){
 
    if(cmd.getName().equalsIgnoreCase("KillPlayer")){
 
        // コマンドのパラメータに、殺害するプレイヤーが指定されているかどうかを
 
        // 確認します。
 
        if (args.length != 1) {
 
            // onCommandでfalseを戻すと、plugin.ymlのusageに設定したメッセージを
 
            // コマンド実行者の画面に表示します。
 
            return false;
 
        }
 
        Player target = Bukkit.getPlayerExact(args[0]);
 
        // 対象プレイヤーがオンラインかどうかを確認します。
 
        if (target == null) {
 
            sender.sendMessage(args[0] + " というプレイヤーは見つかりません!");
 
            return true;
 
        }
 
        // 対象に1000ダメージを与えます。
 
        target.damage(1000);
 
        return true;
 
    }
 
    return false;
 
}
 
</source></blockquote>
 
 
上記の拡張版として、プレイヤーを爆死させる処理を下記に示します:
 
<blockquote><source lang="java">
 
@Override
 
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
 
    if(cmd.getName().equalsIgnoreCase("KillPlayer")){
 
        Player target = Bukkit.getPlayerExact(args[0]);
 
        // 対象プレイヤーがオンラインかどうかを確認します。
 
        if (target == null) {
 
            sender.sendMessage(args[0] + " というプレイヤーは見つかりません!");
 
            return true;
 
        }
 
        float explosionPower = 4F; // 爆発の大きさです。1Fでガストの火球、3Fでクリーパーの爆発、4FでTNTの爆発 に相当します。
 
 
        // 爆発を起こしつつ、対象に1000ダメージを与えます。
 
        target.getWorld().createExplosion(target.getLocation(), explosionPower);
 
        target.damage(1000);
 
        return true;
 
    }
 
    return false;
 
}
 
</source> </blockquote>
 
 
=== 爆発を起こす ===
 
このコードは、TNTの爆発と同様の音とヴィジュアルを再現します。
 
これは、TNTの爆発効果は無効化しつつ、音とヴィジュアル効果を発生させる処理に転用できます。
 
<blockquote><source lang="java">
 
@EventHandler
 
public void onExplosionPrime(ExplosionPrimeEvent event) {
 
    Entity entity = event.getEntity();
 
 
    // このイベントは、点火されたTNTにより発生したのかどうかを確認します。
 
    // (つまり、TNTの爆発はこれで無効化されますが、クリーパーの爆発は無効化されません)
 
    if (entity instanceof TNTPrimed) {
 
        event.setCancelled(true); // イベントをキャンセルして、爆発を無かったことにする
 
        entity.getWorld().createExplosion(entity.getLocation(), 0); // 偽物の爆発を発生させる
 
    }
 
}
 
</source></blockquote>
 
 
=== プレイヤーを非表示にする ===
 
 
これは指定したプレイヤーから自分を非表示にするサンプルです。
 
指定したプレイヤー以外のプレイヤーからは、自分が見えたままになっています。
 
 
<blockquote>
 
<source lang="java">
 
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
 
    if(cmd.getName().equalsIgnoreCase("HideMe") && args.length == 1) {
 
 
        // コマンド実行者がプレイヤーかどうかを確認します。
 
        if (!(sender instanceof Player)) {
 
            sender.sendMessage("このコマンドはゲーム内から実行してください!");
 
            return true;
 
        }
 
        // sender instanceof Player の検査が終わっているので、Playerクラスへ安全にキャストできます。
 
        Player s = (Player) sender;
 
 
        // コマンドのパラメータに、対象のプレイヤーが指定されているかどうかを確認します。
 
        if (args.length != 1) {
 
            // onCommandでfalseを戻すと、plugin.ymlのusageに設定したメッセージを
 
            // コマンド実行者の画面に表示します。
 
            return false;
 
        }
 
 
        // 指定されたプレイヤーを取得します。
 
        // 指定されたプレイヤーがサーバーに接続していない場合、targetはnullになります。
 
        Player target = Bukkit.getPlayerExact(args[0]);
 
        if (target == null) {
 
            sender.sendMessage("Player " + args[0] + " というプレイヤーは見つかりません!");
 
            return true;
 
        }
 
        // プレイヤー "s" を、指定したプレイヤー "target" から、非表示に設定します。
 
        target.hidePlayer(s);
 
        return true;
 
    }
 
    return false;
 
}
 
</source>
 
</blockquote>
 
 
=== クリックした場所に雷を落とす ===
 
 
下記のサンプルは、釣竿を持ってクリックしたときに、クリックした場所を取得して、その場所に雷を落とします。
 
 
<blockquote>
 
<source lang="java">
 
@EventHandler
 
public void onPlayerInteractBlock(PlayerInteractEvent event) {
 
 
    Player player = event.getPlayer();
 
 
    if (player.getItemInHand().getType() == Material.FISHING_ROD) {
 
        // プレイヤーが見ている場所に雷をおとします。
 
 
        Block target = getTargetBlock(player);
 
        if (target != null) {
 
            target.getWorld().strikeLightning(target.getLocation());
 
        }
 
    }
 
}
 
 
private Block getTargetBlock(Player player) {
 
   
 
    // 視線上のブロックを100ブロック先まで取得
 
    BlockIterator it = new BlockIterator(player, 100);
 
 
    // 手前側から検証を行う。
 
    // Blockが取得できた時点でreturnして終了する。
 
    while ( it.hasNext() ) {
 
 
        Block block = it.next();
 
 
        if ( block.getType() != Material.AIR ) {
 
            // ブロックが見つかった
 
            return block;
 
        }
 
    }
 
 
    // 最後までブロックがみつからなかった
 
    return null;
 
}
 
</source>
 
</blockquote>
 
 
 
== プラグインのサンプル兼雛形 ==
 
* [http://pastebin.com/fKjjReyv Example.Java]
 
* [http://pastebin.com/VhNBnLPU ExamplePlayerListener.Java]
 
* [http://pastebin.com/dRVeQKjw ExampleBlockListener.Java]
 
* [http://pastebin.com/GG5R4vAn ExampleEntityListener.Java]
 
 
この内容について質問がある場合、遠慮なく[http://forums.bukkit.org/members/adamki11s.42417/ Adamki11s]か[http://wiki.bukkit.org/IRC BukkitDevのIRCチャンネル](当Wikiの原文を掲載しているサイトのIRCチャンネルです)で聞いてください。
 
:'''Note''': 当ページは訳文であるため、訳文自体に対する文責は原著者にありません。その点を考慮して必ず原文にも目を通してから質問して下さい。
 
 
[[カテゴリ:Bukkitチュートリアル|*]]
 

Minecraft Modding Wikiへの投稿はすべて、他の投稿者によって編集、変更、除去される場合があります。 自分が書いたものが他の人に容赦なく編集されるのを望まない場合は、ここに投稿しないでください。
また、投稿するのは、自分で書いたものか、パブリック ドメインまたはそれに類するフリーな資料からの複製であることを約束してください(詳細はMinecraft Modding Wiki:著作権を参照)。 著作権保護されている作品は、許諾なしに投稿しないでください!

このページを編集するには、下記の確認用の質問に回答してください (詳細):

取り消し 編集の仕方 (新しいウィンドウで開きます)

このページで使用されているテンプレート: