KotlinでDiscord Botを始めてみる1 ~環境構築・起動編~

# はじめに
この記事はKotlinを使ってDiscord Botを開発する上で一番最初の関門となる**環境構築からBotの起動まで**の解説です。
#### 対象読者

- Botアカウントを作成してトークンの取得くらいはできる
- Kotlin(やJava)未経験あるいは触り始めたばかり
- 人気のPythonやJS以外の言語で背伸びしたい

※他言語、特にDiscord.pyやDiscord.jsの経験があればよりスムーズに読めると思いますが無くても問題はありません。

### 教材リポジトリ作りました。
[私のGithub](https://github.com/hisuie08/)にて、当記事の[コードをまとめたリポジトリ](https://github.com/hisuie08/kotlin-tutorial-bot/)を作りました。
ブランチで段階を区切っております。今回は[Chapter1ブランチ](https://github.com/hisuie08/kotlin-tutorial-bot/tree/chapter1)に対応させてください。


#基本編
## そもそもKotlinって
JavaのIDE(統合開発環境)の大手メーカー JetBrains社が開発したJavaベースのオブジェクト指向言語です。

- Javaに比べシンプルで可読性の高い構文
- Null安全を追求した堅牢な設計
- Javaとの親和性が非常に高く、既存Javaライブラリをそのまま使い、クラスやメソッドを呼び出せる

特に3番目の特徴が非常に重要で、Javaの遺産を流用できるおかげで言語の中では比較的後発ながらも**ライブラリやツールには事欠かない**、スムーズなスタートを切ることができるのです。
今回Discord Bot開発に使うライブラリも本来はJava用であったものを流用していきます。

## 用語
#### Kotlin
今回使うプログラミング言語。詳細は上記参照
####IntelliJ IDEA
Kotlinの開発に使うIDE(統合開発環境)。以下IDEA
#### [JDA](https://github.com/DV8FromTheWorld/JDA)
正式名称は「Java Discord API」。Discord.pyやDiscord.jsと同じDiscordAPIライブラリ。
Java用ではあるが前述の通りKotlinでも支障なく使用できる。

#### Gradle
オープンソースのビルド自動化システム。前提ライブラリ等の依存関係解決やビルドをスムーズに行う他、JSのnpmやPythonのpipのように記述した依存ライブラリを自動的にリモートサーバーから取得してプロジェクトに組み込む事ができる。今回はこれを使ってJDAをインストールする。

# 環境構築編

##Java(OpenJDK)のインストール
前述したようにKotlinはJavaベースゆえ、Kotlinプログラムを動かすにはJavaがコンピューターにインストールされている必要があります。
<details><summary>**JDK(Java Development Kit)**という、Java実行環境と開発ツールがセットになったパッケージをインストールしましょう。</summary>
余談ですが、JDKとよく混同されるJRE(Java Runtime Environment)は前者の実行環境のみを指します。
JDKにはJREが含まれているので両方を入れる必要はありません。</details>

Javaがオープン化して以降、「Java=Oracle」の構図が崩れ、様々なベンダーがJDKをリリースしています。
私は~~Botとは全く関係ない理由で~~[BellSoft](https://bell-sw.com/)の**Liberica JDK**を好んで使っています。
大して違いはないのでベンダーは好みで選んで良いですが、バージョンは最新版の**16**か、長期サポート対象最新版の**11**をおすすめします。
インストールしたらパスを通すのを忘れないでください。


##IDEAのインストール
今回はJetBrainsのIDE **IntelliJ IDEA**を使用します。
総本山が出しているIDEだけあってKotlinのサポートが手厚く、スムーズに始めることができます。

[IntelliJ IDEA ダウンロードページ](https://www.jetbrains.com/ja-jp/idea/download/)
有償のUltimate版と無償のCommunity版がありますが、無償版で十分です。

インストールオプションで、PATHの追加と、すべての拡張子の連携、そして「フォルダをプロジェクトとして開く」にチェックを入れておいてください。
デスクトップショートカットと32bitランタイムはお好みで構いません。

##IDEA初回起動からプロジェクト作成
さあ、一気に行きますよ。
IDEAを初めて起動すると規約同意ページが出ることがあります。同意して進んでください。
### 日本語化
IDEAのUIはデフォルトでは英語になっています。英語でも問題ないという方は飛ばして構いません。
[IDEA日本語化プラグイン](https://plugins.jetbrains.com/plugin/13964-japanese-language-pack------/)をインストールして、IDEAを再起動すると日本語化できます。

### 初めてのプロジェクト作成
1. 「**新規プロジェクト**」をクリックします。
1.  左のプロジェクト種類リストから「Kotlin」...ではなく**「Gradle」を選択**してください。![IntelliJ IDEA へようこそ 2021_06_18 14_38_17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398976/83acc503-fe38-0ea0-40f0-49df41d1bd89.png)

1. 「プロジェクトSDK」を選びます
1. 「**Kotlin DSLビルドスクリプト**」、追加のライブラリとフレームワークから「**Java**」、「**Kotlin/JVM**」にチェックを入れ、次に進みます
1. 名前と場所は自由で構いません。
1. アーティファクトのコーディネートは現段階ではあまり重要ではありませんが、独自ドメインをお持ちの方はそれを、Githubアカウントを持っていればプロフィールのURLを、グループID欄へドメインレベルの高い順に「.」区切りで記載してください(例:`com.github.hisuie08`)。
1. アーティファクトIDは名前と同じで構いません。
1. バージョンはそのままで構いません。![IntelliJ IDEA へようこそ 2021_06_18 14_39_07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398976/04ee6252-d102-2c3e-8347-0fa6cf090907.png)

1. 完了をクリックし、しばらく待ちますとプロジェクトの雛形が作成されます
1. 画面下のログに`BUILD SUCCESSFUL in ...`と出ていたら成功です。

## Discord Bot開発の下準備
### gradle バージョンのアップデート
まず、IDEAデフォルトのgradleバージョンが少し古いのでバージョンアップしましょう。
`Alt`+`F12` でターミナルを開き、

```
> gradle wrapper --gradle-version 7.0.2
```
を入力。
しばらくお待ち下さい。
`BUILD SUCCESSFUL in ...`
が出れば成功です。

### build.gradle.kts
`build.gradle.kts`ファイルを開きましょう。
指定ブロック内に追記してください。

```gradle:build.gradle.kts
plugins {
    ...
    application /*追記*/
    id("com.github.johnrengelman.shadow") version "7.0.0" /*追記*/
}
...
repositories {
    ...
    maven("https://m2.dv8tion.net/releases") /*追記*/
}
...
dependencies {
    ...
    implementation("net.dv8tion:JDA:[バージョン]") /*追記*/
    /*
    バージョンはhttps://github.com/DV8FromTheWorld/JDA/releases より参照して適宜変更してください。
    */
}

application {/*applicationブロックごと追記*/
    mainClass.set("${group}.${rootProject.name}.MainKt")
    /*pluginブロック内のapplicationと同時に書いた場合ブロックに警告が出ますが続行してください。*/
}
```
「Gradleの変更を読み込む」をクリックしてください。
`BUILD SUCCESSFUL in ...` とログが出れば成功です。
いよいよBotプログラムを書いていきましょう。

# 開発編
## パッケージとメインファイルの作成
左のプロジェクトツリーから
`[プロジェクト名]`>`src`>`main`>`kotlin`
ディレクトリを見つけてください。無ければ作成しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398976/4b962986-8a2a-7866-8b61-f3ecd05540bd.png)


次に`kotlin`ディレクトリを右クリック→新規→パッケージを選択し、ダイアログに
`[グループID].[アーティファクトID]`
を入力してください。
入力した名前で新しく階層が掘られたと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398976/e5f477b6-3505-c46b-0fd5-070efb29940a.png)

ここにいよいよメインプログラムを書いていきます。
ファイル名は`main`でいきましょう。
掘った階層で右クリック→新規→Kotlinクラス/ファイル→名前に`main`で作成しましょう。
1行目に

```kotlin:main.kt
package [グループID].[アーティファクトID]
```

とだけ書かれたソースコードが出来ましたか？

##最小限のソースコード
最初から出してしまいます。

```kotlin:main.kt
package ...

import net.dv8tion.jda.api.JDA
import net.dv8tion.jda.api.JDABuilder
import net.dv8tion.jda.api.events.ReadyEvent
import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent
import net.dv8tion.jda.api.hooks.ListenerAdapter
import net.dv8tion.jda.api.requests.GatewayIntent

class BotClient : ListenerAdapter(){
    lateinit var jda: JDA
    
    fun main(token: String) { //トークンを使ってBotを起動する部分
        jda = JDABuilder.createLight(token,
            GatewayIntent.GUILD_MESSAGES)
            .addEventListeners(this)
            .build()
    }
    
    override fun onReady(event: ReadyEvent) { //Botがログインしたときの処理
        println("起動しました")
    }
    
    override fun onGuildMessageReceived(event : GuildMessageReceivedEvent) {
        //Botがメッセージを受信したときの処理
        if(event.message.contentDisplay == "/neko"){//メッセージ内容を確認
            event.channel.sendMessageFormat("にゃーん").queue() //メッセージ送信
        }
    }
}

/*Kotlinではコード中から単体main関数を探して最初に実行します。
そこでmain関数にBotClientクラスのインスタンス作成とトークンを渡した起動処理mainメソッドを実行させる形でBotを起動します。
*/
fun main() {
    val bot = BotClient()
    bot.main("トークン文字列")
}
```

これを`main.kt`に追記し、有効なトークンに置き換えてください。


## 起動
`fun main() {`の左に緑の三角ボタンがあるでしょうか。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398976/69f67f20-fceb-0ef4-a6f3-cf775dd8426a.png)

三角ボタンを押して「実行'MainKt'」をクリックしてください。
しばらく待った後、コンソールに `起動しました`と出れば成功です。

上記のBotには`/neko`というメッセージに反応するコードを組み込んであります[^1]。試してみてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398976/82593ef3-d4de-e31f-2b99-992f380a3360.png)

## jarファイルを作成
さて、ここまでで、IDEA上でBotを動かせましたが、まだ何か足りませんね。

KotlinはJavaベースの言語ですよね。
Javaのアプリケーションは`.jar`拡張子になっているファイルを使いますよね。

kotlinで書いたBotのソースから`jar`ファイルを作ってみましょう。
[下準備](#buildgradlekts)でshadowJarプラグインを入れたことにより、前提ライブラリ込のjarファイルを作成することは非常にかんたんです。
その前に、`main()`関数を少し書き換えてください。

```kotlin:main.kt
fun main(args:Array<String>){
    val bot = BotClient()
    bot.main(args[0])
}
```
これで、出来上がったjarにコマンドライン引数として与えた文字列をトークンとして起動できます。

「Gradle」タブの`Tasks`>`shadow`>`shadowJar`をクリック起動してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398976/014484e1-3256-5416-af82-aef7cca3e87c.png)

暫く待つと、
`[プロジェクト名]`>`build`>`libs`>`[プロジェクト名]-1.0-SNAPSHOT-all.jar`
ファイルが出来上がっているでしょうか。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398976/1c443dd9-c66a-aa9f-9865-504459fa141d.png)
これが完成したBotのjarファイルです。
コマンドプロンプトでこのファイルのディレクトリに移動し、

```
>java -jar [jarファイル] [トークン文字列]
```
と実行してみましょう。
[さきほど](#起動)と同様にDiscord上で試してみてください。

#最後に
正常に動きましたでしょうか？
動いた方、おめでとうございます！
動かなかった方はエラーログを添えてコメント頂ければ可能な限りお手伝いします。

ここまで読んでいただきありがとうございました！
余力があればよりステップアップした記事を投稿しようと考えています。
それでは良いKotlinライフを！

次回:[シンプルなコマンド実装編](https://qiita.com/hisuie08/items/2cc32edbfa772af57a45)

[^1]: [元ネタ](https://qiita.com/1ntegrale9/items/9d570ef8175cf178468f)