A basic and probably over engineered approach to creating a discord bot in haxe. This project depends on aidan's ecs but is easy to swap out should you want to. The structure of this project is simply focused on making a discord bot, really easy, where the logic is simple to follow. Make your command, add it to the Main file, everything is contained
Requires:
Example Project:
- Clone the repo
git --recursive clone https://github.com/Jarrio/DiscordBotTemplate
- cd into the
bin
directory and then run:
npm install
- Get your
API token
and read here for further bot setup instructions - Go to
./bin/config/keys.json
and add your discord api keys in here - Add the bot to a server
- Compile!
- Run the bot using:
node main.js
or hit the debug button in vscode - In your discord server send the command
/hi
or/boop
and the bot should reply :)
gif is old, it shows a text command but new setup actually works with slash commands
Usage is simple, a system represents a command and most of the initial parsing work is done in CommandBase
all you need to do is just implement your commands.
First go to src/components/Command.hx
and you should see an enum called CommandOptions
. This is what handles the typing for the discord parameters and filtering the commands, simply add an enum to the list based on the config spec.
enum CommandOptions {
Hi; //A basic command, has no parameters
Boop(user:User); //Expects the user to pass a discord user object as a parameter
Test(category:Float, data:String); //Takes 2 parameters from the user, a number and a string
}
After this, go to the ./bin/config/commands.json
and add your additional commands in here. The typedef structure can be found in
Main.hx
called TCommands
An example of a commands.json
file will look like:
[
{
"name": "hi",
"description": "Say hi to the bot"
},
{
"name": "boop",
"description": "boops a user",
"params": [
{
"name": "user",
"type": "user",
"description": "The user to boop",
"required": true
}
]
},
{
"name": "test",
"description": "tests user input",
"params": [
{
"name": "type",
"type": "number",
"description": "Category of test",
"required": true
},
{
"name": "topic",
"type": "string",
"description": "additional condition",
"required": false
}
]
}
]
This sets up 3 commands and should be fairly self explanatory with the enum definitions above.
name
: The parent objectname
is what comes directly after the slash./hi
,/boop
, or/test
description
: This will show a brief description in the command list within discord about the commandparams
: It has the same structure, except nowname
anddescription
describe the parameter definition
Then head to the Main.hx
and you should see the following:
universe = Universe.create({
entities: 1000,
phases: [
{
name: 'commands',
systems: [Hi, Boop, Test]
}
]
});
systems is an array that takes in the module name of a command.
package systems.commands;
import components.Command;
class Hi extends CommandBase {
function run(command:Command, interaction:BaseCommandInteraction) {
message.reply("Hey there");
}
function get_name():String {
return 'hi';
}
}
package systems.commands;
import discord_builder.BaseCommandInteraction;
import components.Command;
class Boop extends CommandBase {
function run(command:Command, interaction:BaseCommandInteraction) {
switch (command.content) {
case Boop(user):
interaction.reply('BOOP <@${user.id}>');
default:
}
}
function get_name():String {
return 'boop';
}
}
get_name()
Is where you define your command name, this is what your users will type in discord to trigger the command - it is required.
function run(command:Command, interaction:BaseCommandInteraction)
Is what will be called when a message that matches the commands has been sent, treat this as the init point of the command.
Click Message
to see the official API, documentation and usage.
Command
is just an object with 2 fields:
name
: The command name (/hi
)content
: Content encapsulates any parameters parsed to the bot, it will be organised into an enum constructor
{
name: "hi",
content: Hi //represented by a haxe enum
}
If you need to add some code to the update loop, just override it but remember to call super
otherwise the base logic wont run
override function update(_) {
// code checks here
super.update(_);
// ... or here
}