LoginSignup
2
0

More than 1 year has passed since last update.

【Java/Kotlin】Discord Bot のスラッシュコマンドを実装する-2022

Last updated at Posted at 2022-04-30

はじめに

この記事は、Java で Discord Bot のスラッシュコマンド実装方法を解説していきます。
私が嵌った点を含めて、備忘録的に書いていこうと思います。
Discord Bot の作成は、他に記事がたくさんあるので、作成されている前提で話を進めていきます。
リポジトリを使用する際は、プロジェクトに依存関係を追加することを忘れないようにしましょう。

ソースコードは、Java と Kotlin の両方を掲載します。
私が Kotlin 推しなので、、、。
Kotlin すごく楽で便利でいいですよ!

この記事で実際に使用したソースコードは、以下の GitHub に push しておくので全体像を見たい場合はそちらを確認してください。

目次

1. はじめに
2. 目次
3. 使用するライブラリ
4. DiscordBotの招待
5. Botにログインする
6. スラッシュコマンドを登録する
7. コマンドの処理を実装する
8. 最後に
9. 参考文献

使用するライブラリ

  • JDA - 5.0.0-alpha.11

GitHub

JavaDoc

DiscordBotの招待

  1. 自分で作成した Bot を選択し、OAuth2 > URL Generator を開きます。
  2. チェック欄を以下の画像のようにします。
  3. applications.commands にチェックを入れます。
    ※ このチェックを入れないと、スラッシュコマンドを作成することができません! (私はここで嵌りました。)
  4. 最下部に表示されている URL を使用し、自分のサーバーに Bot を招待します。
    image.png

Botにログインする

TOKEN という変数に、Discord Bot のトークンを入力します。
次に、ログイン処理内の .setActivity(Activity.playing("作業")) の "作業" を好きな文字列に置き換えましょう。
これは、Discord のオンライン欄に表示される、"○○をプレイ中" の部分のことです。

ログイン処理では、ログインできなかった時に LoginException が発生するので、try-catch で囲っておきます。
ログイン処理内の、 GatewayIntent は、種類がいくつかあり、監視するイベントを設定することができます。
詳細は、JavaDoc を確認してみてください。

これを実行すると、Bot にログインすることができます。
そして、サーバーに招待した Bot が、オンラインになっていることが確認できると思います。

Main.java
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.entities.Activity;
import net.dv8tion.jda.api.requests.GatewayIntent;

import javax.security.auth.login.LoginException;

public class Main {
    private static final String TOKEN = "Discord bot のトークンを記述";

    public static void main(String[] args) {
        try {
            // Login 処理
            JDABuilder.createLight(TOKEN, GatewayIntent.GUILD_MESSAGES, GatewayIntent.DIRECT_MESSAGES)
                    .setActivity(Activity.playing("作業")) // "~をプレイ中" の ~の部分
                    .build();
        }catch (LoginException e){
            e.printStackTrace();
        }
    }
}
MainKt.kt
import net.dv8tion.jda.api.JDABuilder
import net.dv8tion.jda.api.entities.Activity
import net.dv8tion.jda.api.requests.GatewayIntent

import javax.security.auth.login.LoginException

class MainKt {
    companion object {
        private const val TOKEN = "Discord bot のトークンを記述"
    }

    fun first() {
        try {
            // Login 処理
            JDABuilder.createLight(TOKEN, GatewayIntent.GUILD_MESSAGES, GatewayIntent.DIRECT_MESSAGES)
                .setActivity(Activity.playing("作業")) // "~をプレイ中" の ~の部分
                .build()
        } catch (e: LoginException) {
            e.printStackTrace()
        }
    }
}

fun main(){
    MainKt().first()
}

スラッシュコマンドを登録する

実際にスラッシュコマンドを追加します。
スラッシュコマンドを実装する場所を全ての場所にすると、コマンド登録に最大1時間かかるようです。
そのため、コマンドをテストしたい場合は特定サーバーのみ使用可能な形にすると良いそうです。
参考 JavaDoc

まず、JDABuilderbuild() した時に戻り値である JDA を使用するので、変数 jda に置きます。
次に、jda.awaitReady() を記述し、ログイン処理が完了するまで待ちます。
この処理を書かないと、サーバーが見つからず null になってしまいます。 (私はここで嵌りました。)

次に、サーバー ID からサーバー情報を取得して、変数 guild に置きます。

次に、登録するスラッシュコマンドを作成します。
作成方法は、Commands.slash("コマンド名", "コマンドの説明")SlashCommandData 型で変数に置きます。

次に、サーバーにコマンドを登録します。
guild.updateCommands().addCommands(作成したコマンドの変数).queue();
これを記述することで、登録することができます。
全ての場所に登録したい場合は、guild の部分を jda に変更しましょう。

ソースコードが長くなるため、import 文は追加分だけ書きます。

Main.java
import net.dv8tion.jda.api.JDA;

import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData;

public class Main {
    private static final String TOKEN = "Discord bot のトークンを記述";
    private static final String GUILD_ID = "Discord サーバーの ID を記述";

    public static void main(String[] args) {
        try {
            // Login 処理
            JDA jda = JDABuilder.createLight(TOKEN, GatewayIntent.GUILD_MESSAGES, GatewayIntent.DIRECT_MESSAGES)
                    .setActivity(Activity.playing("作業")) // "~をプレイ中" の ~の部分
                    .build();

            // ログインが完了するまで待つ
            jda.awaitReady();

            // 参加しているサーバーを ID から取得
            Guild guild = jda.getGuildById(GUILD_ID);

            // 登録するコマンドを作成
            SlashCommandData testCommand = Commands.slash("test", "テストコマンド");

            // コマンドを指定したサーバーに登録
            guild.updateCommands()
                    .addCommands(testCommand)
                    .queue();
            
        }catch (LoginException | InterruptedException e){
            e.printStackTrace();
        }
    }
}
MainKt.kt
import net.dv8tion.jda.api.interactions.commands.build.Commands

class MainKt {
    companion object {
        private const val TOKEN = "Discord bot のトークンを記述"
        private const val GUILD_ID = "Discord サーバーの ID を記述"
    }

    fun first() {
        try {
            // Login 処理
            val jda = JDABuilder.createLight(TOKEN, GatewayIntent.GUILD_MESSAGES, GatewayIntent.DIRECT_MESSAGES)
                .setActivity(Activity.playing("作業")) // "~をプレイ中" の ~の部分
                .build()

            // ログインが完了するまで待つ
            jda.awaitReady()

            // 参加しているサーバーを ID から取得
            val guild = jda.getGuildById(GUILD_ID)!!

            // 登録するコマンドを作成
            val testCommand = Commands.slash("test", "テストコマンド")

            // 指定したサーバーにコマンドを登録
            guild.updateCommands()
                .addCommands(testCommand)
                .queue()

        } catch (e: LoginException) {
            e.printStackTrace()
        }
    }
}

fun main(){
    MainKt().first()
}

コマンドの処理を実装する

現在は、コマンドを登録だけして中身を書いていないので、コマンドを打つと、応答していないと言われます。
なので、これから処理するクラスを実装していきます。

処理するクラスを作る

実装方法は、ListenerAdapter を継承したクラスを使用します。
このクラス内で、onSlashCommandInteraction メソッドを override して、その中にコマンドの中身を書きます。

event.getName() を使用することで、コマンド名を取得できます。
ここでは、test コマンドであれば処理をするようにしています。

event.reply("リプライメッセージ") を使用することで、コマンド送信者に対して返信という形でメッセージを返すことができます。
.setEphemeral(boolean) を true に設定することで、コマンドを使用した人のみにしか見えないように返信されます。

SlashCommandListener.java
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.jetbrains.annotations.NotNull;

public class SlashCommandListener extends ListenerAdapter {
    @Override
    public void onSlashCommandInteraction(@NotNull SlashCommandInteractionEvent event) {
        // test コマンドなら処理をする。
        if (event.getName().equals("test")) {
            // コマンド送信者に対して、その人にだけ見えるメッセージとして返信する。
            event.reply("This is test command!").setEphemeral(true).queue();
        }
    }
}
SlashCommandListener.kt
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent
import net.dv8tion.jda.api.hooks.ListenerAdapter

class SlashCommandListener : ListenerAdapter() {
    override fun onSlashCommandInteraction(event: SlashCommandInteractionEvent) {
        // test コマンドなら処理をする。
        if (event.name == "test") {
            // コマンド送信者に対して、その人にだけ見えるメッセージとして返信する。
            event.reply("This is test command!").setEphemeral(true).queue()
        }
    }
}

処理するクラスをBotに登録する

コマンドの処理を行うクラスを Bot に登録します。
Main クラスで行っているログイン処理の部分に追加の記述をします。

.addEventListeners() を使用して、コマンドの処理を Bot に登録します。
具体的には、.addEventListeners(new 処理するクラス()) と記述すれば ok です。
処理するクラスが複数ある場合は、.addEventListeners(new C1(), new C2()) のようにカンマ区切りで記述できます。

Main.java
// Login 処理
JDA jda = JDABuilder.createLight(TOKEN, GatewayIntent.GUILD_MESSAGES, GatewayIntent.DIRECT_MESSAGES)
    .addEventListeners(new SlashCommandListener())
    .setActivity(Activity.playing("作業")) // "~をプレイ中" の ~の部分
    .build();
MainKt.kt
// Login 処理
val jda = JDABuilder.createLight(TOKEN, GatewayIntent.GUILD_MESSAGES, GatewayIntent.DIRECT_MESSAGES)
    .addEventListeners(SlashCommandListener())
    .setActivity(Activity.playing("作業")) // "~をプレイ中" の ~の部分
    .build()

最後に

JDA を使ってスラッシュコマンドを実装するときに、最新の情報がほとんど見つからなかったので、備忘録的に書いてみました。
ほとんど JavaDoc から解読して手探り状態だったのでとても大変でした。
しかし、スラッシュコマンドを実装すると、tab 補完でコマンドを打つことができるようになるので、とても楽することができます。

わかり辛いところも多々あったかと思いますが、皆様のお役に立てば幸いです。

なにか間違い等があれば指摘の方をお願いします。
ありがとうございました。

参考文献

2
0
0

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
  3. You can use dark theme
What you can do with signing up
2
0