Message Commands

Wanna use good old message commands instead? We have you covered!

Unless you have a good reason to continue using legacy message contents, you're strongly recommended to migrate to Application Commands (i.e. slash commands) instead. Refer to Registering Commands and Responding to Commands to see how that's accomplished with DiscordKit.

Intents

Gateway Intents is Discord's method of filtering gateway events, such that applications only receive the events that are useful to them. Events or fields that might contain sensitive data are gated behind "privileged intents" and require approval to remain enabled if your bot is in more than 100 servers.

Developer Portal

Due to a controversial change that was made some time ago, user-created content (including messages) is now gated behind a privileged intent and empty by default. You'll have to enable it in both your bot application and Discord's Developer Portal in order for those fields to be populated.

To do so, go to your application in Discord's Developer Portal and enable the Message Content Intent under the Bot page (you might have to scroll down a bit). Make sure to press Save Changes after making this change!

As stated under the option, you'll have to request for Discord's approval to continue using the privileged message content intent when your bot is in more than 100 servers!

Client Parameters

You'll also have to make a change to the intents specified during the creation of your Client object. You might be instantiating the Client object like so:

Client(intents: .unprivileged)

To enable the message content intent, simply append .messageContent to the bitfield:

Client(intents: [.unprivileged, .messageContent])

That's all the changes you'll need to make in your code to receive message contents.

Handling Message Events

Now that you're receiving message contents, you'll need to handle them. To do so, place the following example code before the call to .login() (assuming bot is an instance of Client):

bot.messageCreate.listen { message in
    print("Received message with content '\(message.content)'")
}

Rerun your bot, and you should see something printed out to your console every time a message is sent in any server your bot is in!

To reply to a message, you could add something like the following code in the event handler:

if message.content == "?ping" {
    print("Received ping command!")
    _ = try? await message.reply("Pong!")
}

The bot should now reply to every message with the content "?ping" with a "Pong!" message!

However, the code doesn't scale as the number of commands increase. At this point, you could choose to handle commands in any way you wish, but an example is provided below if you'd like something to build off:

bot.messageCreate.listen { message in
    if message.content.hasPrefix(Self.MSG_CMD_PREFIX) { // Check if the message has our prefix
        // Remove the prefix and split the text into individual args
        let args = message.content.trimmingPrefix(Self.MSG_CMD_PREFIX).components(separatedBy: .whitespaces)
        // Ensure there's at least one arg, which will be used as the command
        guard let command = args.first else { return }
        switch command {
        case "ping":
            _ = try? await message.reply("Pong!")
        default:
            _ = try? await message.reply("I don't recognise that command :(")
        }
    }
}

Add the following static property in the struct that's annotated with @main:

/// The prefix we're using for commands
///
/// This reads from the `MESSAGE_COMMAND_PREFIX` environment variable and defaults
/// to "?" as the prefix if the variable isn't found.
static let MSG_CMD_PREFIX = ProcessInfo.processInfo.environment["MESSAGE_COMMAND_PREFIX"] ?? "?"

And you're all set! Go build something wonderful with message commands (or use slash commands as a better alternative instead)!

Last updated