2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

八戸高専Advent Calendar 2023

Day 11

C++でdiscord botを作る

Last updated at Posted at 2024-01-29

C++でdiscord botを作る

この記事はアドカレに参加しています。

C++でdiscord bot

C++でdiscord botを作成するような日本語情報を見つけれなかったので、記事にすることにしました。

D++

C++で一からdiscord botの処理を作るのは大変なので、D++というライブラリを使用します。基本的にdiscordjsなどと同じようにコードを書けますが、若干の違いもあるので注意が必要です。

D++のすべてのAPIの説明は公式サイトにあります。

botの登録

Discord Developer Portalでbotを登録します。トークンの取得とか、botに渡す権限やサーバーに招待する方法などについては、この記事では触れません。この辺はJavaScriptだろうがC++だろうが変わらないからです。

環境構築

C++でD++を使用するための環境構築について説明します。Visual Studio 2022を使用することを前提として説明しますが、他のコンパイラでもやることは殆ど変わらないはずです。

ライブラリをダウンロードしてパスを繋ぐだけなので、ご存じの方は読み飛ばしてください

1. ライブラリのダウンロード

まずは、D++公式サイトからコンパイル済みのライブラリをダウンロードします。

Visual Studio 2022を使用する場合には、以下の二つをダウンロードします。リリースビルドの際はrelease buildの方にあるファイルを、デバックビルドの際はdebug buildの方にあるファイルを使用します。
x64 Windows (64 bit vs2022 release build)
x64 Windows (64 bit vs2022 debug build)

ダウンロードできたらzipを解凍しておきましょう。

2. プロジェクトにD++のパスを繋ぐ

Visual StudioのプロジェクトにD++のパスを繋ぎます。プロパティページを開いたら、以下の設定を行っていきます。

・構成プロパティ→全般→C++ 言語標準
C++ 17以上にします。(D++はC++ 17で開発されているため)

・C/C++→全般→追加のインクルード ディレクトリ
ダウンロードしたファイルの中にあるdpp.hというファイルのあるフォルダのパスを追記します。

・リンカー→全般→追加のライブラリ ディレクトリ
ダウンロードしたファイルの中にあるdpp.libというファイルのあるフォルダのパスを追記します。

・リンカー→入力→追加の依存ファイル
dpp.libを追記します。

3. dllをexeと同じフォルダに置く

これはコンパイル後の話になりますが、コンパイルしたexeを実行するには以下の6つのdllをexeと同じフォルダに置く必要があります。
dpp.dll
libcrypto-1_1-x64.dll
libsodium.dll
libssl-1_1-x64.dll
opus.dll
zlib1.dll

プログラム

D++を使用できる環境が整ったら、コードを書いていきます。全体コード(プログラム例)の内容をつまんで解説していくので、最初に全体コードを見た方がいいかもしれないです。

(0) ヘッダー

まずはヘッダーを#includeします。

#include "dpp/dpp.h" //(0)

(1) bot操作用のオブジェクト

基本的にdpp::clusterを使用してdiscord botを操作します。
コンストラクタではbotのトークンと、インテントを指定します。botのトークンはDiscord Developer Portalで入手することができます。インテントは、botが実行できる権限に関するフラグです。

//bot操作用のオブジェクト (1)
dpp::cluster bot(BOT_TOKEN, dpp::i_default_intents | dpp::i_message_content);

(2) ログ表示

bot.on_log()dpp::utility::cout_logger()を渡すことで、botのログ情報をD++がコンソールに表示してくれるようになります。デバッグなどをする際に役に立ちます。

//logをコンソールに (2)
bot.on_log(dpp::utility::cout_logger());

(3) 最初に呼ばれるイベント

botを起動してから最初に呼ばれるイベントがreadyです。readyで実行したいプログラムをbot.on_ready()に関数で渡します。可読性が上がるので、ラムダ式で書くのがおすすめです。

//最初に呼ばれるイベント (3)
bot.on_ready([&bot](const dpp::ready_t& event) {
    std::cout << "ログインしました" << std::endl;
});

(4) メッセージが来た場合の操作

discordにいるユーザーによってメッセージが生成された際にはmessage_createイベントが発生します。メッセージが生成されたときに何か処理をしたい場合には、bot.on_message_create()に実行したい関数を渡します。

以下のプログラム例では、チャンネルidに投稿されたメッセージが!!pingの場合にはPong!とbotがリプライします。!!destroyの場合には、flag変数にfalseを代入しています。

//メッセージが来た場合の操作 (4)
bot.on_message_create([&flag, &bot](const dpp::message_create_t& event) {
    if (event.msg.channel_id == チャンネルid) {
        if (event.msg.content == "!!ping") {
            event.reply("Pong!", true); //(5)
        }
        else if (event.msg.content == "!!destroy") {
            flag = false; //(6)
        }
    }
});

(5) メッセージに返信

メッセージに返信するには、dpp::message_create_treplyメソッドを使用します。

event.reply("Pong!", true); //(5)

(6) flagの意味

(8)によるループ文から分かる通り、flagtrueの間はbotが動き続けます。flagfalseになると、botは停止します。

flag = false; //(6)

(7) botをスタートさせる

各種イベントに実行したい関数を設定したら、bot.start()でbotの処理をスタートさせます。bot.start()trueを渡すと、すぐに処理が戻ってきますが、falseを渡すとbot.start()の中で無限ループに入るので上手く使い分ける必要があります。

//botをスタートさせる (7)
bot.start(true);

(8) 終了まで待機

スタートしたbotは、各種イベントが呼ばれるまでやることがありません。bot.start()trueを指定した場合には、すぐに処理が戻ってきてしまうため、時間つぶしをする必要があります。

//終了まで待機 (8)
while (flag) {
    Sleep(1000);
}

(9) dpp::clusterのデストラクタが呼ばれる

dpp::clusterがスコープを抜けると、デストラクタが呼ばれます。デストラクタが呼ばれると、botの動作は停止します。

{
    dpp::cluster bot(BOT_TOKEN, dpp::i_default_intents | dpp::i_message_content);
} //dpp::clusterのデストラクタが呼ばれる //(9)

ここで注意したいのは、botを停止したいときに明示的にshutdown()を呼んではいけないことです。shutdown()を呼ぶと、内部のオブジェクトがdeleteされるのですが、その後にデストラクタでもshutdown()が呼ばれてしまいます。つまり、shutdown()を呼ぶと同じポインタを二回deleteしてしまうことになってしまいます。
https://github.com/brainboxdotcc/DPP/blob/master/src/dpp/cluster.cpp

こういうバグを引き起こさないためにも、皆さんはちゃんとdeleteしたらnullptrを詰めるようにしましょうね。

プログラム例

Visual Studio 2022 C++ 17 でコンパイルと実行を確認しました。

main.cpp
/*

main.cpp

*/

#include <iostream>
#include <string>
#include "dpp/dpp.h" //(0)

const std::string BOT_TOKEN = "";

int main() {
    std::cout << "start" << std::endl;

    {
        bool flag = true;

        //bot操作用のオブジェクト (1)
        dpp::cluster bot(BOT_TOKEN, dpp::i_default_intents | dpp::i_message_content);

        //logをコンソールに (2)
        bot.on_log(dpp::utility::cout_logger());

        //最初に呼ばれるイベント (3)
        bot.on_ready([&bot](const dpp::ready_t& event) {
            std::cout << "ログインしました" << std::endl;
        });

        //メッセージが来た場合の操作 (4)
        bot.on_message_create([&flag, &bot](const dpp::message_create_t& event) {
            if (event.msg.channel_id == チャンネルid) {
                if (event.msg.content == "!!ping") {
                    event.reply("Pong!", true); //(5)
                }
                else if (event.msg.content == "!!destroy") {
                    flag = false; //(6)
                }
            }
        });

        //botをスタートさせる (7)
        bot.start(true);

        //終了まで待機 (8)
        while (flag) {
            Sleep(1000);
        }
    } //dpp::clusterのデストラクタが呼ばれる //(9)

    std::cout << "end" << std::endl;
    system("pause");
    return 0;
}

参考文献

D++: A C++ Discord API Library for Bots

むすび

C++でdiscord botを作る話でした。

2
0
1

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?