Skip to content

Your first bot

tostc edited this page May 31, 2020 · 10 revisions

Introduction

Ok we have following scenario: You are a normal Discord user like me and think "Hey how do I create a bot for Discord?" or "I like to create my own bot which ...". Than you search "discord create bot" and you find the official API documentation and you have no plan where to getting started. (That's was my first mind, because I wanted to create fast and easy a bot). But luckily there are users like me or others, I'm not the only one, who have written an implementation. And this side should help you to create a simple bot and help you to understand the fundamentals of this library.

Overview

This chapter concentrates on the working with the library to create a simple "Hello World!"-bot. This bot can receive a command from a user and replies with "Hello World!".

Prerequisites

Before you can to begin to write your own bot you need to register the bot by Discord.

  1. You need a Discord Account. (I know you have one, because why you should write a bot for Discord, if you don't know or use Discord?)
  2. You need to go to this site. You must login with your Discord account in the web to use this site.
  3. You now see this website where you can see all your bots and applications you have registered. Now click on "New Application". After you clicked the button you must enter a name and hit "Create".
  4. Now you see this page. Where you can add an app image(This is not the profile picture of the bot) and a description for the bot. You also see the client ID of the bot. In the left side bar you find the entry "Bot".
  5. Next click the "Add Bot" button to create the bot.
  6. Scroll down and activate the Server Members Intent option. This is necessary to use the rights managements system of the library.
  7. You can now copy the token of the bot. This token is needed for the library to initialize. **ATTENTION: DON'T SHARE THIS TOKEN WITH ANYBODY!!!**

After you have received your token we can begin to create our own bot. You can follow this guide to understand what each call of the library do or you can checkout this repo and copy the project_template folder to create your first bot.

Let's get started

The library is designed to handle all low level stuff. This means all events and objects of Discord are handled by the library and the relation between objects like Member and Guild(Server) is managed internally. The user, you the developer, is informed by this events over controllers. These controllers get all events like user joined a channel or a user leave a channel. So let's begin to write our own controller.

Botcontroller.hpp

#ifndef BOTCONTROLLER_HPP
#define BOTCONTROLLER_HPP

#include <controller/IController.hpp>

using namespace DiscordBot;

class CBotController : public IController
{
    public:
        CBotController(IDiscordClient *client) : IController(client) {}
        virtual ~CBotController() {}
};

#endif

Maybe you think: "Hey that was easy and so unnecessary. Why the heck I need this empty class?". These question is justified, maybe I like that the user need to implement unnecessary interfaces. But how I mentioned earlier all events from Discord are routed to this controller. You can go inside the IController.hpp of the library to see what events you can received. Next we create the main for our bot.

Note: Since version 2.0.0-alpha it's necessary to call the base constructor with the IDiscordClient object.

main.cpp

#include <IDiscordClient.hpp>
#include <BotController.hpp>

using namespace DiscordBot;

int main(int argc, char const *argv[])
{
    DiscordClient client = IDiscordClient::Create("API-TOKEN");
    client->RegisterController<CBotController>();

    //Runs the loop until the Quit() method of the client is called.
    client->Run();
    return 0;
}

That's not much code but a huge amount to explain. First we include the client interface for Discord and our controller class we have written earlier. Inside the main we first create a client with our token we have create in the Prerequisites step. (You can also add intents for the bot as second parameter.) Next we register our controller.

Note: Every client can only have one controller.

Now we can run our bot. Inside the terminal you should see following message(The URL and Date/Time can be different):

[ 2020-05-23 17:57:17 ] [ info ] Connected with Discord! wss://gateway.discord.gg/?v=6&encoding=json

This message means your bot is successfully connected to Discord and you should see him in the member list of your Guild as online. Maybe you think "Cool stuff, but where are the commands for the bot?". Ok a very justified question. The answer is simple currently there are no commands. But lets move on to create our first one. First we need to create a command handler class/controller.

HelloCommand.hpp

#ifndef HELLOCOMMAND_HPP
#define HELLOCOMMAND_HPP

#include <controller/ICommand.hpp>
#include <IDiscordClient.hpp>

using namespace DiscordBot;

class CHelloCommand : public ICommand
{
    public:
        CHelloCommand(IDiscordClient *client) : m_Client(client)
        {
                //Registers the function which handels a command.
                RegisterCommandHandler("hello", std::bind(&CHelloCommand::Hello, this, std::placeholders::_1));
        }

        virtual ~CHelloCommand() {}
    private:
        IDiscordClient *m_Client;

        void Hello(CommandContext ctx)
        {
                m_Client->SendMessage(ctx->Msg->ChannelRef, "Hello World!");
        }
};

#endif

What we see in this code snippet? First we see a class CHelloCommand which inhirets from the ICommand interface. This is necessary to call commands. The commands are internally routed to the right method of the class. Next we see a constructor which takes a IDiscordClient interface as parameter. This is necessary to send a message into the chat. This parameter is set with a depency injection like pattern. Inside the constructor we see this line RegisterCommandHandler("hello", std::bind(&CHelloCommand::Hello, this, std::placeholders::_1));. This line creates the routing from the command hello to the method void Hello(CommandContext ctx). You can register any command with this kind of registration. At the last step we need to register our command handler class/controller. This registration is made inside the CBotController from earlier.

Botcontroller.hpp

#ifndef BOTCONTROLLER_HPP
#define BOTCONTROLLER_HPP

#include <controller/IController.hpp>
#include <HelloCommand.hpp>

using namespace DiscordBot;

class CBotController : public IController
{
    public:
        CBotController(IDiscordClient *client) : IController(client) {}
        {
                Prefix = "!";   //Prefix for the command.
        }

        void OnReady() override
        {
                //Registers a new command, with description for the builtin help command.
                RegisterCommand<CHelloCommand>({"hello", "Writes \"Hello World!\" into the channel", 0, "", AccessMode::EVERYBODY}, Client);
        }

        virtual ~CBotController() {}
};

#endif

Inside the constructor we set the command prefix. This prefix introduces a command which the bot should handle. Maybe you have seen it before by other bots where you type commands like !help. We see after the constructor a new method. This is a event of the library which is called after the bot is connect to discord. Inside this event we register our CHelloCommand class/controller and bind it to the hello command. You see the first parameter is an initializer list which takes 4 parameters. The first one is the command itself. The second is the description for the command, which will be print by the builtin help command(h or help as command). As third parameter we have the amount of command parameter(e.g. !say Hallo Welt). For the hello command we don't have any parameter.(-1 is null or more.) Following parameter is the delimiter for the command parameters. The last one is the default access mode for the command. This allows you to predefine the access of the command by users. The access mode can changed by the owner of the server. As i mentioned earlier the parameter for the constructor of the CHelloCommand are injected over a kind of dependency injection. These parameter you can see at the last parameter of the RegisterCommand call. We inject the current client to the call.(This client is a attribute of IController interface and is set before after OnReady is called.). If you now start your bot and type !hello into the chat, the bot should answer Hello World!.

Note: Since version 2.0.0-alpha it's not necessary anymore to set the prefix. The default one is !. Also since this version the rights management system is integrated, which means your commands needs a default access mode.

Congratulations

You have made it to the end of the first tutorial. You know now how to initialize the library and create your own command.

Hopefully this tutorial was understandable, if not please open an issue so I can correct it.