【Kotlin】Spigot プラグイン開発 チュートリアル

# はじめに
Minecraftプラグインの作成に関する記事が少なく、ましてやKotlinで作ってみたものはさらに少ないので、チュートリアルを作成してみました。
これからプラグインを作りたいという方はJavaよりKotlinが書きやすくておすすめなので、ぜひ参考にしてください。

コードはこちらにあります。
[SamplePlugin](https://github.com/kanakiyo314/SamplePlugin)

# そもそもKotlinって？
説明に入る前に、Kotlinについて少し触れておきましょう。
KotlinはJavaと完全互換の言語です。
2017年5月にGoogleがAndroid開発言語に選定してから、徐々に人気を伸ばしてきました。（おかげで、Androidの情報ばかりで、マイクラのプラグインの記事なんて数えるほどしかありません）
― [【TechCrunch】Google、KotlinをAndroidアプリ開発言語に選定](https://jp.techcrunch.com/2017/05/18/20170517google-makes-kotlin-a-first-class-language-for-writing-android-apps/)

その特徴はなんといっても、**Null Safety**です。
Javaで開発していると、必ずといって現れるNullException...これが**コンパイルの時点で防げる**ということ。
ああ、Null Safety、なんて甘美な響きでしょう。

とはいえ、JavaのライブラリやAPIを併用することもあるので、NullExceptionを完全に防ぐことはできません。
Nullableな変数を指定すれば、Nullの代入を許してしまうので、あくまでNullExceptionが発生しにくくなったぐらいで考えておくと良いかもしれません。

他にもJavaとの違いをあげると

- セミコロンがいらない
- 三項演算子の代わりにif（Kotlinではifは関数）
- 型推論（型指定が省略できる）
- 変数宣言にvar（書き換え可）、val（書き換え不可）がある

などなど完全互換といえど、Javaと異なる点はいくつもあります。似て非なる言語です。
JavaとKotlinの違いに関する記事はいくつも出されていますので、ここでは割愛します。
― [【Qiita】はじめてのKotlin。Javaと比較してみた
](https://qiita.com/hituziando/items/fa2dc4097b24ab78276e)

それでは、プラグインの開発環境を構築しましょう。

# 開発環境構築
私の環境です。

| 項目 | 値 |
|:-:|:-:|
| OS | Windows10 |
| メモリ | 16GB |
| IntelliJ IDEA Version | 2019.1 (Ultimate Edition) |

## IntelliJ IDEA インストール
まずはKotlinの開発環境を整えます。Kotlinの開発環境は[IntelliJ IDEA](https://www.jetbrains.com/idea/)一択かと思います。IntelliJ IDEAはKotlinの開発元であるJetBrains社が提供しているIDEです。よほどの理由がない限り、IntelliJ IDEAを使いましょう。

- [IntelliJ IDEA 公式](https://www.jetbrains.com/idea/)
- [IntelliJ IDEA インストール手順](http://trelab.info/intellij-idea/intellij-idea-install/)

ちなみに筆者の

## Minecraft Development 追加
インストールが終わったらプロジェクトを作成する前に、IntelliJ IDEAのプラグインとしてMinecraft Developmentを追加します。これを導入することで、SpigotやBukkit用のテンプレートが作成できるようになります。

IntelliJ IDEAが起動したら、`File` -> `Settings`でSettingsウィンドウを開きます。
ウィンドウの左メニューから`Plugins`を選択し、検索ウィンドウに"minecraft"と入力します。
![install_minecraft_develpment.png](https://qiita-image-store.s3.amazonaws.com/0/267005/68a1378b-c95c-a40c-429f-e892a194fca0.png)

検索結果に`Minecraft Development`があるので、`Install`ボタンを押してプラグインを適用します（図ではすでにインストールされているので、`Installed`となっています）。

もし、Kotlinプラグインも入っていなければ、同様の手順で導入してください。検索ワードは`kotlin`でOKです。
これで開発環境は整いました。続いて、プロジェクトの作成を行います。

# プロジェクト作成
プロジェクトの作成は`File` -> `New` -> `Project`で行います。
`New Project`ウィンドウが開くので、左メニューから`Minecraft`を選び、`Choose plugin type`で`Spigot Plugin`にチェックを入れ、`Next`ボタンを押してください。Build Setting画面になります。
![select_spigot.png](https://qiita-image-store.s3.amazonaws.com/0/267005/56645cf5-2549-a82e-f5b0-323144083127.png)

もし、左メニューに`Minecraft`がない場合は、Minecraft Developmentプラグインが入っていないということです。プラグインが入っているかどうか確認してください。

## Build Setting
ここではGroupId、ArtifactId、Versionを指定します。今回は例の通りに設定します。

|     項目     | 説明 | 例 |
|:--           |:--  |:-- |
| GroupId      | 団体やグループのユニークなID | com.sample |
| ArtifactId   | 生成されるjarファイルのバージョン抜きの名前  | Sample |
| Version      | プラグインのバージョン  | 1.0-SNAPSHOT |

ここで、**注意!**
デフォルトではMavenとなっていますが、**Gradle**に変更してください。
Mavenでやりたいって人は構いませんが、よく分からないって人はGradleをおすすめします。
MavenはXMLで設定するので、読みづらく設定もしずらいです。
この後の解説もGradle前提で行います。

![build_settings.png](https://qiita-image-store.s3.amazonaws.com/0/267005/c6382129-ccb3-7466-5967-492c389305e3.png)

入力し終えたら、`Next`ボタンを押します。

## Spigot Settings
Spigot Settingsでは、プラグイン名やメインクラス名の指定を行います。Minecraftのバージョンもここで指定するので、導入したいMinecraftのバージョンにあわせましょう。特になければ最新版を選択すればOKです。
また、メインクラス名は`プラグイン名 + Plugin`がおすすめです。メインクラスは`JavaPlugin`を継承することになるので、命名規則の都合上`プラグイン名 + Plugin`となることが多いです。
![Spigot_settings.png](https://qiita-image-store.s3.amazonaws.com/0/267005/1958fd73-b6f6-7bbf-f594-f24e6a54aae1.png)

入力が完了したら、`Next`ボタンを押して次に進みます。

## ディレクトリ指定
最後の設定画面です。
ここではディレクトリ名を指定します。プロジェクトには直接関係はありません。
分かりやすい名前をつけましょう。
ディレクトリの場所を変更したい人は`Project location`から指定が可能です。

![Project directory.png](https://qiita-image-store.s3.amazonaws.com/0/267005/9bc17f64-c390-65ca-5c6c-9d64057f25c8.png)

最後に`finish`を押せばプロジェクトの作成は完了です！
`Import Module from Gradle`というウィンドウが出てくるかもしれませんが、OKで大丈夫です。

# まだ半分です...
「これで開発できる!」といいたいんですが、もう少しやることがあります。
JavaをKotlinにコンバートする作業です。他にもGradle編集や最低限の設定が残っています。

# Convert Java File to Kotlin File
SpigotはJavaで作成されているので、プラグインテンプレートもJavaで作成されています。
Kotlinで書くには自動生成されたJavaコードをコンバートしなければなりません。
とはいえ、リファクタリングするまでもなく、IntelliJ IDEAの機能で自動変換してくれます。

Projectメニューに表示されているディレクトリから`src` -> `main` -> `java`を選択してください。
選択したら、メニューバーの`Code` -> `Convert Java File to Kotlin File`をクリックすれば、自動でコードをKotlinに書き直してくれます。

ついでに、ディレクトリ名も`java`から`kotlin`に変更しておきましょう。
![Convert Java File to Kotlin File.png](https://qiita-image-store.s3.amazonaws.com/0/267005/fcdda293-f9c4-319d-a71a-f567890cb64e.png)

# build.gradleの編集
チュートリアル最大の山場、Gradleです。
Gradleとはビルドシステムのことで、依存関係やビルド方法を記述したものになります。
Gradleの記述を間違えると、「コードは正しいのに動かない」なんてこともしばしばですので、間違いなく書いていきましょう。

## 不要なファイルの削除
実はIntelliJ IDEAが自動生成したファイルの中に、不要なものがあります。ルートディレクトリの.ideaディレクトリにある`iml`ファイルです。これはIntelliJ IDEAの設定ファイルですが、これが原因で`build.gradle`に不要な警告（黄色の網掛け）が表示されてしまいます。特に必要のないファイルとのことなので、`build.gradle`を編集する前に削除しておきましょう。
もし、心配な人はバックアップを取っておくと良いと思います。

`iml`ファイルを削除したら、`Build` -> `Rebuild Project`からプロジェクトをリビルドしましょう。警告が表示されなくなるはずです。

## buildscript, dependencies, jarの変更・追記
Kotlinや外部ライブラリ周りの依存関係を追記していきます。
今回は以下のように記述しました。

```title:build.gradle
buildscript {
    ext {
        junit_version = '4.12'
        kotlin_version = '1.3.21'
        spigot_version = '1.13.2-R0.1-SNAPSHOT'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.21"
    }
}

apply plugin: 'java'
apply plugin: 'kotlin'

group = pluginGroup
version = pluginVersion

sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenCentral()
    maven {
        name = 'spigotmc-repo'
        url = 'https://hub.spigotmc.org/nexus/content/groups/public/'
    }
    maven {
        name = 'sonatype'
        url = 'https://oss.sonatype.org/content/groups/public/'
    }
}

dependencies {
    testImplementation group: 'junit', name: 'junit', version: junit_version
    testRuntimeOnly group: 'junit', name: 'junit', version: junit_version
    compile "org.spigotmc:spigot-api:$spigot_version"
    compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}

import org.apache.tools.ant.filters.ReplaceTokens

processResources {
    from(sourceSets.main.resources.srcDirs) {
        filter ReplaceTokens, tokens: [version: version]
    }
}

jar {
    from {
        configurations.compile.collect {
            it.isDirectory() ? it : zipTree(it)
        }
    }
}

```
主要な部分についてだけ解説します。
## buildscript ブロック
まずは`build.gradle`の先頭に`buildscript`を追記しましょう。
`buildscript`はビルドスクリプト自体が依存しているライブラリを指定するブロックになります。今回はKotlinのGradleプラグインを利用するために必要な記述です。他に各ライブラリのバージョンもここで指定すると、管理が楽になります。

```title:build.gradle
buildscript {
    ext {
        junit_version = '4.12'
        kotlin_version = '1.3.21'
        spigot_version = '1.13.2-R0.1-SNAPSHOT'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.21"
    }
}
...
```

## dependencies ブロック
`dependencies`ブロックはその名の通り、ライブラリの依存関係を記述する場所になります。
バージョンは`buildscript`の`ext`ブロックで記述したのでそれを参照します。
今回はSpigotの他にKotlinのライブラリも使うので、これらを記述します。
また、テスト用にJunitライブラリも入れておきます。

```title:build.gradle
...
dependencies {
    testImplementation group: 'junit', name: 'junit', version: junit_version
    testRuntimeOnly group: 'junit', name: 'junit', version: junit_version
    compile "org.spigotmc:spigot-api:$spigot_version"
    compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
...
```

## jar ブロック
`jar`ブロックではjarファイルに出力に関する記述を行います。
ここでは外部ライブラリをjarに含める処理を書いています。
これを記述しないと、jarファイルに外部ライブラリが含まれず、実行エラーを引き起こす恐れがあります。
jarファイルが大きくなる原因にもなりますが、依存プラグインを持たせたくないのであれば、この記述は必須になります。

```title:build.gradle
...
jar {
    from {
        configurations.compile.collect {
            it.isDirectory() ? it : zipTree(it)
        }
    }
}
```

最後にビルドをして、エラーが出なければOKです。
何かしらのエラーが出た場合、`build.gradle`に不備があるということです。
もう一度、`build.gradle`を見直してみましょう。

# plugin.ymlの編集
これが最後の手続きになります。
作ったプラグインに関する情報が書かれている`plugin.yml`を編集しましょう。
ymlファイルについては、別記事を参照してください。
― [【Qiita】YAML 基本記法まとめ
](https://qiita.com/tfrcm/items/5f8e4c5795ce41b214d1)

`plugin.yml`は`src` -> `resources`ディレクトリの中にあります。

```title:plugin.yml
name: Sample
version: @version@
main: com.tklcraft.sample.SamplePlugin
api-version: '1.13'
author: kanakiyo314
```
まず、api-versionはシングルクォーテーション`''`で囲みましょう。
Stringが実数になっていると警告が表示されてしまいます。

そして大事なのが`author`の記述です。
誰が作ったのかは大変重要な情報なので漏れなく書き込みましょう。
何より、動作テストのときに表示させると**とても感動します**。

authorが複数いる場合は、
`authors: [authorA, authorB]`
と記述することで、`author`を複数記述できます。

# 動作テスト
最後に動作テストです。
ビルドできても動かないなんてことはザラなので、きちんと確認しましょう。

ビルドで生成されがjarファイルは`ルートディレクトリ` -> `build` -> `lib`にあります。
それを通常のプラグインと同様に`plugins`フォルダにコピーすれば準備は完了です。
サーバを起動してみましょう。

サーバログに`[Sample] Enabling Sample v1.0-SNAPSHOT`と表示されれば成功です（プラグイン名、バージョンは設定した値）。

ついでに`about プラグイン名`でコマンドを入力してみましょう。すると…
![about command.png](https://qiita-image-store.s3.amazonaws.com/0/267005/1411c4ef-8659-79ce-9767-27b111fc0a7a.png)

どうですか？
ちょっと感動しませんか？

ここまで来れば、プラグイン開発の準備は完全に整いました。
もうこれで、バリバリコードが欠けます！

# 最後に
Minecraftのプラグイン作成に関する記事はとても少ないです（Kotlinならなおさら…）。
今回は誰もが苦労するであろう部分を重点的にまとめてみました。

次回はプラグインの作り方についてのチュートリアルでも書こうかと思います。

# 参考リンク
- [【公式】Kotlin](https://kotlinlang.org/)
- [【TechCrunch】Google、KotlinをAndroidアプリ開発言語に選定](https://jp.techcrunch.com/2017/05/18/20170517google-makes-kotlin-a-first-class-language-for-writing-android-apps/)
- [【ブログ】Android公式言語 Kotlinとはどんな言語でどんなメリットがあるのか？！](https://eigoninaritai.com/about_kotlin_of_official_language_on_android/)
- [【Qiita】はじめてのKotlin。Javaと比較してみた
](https://qiita.com/hituziando/items/fa2dc4097b24ab78276e)
- [【ブログ】KotlinのNull安全ってどうなの？！検証も交えてまとめてみた！](https://eigoninaritai.com/null_safety_in_kotlin/)
- [【SlideShgare】Gradle 入門](https://www.slideshare.net/orekyuu/gradle-36782786)
- [【Spigot】How to use Kotlin in your plugins](https://www.spigotmc.org/wiki/how-to-use-kotlin-in-your-plugins/)
- [【Qiita】Gradleを始めてみよう](https://qiita.com/3bch/items/639bc0a4afaa7c79a124)
- [【Qiita】KotlinでSpigotプラグインを作るためのbuild.gradle](https://qiita.com/m4kvn/items/5e4829964ad780155b8f)
- [【公式】Kotlin using Gradle](https://kotlinlang.org/docs/reference/using-gradle.html)
- [【stack overflow】IntelliJ IDEA and Gradle - Cannot be applied to '(groovy.lang.Closure)'] (https://stackoverflow.com/questions/32905270/intellij-idea-and-gradle-cannot-be-applied-to-groovy-lang-closure)
- [【Qiita】YAML 基本記法まとめ
](https://qiita.com/tfrcm/items/5f8e4c5795ce41b214d1)