Building a MapleStory Boss Drop Management Discord Bot: Connecting to Discord!

in STEMGeeks2 years ago

Surprisingly, I didn't abandon the project after 48 hours! Although proceeding from the database last time had proven to be a little bit more painful than I initially expected...

It's actually hard to walk out of the rethinking part... xkcd

What do I mean by "a little bit more painful"? Turns out that, when designing the database, I did it from a perspective that this bot is only going to be used personally, and I will be the only person running the code on a single Discord server where my party lives. However, as I started to develop the code for the bot and running it on multiple servers, several problems started to pop up - for example, there was no way to keep a server's data to its own, and they will flow all over the place to other servers with the same bot in it. Sounds like a major privacy concern...

Besides that, because I'm using SQLite, there isn't much support for alter table operations. This makes editing the tables much more annoying than what I thought it would be, as for most of the times it is a better and cleaner option to just drop the table and remake one. Needless to say, it accidentally caused a bunch of data loss and additional pain caused by foreign key references. Luckily, I kept backups of all of the data I previously used on the bot... so nothing serious happened and I can still pay my party members! Whew.

So, in the meantime, I still maintain (and happen to have enhanced™) the Excel file that I used for the records... No choice though! But the bot still has to go on. So this time around, we're connecting it to Discord for real.


I actually can't believe that searching for "Discord" yielded some results on Unsplash... Photo by ELLA DON on Unsplash

(You can find the source code so far in a link at the bottom of this post!)

To make a Discord bot, the easier way is to use a Discord API library for the programming language that you use. It is possible to make a bot without a dedicated Discord API library and just force your way through curl commands, but I guess it would be significantly less enjoyable. I think somewhere out there someone is living their life writing a Discord bot in Bash, but... that's not going to be me :)

I'm using the C# programming language, and I picked the DSharpPlus library to do the job. There are also other libraries available, such as Discord.Net and DisCatSharp, but after reading some documentation of these libraries I decided that DSharpPlus is what I'm going to use.

It is not hard to connect a bot to Discord, if that is the only thing we need our bot to do, since we can just copy paste code and follow instructions on the getting started guide. But, I need to do some changes to the code available there to fit them to the usage of the bot. For example, we definitely don't want to put the bot token in the source code itself. So that's the first thing we are changing.

There are several options to read tokens from an external source, such as environment variables or a token file, but I decided that I want to use an appsettings.json file instead, as it can not only hold token values but other configurations for the bot instead, and it is a pretty JSON file instead of XML or some stuff. Reading the file is not hard (even easier with the steps given by this StackOverflow answer), so I just threw things around from the DSharpPlus article and the StackOverflow answer... and I get this.

If you compare this with the DSharpPlus' article, you might find some differences here and there, such as I have another statement of UseInteractivity, and I have another method call to register slash commands. The UseInteractivity statement is there because the bot also uses Discord's Interactions APIs (well, at least when I implement the features that make use of buttons...), and slash commands in another class is because I like to keep my main method clean, and hence I have another class to do the heavy lifting of managing the commands and registering them with Discord. I also replaced the line of await Task.Delay(-1); with await host.RunAsync();, since I'm using Microsoft's hosting package to read the appsettings.json file.

Just like every other bot project, we start off by making a ping command. As you can see in the code above, the commands are registered through the CommandMaster class. The class has a few methods, but in general, the purpose of the class is simple: add all the command classes and their dependencies to a ServiceCollection, build a ServiceProvider, throw the ServiceProvider to the bot's client object, and register the commands with Discord. Or, in terms of code, on a very high level view (this is exactly what the public method looks like), this is what it does:

This setup makes it easy for me to add new commands to the bot without needing to change too many things in the code. I only need to make a new class for the new command, add it to the _GetCommandClasses() method, and the rest will fit in automatically. The new command's dependencies will be automatically handled through dependency injection, and it will be automatically be registered on Discord as well without the need of writing another line of code to perform the task.

When I add a new command, I only need to add a new line of code to add the new class to the list, and the rest will be handled automatically. It sounds pretty sweet!

Setting up slash commands however is initially the more tricky part. It's a relatively new feature of Discord, and I thought that it was not supported by DSharpPlus yet. However, asking a little in their friendly Discord server revealed that they actually do support this feature, but the documentation is hiding in their GitHub instead of the website. Well, since now we have the documentation, it's not hard anymore! Here we quickly whip out a class for the /ping command that when the bot receives it, will respond with an embed saying that it received a ping.

The method uses my utility class EmbedUtilities to create an "OK embed" (which is actually just a normal embed but with a nice green colour) and send it back to the channel where the /ping command was sent. The utility class is supplied to the class through dependency injection, which should work as long as the EmbedUtilities class is available in the service provider (and it is).

After putting all the code in place and filling in the appsettings.json file (it by default looks like this so we need to fill it up for the bot to work), it's time to try it out...

Running a C# project with the newer .NET versions is pretty sweet, as you only need to do dotnet run in the project's root folder and it handles everything for you. Because I'm using Microsoft's hosting stuff, there are a few other lines of output that is not from DSharpPlus, but they are harmless. When the output looks like this, it means that the bot is connected to Discord!

It's online, and the command is registered to Discord...

And using the command returns an expected result!

That's the /ping command done! Well, there are a lot more other features to make... that's for another time!


Know Your Meme

Since there were two public holidays in the past two weeks for me, I had been working on the bot since that time. But, progress turns out to be slower than I thought! Mainly because, there's a lot of rethinking and remaking throughout the process :) Firstly, there is the sudden realisation that I should reimplement the commands as slash commands in Discord, as they are in some ways easier to handle, and we don't need to request for a messages intent from Discord just in case the bot goes big in the future. There are also a bunch of feature reconsiderations and thoughts on how to better structure them after the switch to slash commands, as the logic allowed would largely differ from the original plan. We haven't even started looking back at the database changes! Programming itself isn't hard, but making something good enough to convince yourself to keep it into the future is very hard, and it might still be an understatement.

Talking about databases, someone just told me about EF Core, and I am (of course) convinced to look at it and possibly rewrite all the database interactions to use it instead. Looks like I'm going to get stuck on the rethinking part for a longer period of time. But if it means an easier time dealing with data, I don't see why not...

The bot's code so far can be found here, and needless to say, expect lots of big changes on it in the future. Just like the warning I wrote on the readme in the repo, it's definitely not ready for use (and it's not like it has any features for now as well). Hopefully this will change in the near future and I'll have something usable sitting on my Discord servers :)

Have fun with whatever you're doing, and, if you're coding... happy coding, happy rethinking.

:)

Sort:  


The rewards earned on this comment will go directly to the people( @lindoro ) sharing the post on Twitter as long as they are registered with @poshtoken. Sign up at https://hiveposh.com.