Quick fix on getting a Discord bot to echo in Discord.Net
March 17, 2023
Channeling some Simon Wilson I’m thinking that I should be more transparent about hacking that I’m doing and add in some accountability for projects. Specifically, if I decide to hack on something, it’s also a commitment to write about it in some form.
So here’s a go at it.
I’m working with Discord and the ChatGPT/GPT4 API to try and build… something? I’ve got a few ideas but nothing to report back yet really. Part of this process though necessitated building the bot itself, so naturally I reached for whatever existed for dotnet.
I found seemingly the only framework, Discord.NET, and starting getting building with it but uh, damn. The documentation is pretty terrible. Don’t get me wrong, there is lots of it, but it somehow strikes this terrible middle ground between condescending and terse and verbose and messy. It’s like That One Guy That Likes To Get Mad At Everyone On A Discord Server For Not Already Knowing Something wrote 20,000 words of docs to prove a point.
So parsing it is… difficult. I wanted to just get a simple server setup with a bot that could do an echo, which took me a surprisingly large amount of time.
The KEY THING I was missing was that echoing a sent message required reading a message’s content, and reading content was recently made into a special permission (“Intent”) for bots. This meant that messages I received from the server were showing empty content.
Turns out, you’ve got to both set this intent in Discord’s bot settings page, AND set it in the code for the config.
So here’s how to do it:
using Discord;
using System.Text.Json;
using System.Text.Json.Serialization;
using Discord.WebSocket;
namespace DiscordThinkTankBot;
class Program
{
public static Task Main(string[] args) => new Program().MainAsync();
private DiscordSocketClient _client;
public async Task MainAsync()
{
// SET INTENTS HERE!
var config = new DiscordSocketConfig()
{
GatewayIntents = GatewayIntents.AllUnprivileged | GatewayIntents.MessageContent
};
_client = new DiscordSocketClient(config);
_client.Log += Log;
// You can assign your bot token to a string, and pass that in to connect.
// This is, however, insecure, particularly if you plan to have your code hosted in a public repository.
var token = "";
await _client.LoginAsync(TokenType.Bot, token);
await _client.StartAsync();
_client.MessageReceived += MessageReceived;
// Block this task until the program is closed.
await Task.Delay(-1);
}
private Task Log(LogMessage msg)
{
Console.WriteLine(msg.ToString());
return Task.CompletedTask;
}
private async Task MessageReceived(SocketMessage message)
{
Console.WriteLine(um.CleanContent);
//echo messages sent in general to general
if (message.Channel.Name == "general" && !message.Author.IsBot)
{
var channel = message.Channel as SocketTextChannel;
await channel.SendMessageAsync(message.Content);
}
}
}
Notably, I actually tried asking ChatGPT how to do this, and it couldn’t figure it out. Specifically it’s because the new intents change happened after it’s cutoff date, so it had no idea about the injection!
Hope this helps anyone else looking to setup something simple!
Published on March 17, 2023.