Using KotlinJS and NPM to create a Discord Bot - Discord Bot Series (Part 2)
Kevin Schildhorn
Posted on April 26, 2022
Discord is a great platform for keeping in touch with friends, and adding a bot can enrich that experience. A bot can respond to messages, perform an action based on a command, or even add music to a voice chat.
In this series we'll be going over how to create a small example bot by using the NPM module for DiscordJS in a KotlinJS project.
Note: This is the second post in a series of three posts, about how to use KotlinJS and NPM modules to create a full fledged project, in this case a Discord Bot. You can find the first post here.
Previously
In my last post we went over how to import node modules into our KotlinJS project, and created a simple project to test our imports. In this post we'll go over how to add DiscordJS to our project, and start creating our bot! Let's get started.
As a refresher, in this series we're going to create a small discord bot that responds to a specific message with its computer name.
Registering a Discord Bot
Before digging into code make sure you register a bot. Choose New Application
, add a name and click create
.
You can find more documentation on this process here.
After you create your bot you should see this screen.
Click on the Bot tab on the left and in the Build-a-bot
section click add bot
. Once you've done this you'll have created a bot! Be sure to keep the token from this screen for use in the project.
Also be sure to register your bot to your Channel using this guide.
Initializing DiscordJS
For our KotlinJS project we'll be using DiscordJs, which is a well documented and widely used node module for discord.
So first we'll add the dependency to the build.gradle
file like before:
dependencies {
implementation(npm("discord.js", "13.6.0"))
}
Then we can reference the Creating the main file documents to find out how to launch the bot. We can see that the client is initialized, then it listens for messages, then finally calls to login.
This is in Javascript but the kotlin implementation will look mostly the same. First we need to define the Client
class. So we'll go to the documentation for the client, and see what we need to define. We can see that:
- Client takes in
ClientOptions
to init. - Client inherits from
EventEmitter
, which is howonce
is called - Client
login
function takes in a string token and returns a string promise.
Init
Before we go defining ClientOptions
and potentially going down the rabbit hole, we can see that it's defined as an object. In this case we can just pass a Json object in the constructor.
@JsModule("discord.js")
external class Client(config: Json?)
const val GUILDS = 1 // 1 << 0
val client = Client(json(Pair("intents", arrayOf(GUILDS))))
The client takes in "intents", which is an array of just Intents.FLAGS.GUILDS
. If we follow the documentation from DiscordJS to the intents we can find their definition here. We see that Intents.FLAGS.GUILDS
is 1 << 0 (or 1) so we'll pass that.
Once
This function we can figure out by the simple call. This is just to let us know the client is ready, so we'll just print out a confirmation.
@JsModule("discord.js")
external class Client(config: Json?) {
fun once(event: String, cb: (Unit) -> Unit)
}
client.once("ready") {
println("Hello From ${computerName()}!")
}
We can tell that it takes in a string, and returns a block. Since there's no input or output we can just use Unit
, which acts as void
.
Login
Based on what we learned we can define this easily. The token we will pass in comes from your created bot on the discord site. This was the token that was grabbed from the beginning of this post.
@JsModule("discord.js")
external class Client(config: Json?) {
//...
fun login(token: String): Promise<String>
}
//Main.kt
client.login("YOUR_TOKEN")
In this case we can tell the function returns a Promise from the DiscordJS documentation.
Running your bot
At this point all the calls should be in, your Main.kt
should look something like this:
const val GUILDS = 1 // 1 << 0
val client = Client(json(Pair("intents", arrayOf(GUILDS))))
client.once("ready") {
println("Hello From ${computerName()}!")
}
client.login(token)
If you run it you should be able to see your computer name in the terminal and your bot should be online!
Responding to Messages
This is great that the bot is running, however right now it's not doing anything. So let's get the bot to respond to a message.
Note: intent
In order for the bot to get messages, the client needs to register another intent, GUILDS_MESSAGES
.
const val GUILDS = 1 // 1 << 0
const val GUILDS_MESSAGES = 512 //1 << 9
val client = Client(json(Pair("intents", arrayOf(GUILDS, GUILDS_MESSAGES))))
Defining Messages
So first we'll quickly define a message, as that's what's passed in. From the docs we can see a message contains a content
string, the author
, and the channel
it was sent in. we're going to use the channel
to send the reply to, and use the author
to create a personalized message.
To make things quicker I've defined what we need from the documentation below:
external class Message {
val author: User
val channel: TextChannel
val content: String
}
external class User {
val avatar: String
val username: String
}
external class TextChannel {
fun send(content: Any): Promise<Message>
}
Listening for Messages
With that being set we can then go to the Client
definition and add a listener for the message:
external class Client(config: Json?) {
// ...
fun on(event: String, cb: (item: Message) -> Unit)
}
So now we can listen for "message" events (or rather "messageCreate" events defined in the migration guide).
client.on("messageCreate") { message ->
print(message.content)
}
To go even further let's implement our desired code. We'll check to see if someone says hello, and if they do respond with their name and the bots computer name.
client.on("messageCreate") { message ->
if(message.content == "hello")
message.channel.send("Hello ${message.author.username} From ${computerName()}!")
}
Now build and run the bot, and say hello! You should see a response like so.
Conclusion
Congrats, You've made a working Discord Bot! You now have the basics to expand your bot to respond to lots of different messages in many ways.
After playing around with the bot you may realize that there are some uncaught issues, for example the bot won't respond if there's a space in the message or if "Hello" is capitalized. In the next post of this series, we'll go over how we can write tests to catch these issues and make sure our bot works the way we expect.
Thanks for reading! Let me know in the comments if you have questions. Also, you can reach out to me at @kevinschildhorn on Twitter.
Posted on April 26, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.