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_t
のreply
メソッドを使用します。
event.reply("Pong!", true); //(5)
(6) flag
の意味
(8)によるループ文から分かる通り、flag
がtrue
の間はbotが動き続けます。flag
がfalse
になると、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
*/
#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を作る話でした。