Works でも公開している通り、学内Discord鯖のBot制作を担当しました。その時に用いたDiscord .NETのお話です。
この記事での目標はDiscord上のサーバーで「おはよう」という入力に対して「Hello!」と返信するBotの作成を行います。入出力ができれば大体の状況で応用が効くので…
Discord .NETについてはGitHubの公式リファレンスを読めば済む話ですが、ちゃんと日本語で説明を書きます。
参考:Discord.NETを用いたbot開発LT
そもそもなんでBot制作にPython使わないの?
「Discord Bot開発」で検索すると大体がPythonを用いた記事です。
しかしそれでもC#で書くのはなぜか、それは僕がC#好きだからです。いいでしょ。
真面目な理由を話すと
- C#を使い慣れている人にとって好都合である(新言語を学ぶコストを削減できる)
- 言語総合クエリ(LINQ)などが強力
- .NET関連技術の恩恵を最大限に受けることができる
- NuGetが便利、ライブラリが充実している
などが挙げられます。
まずはDiscord側の設定をする
DiscordのBotDeveloperサイトへアクセスし、使用するBotの設定を行います。
アクセス後表示される画面の右上「New Application」から作成したいBotの名前を入力してBotを作成します。

入力終了後、Botの設定画面が表示されます。
まず、設定画面左のメニューから「Bot」を選択します。
ボットの名前の設定を行い、「TOKEN」の部分からBotのトークンを取得します。

次に「OAuth2」の項目に移動し、「bot」にチェックを入れて生成されたリンクへ飛びます。
認証設定画面が表示されるので、追加したいServerを選択してあげましょう。ServerにBotが自動的に追加されます。

これにてDiscord側の設定は終了です。
実際にコーディングしてみよう
それでは早速コーディングに入っていきましょう。
環境はVisual Studio 2019で進めます。
新規プロジェクトの作成
まずは新規プロジェクトを作成します。


“作成”ボタンを押下するとプロジェクトの作成が自動で行われ、プロジェクトファイルが生成され開かれます。

Discord .NETの導入
Visual Studio を使っている方は 「NuGetパッケージの管理」から簡単に導入することが出来ます。

NuGetパッケージ管理画面が現れたら、検索ボックスに「Discord .NET」と入力。

そのまま案内に従うことで導入することが出来ます。

また、Visual Studioを使わずにDiscord .NETのライブラリがほしい方はGitHubのページから導入しましょう。
https://github.com/discord-net/Discord.Net
コーディング
やっとコーディングらしいコーディングです。
“_client” にBot情報を格納しながら起動するサンプルプログラムを以下に示します。
大本のコードは公式リファレンスによっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
using System; using System.Threading.Tasks; using Discord; using Discord.WebSocket; namespace TestHoge { class Program { private DiscordSocketClient _client; public static CommandService _commands; public static IServiceProvider _services; static void Main(string[] args) => new Program().MainAsync().GetAwaiter().GetResult(); public async Task MainAsync() { _client = new DiscordSocketClient(new DiscordSocketConfig { LogLevel = LogSeverity.Info }); _client.Log += Log; _commands = new CommandService(); _services = new ServiceCollection().BuildServiceProvider(); _client.MessageReceived += CommandRecieved; //次の行に書かれているstring token = "hoge"に先程取得したDiscordTokenを指定する。 string token = "hogehogehogehoge"; await _commands.AddModulesAsync(Assembly.GetEntryAssembly(), _services); await _client.LoginAsync(TokenType.Bot, token); await _client.StartAsync(); } private Task Log(LogMessage message) { Console.WriteLine(message.ToString()); return Task.CompletedTask; } } } |
サンプルコードの説明–
1 |
async Task Log(LogMessage message) |
では、コンソールにログを吐き出すための実装がなされています。
1 |
async Task MainAsync() |
では、_clientにBot情報を格納する処理を行うための実装をしています。
コメントアウトにも書きましたが、”hoge”となっている部分に先程取得したDiscordTokenを設定してあげましょう。
このコードにより、Botはログイベントを受け取ることが可能となります。
目的を達成させる
この記事の目的は
Discord上のサーバーで「おはよう」という入力に対して「Hello!」と返信するBotの作成
です。早速実装すると、コードはこのようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
using System; using System.Reflection; using System.Threading.Tasks; using Discord; using Discord.Commands; using Discord.WebSocket; using Microsoft.Extensions.DependencyInjection; namespace TestHoge { class Program { private DiscordSocketClient _client; public static CommandService _commands; public static IServiceProvider _services; static void Main(string[] args) => new Program().MainAsync().GetAwaiter().GetResult(); public async Task MainAsync() { _client = new DiscordSocketClient(new DiscordSocketConfig { LogLevel = LogSeverity.Info }); _client.Log += Log; _commands = new CommandService(); _services = new ServiceCollection().BuildServiceProvider(); _client.MessageReceived += CommandRecieved; //次の行に書かれているstring token = "hoge"に先程取得したDiscordTokenを指定する。 string token = "hogehogehogehoge"; await _commands.AddModulesAsync(Assembly.GetEntryAssembly(), _services); await _client.LoginAsync(TokenType.Bot, token); await _client.StartAsync(); await Task.Delay(-1); } /// <summary> /// 何かしらのメッセージの受信 /// </summary> /// <param name="msgParam"></param> /// <returns></returns> private async Task CommandRecieved(SocketMessage messageParam) { var message = messageParam as SocketUserMessage; //デバッグ用メッセージを出力 Console.WriteLine("{0} {1}:{2}", message.Channel.Name, message.Author.Username, message); //メッセージがnullの場合 if (message == null) return; //発言者がBotの場合無視する if (message.Author.IsBot) return; var context = new CommandContext(_client, message); //ここから記述-------------------------------------------------------------------------- var CommandContext = message.Content; // コマンド("おはよう")かどうか判定 if (CommandContext == "おはよう") { await message.Channel.SendMessageAsync("Hello!"); } } private Task Log(LogMessage message) { Console.WriteLine(message.ToString()); return Task.CompletedTask; } } } |
実行結果


コードの説明
usingの変更、MainAsyncの変更
先程のコードから新たに
1 2 3 |
using System.Reflection; using Discord.Commands; using Microsoft.Extensions.DependencyInjection; |
などが追加されています。
また、変数
1 2 |
public static CommandService _commands; public static IServiceProvider _services; |
が、追加され、MainAsyncの処理にも変更があります。
async Task CommandRecieved(SocketMessage messageParam)
1 |
async Task CommandRecieved(SocketMessage messageParam) |
では、何らかのメッセージを受け取ったときの処理が実装されています。
1 |
var message = messageParam as SocketUserMessage; |
と宣言することによって、変数messageにユーザーの発言情報が格納されます。
そしてmessageから情報を抜き取ることで、発言情報がnullでないか、それがユーザーによる発言なのかを判別します。
1 2 3 4 |
//メッセージがnullの場合 if (message == null) return; //発言者がBotの場合無視する if (message.Author.IsBot) return; |
そして発言がユーザーによるものだということを確認し次第、string型のcontextを取得し、照合し、発言させます。
1 2 3 4 5 6 7 8 9 |
var context = new CommandContext(_client, message); //ここから記述-------------------------------------------------------------------------- var CommandContext = message.Content; // コマンド("おはよう")かどうか判定 if (CommandContext == "おはよう") { await message.Channel.SendMessageAsync("Hello!"); } |
これでチュートリアルは終了
以上で目標達成、チュートリアル終了となります。
今回は深くまでは触れていませんが、C#でのDiscord Bot開発が チョットワカル 状態になったことでしょう。(期待しています)
更に難しい動作をさせたい場合(例えばユーザーメンション,○○をプレイ中表示変更)は公式リファレンスを読むことをおすすめします。
また、僕が気が向いたら解説記事を書くかもしれません。その時はどうぞよろしくお願いします。