An advanced bot engine for Discord running on lightweight Eris
What can Cyclone do?
-
Manage and automate connections to the Discord API
-
Handle commands with capability, versatility, and ease
-
Add user flexibility to your bot with command aliases
-
Prevent crashing due to errors
-
Integrate automated actions
-
Simplify how attachments such as databases are integrated into systems
-
Auto generate command info
-
Utilize a dynamic built-in help menu generator
-
Allow freedom of server-side prefixes
-
Return command results for analysis and logging
-
Create interactive menus with awaited actions and reactions
-
Grant complete freedom of bot design
-
Assign authority levels to server roles with an ALO permissions system
Examples of bots that use Cyclone
Getting started
Prerequisites
eris
- You need to install Eris and supply it to the agent. Eris is supplied manually to allow custom Eris classes to be used by the engine.
npm i cyclone-engine
Constructing the Agent class
The Agent class is the main manager of the bot. This will be controlling automated actions as well as call the Command & Reaction Handler.
const TOKEN } = processenv const Eris = const Agent } = const handlerData = { if results console} const agent = Eris token: TOKEN handlerData options: connectRetryLimit: 5 prefix: '.' postEventFunctions: message: postFunction reaction: postFunction agent
Using an attachment such as a database manager
If you'd like to have a class/object/value that can be utilized by commands even if it's not defined in the same scope, you can use the attachment feature
Knex example:
Main file:
const TOKEN DATABASE_URL } = processenv const Eris = const Knex = const commands } = const knex = client: 'pg' connection: DATABASE_URL const agent = Eris token: TOKEN handlerData: commands agent agent
Command file:
const Command } = const data = name: 'points' desc: 'See how many points you have' { return agentattachments } moduleexports = data
Constructing the Command Handler without the agent
The Command Handler is taken care of automatically when the agent is constructed and connected. However, if you would not like to use the agent, you can construct the handler separately.
const TOKEN } = processenv const Eris = const client = TOKEN const CommandHandler } = const commands replacers } = const handler = client client
Creating Commands
The Command Handler takes an array of command and replacer classes to function. A multifile system is optimal. A way to implement this would be a folder containing JS files of every command with an index.js
that would require every command (Looping on an fs.readdir()
) and return an array containing them.
Command File:
const Command } = const data = name: 'say' desc: 'Make the bot say something.' options: args: name: 'content' mand: true restricted: true /* Make this command bot-owner only */ content /* The command returns the content provided by the user */ moduleexports = data
Awaiting Messages
Certain commands require multiple messages from a user. If a command asks a question, it will usually want to await a response from the user. This can be done with awaits.
Command File:
const Command Await } = const data = name: 'ban' desc: 'Ban a user' options: args: name: 'username' mand: true { const user = clientusers if !user return '`Could not find user.`' const rspData = options: args: name: 'response' mand: true timeout: 10000 msgchannel { if response === 'yes' return client else return 'Ban cancelled.' } return content: `Are you sure you want to ban `$userusername`? (Cancels in 10 seconds)` awaits: rspData } moduleexports = data
Creating Replacers
Replacers are passed to the command handler and are applied to messages that trigger commands. Using keywords, live data can be inserted into your message as if you typed it. For example, you could replace |TIME|
in a message with the current date and time.
Replacer File:
const Replacer } = const data = key: 'TIME' desc: 'The current time' options: args: name: 'timezone' /* If I wrote `!say |TIME America/New_York|` at 12:00PM in London on Frebruary 2nd 1996, The bot would respond with `2/2/1996, 7:00:00 AM`. (The timezone is optional)*/ moduleexports = data
Constructing the Reaction Handler without the agent
The Reaction Handler is taken care of automatically when the agent is constructed and connected. However, if you would not like to use the agent, you can construct the handler separately.
const ReactionHandler } = const reactCommands } = const handler = client client
Creating React Commands
React commands listen for when any user reacts to any command with a certain emoji.
React Command File:
const ReactCommand } = const MODERATOR_CHANNELID } = processenv const data = emoji: '❗' /* A custom emoji would be `:name:id` (Animated emojis are `a:name:id`) */ desc: 'Report a message to the moderators' { return content: `Reported by **. Message link: https://discordapp.com/channels///` embed: author: name: msgauthorusername icon_url: msgauthoravatarURL title: msgcontent options: channels: MODERATOR_CHANNELID } moduleexports = data
Binding interfaces to messages
Interfaces are a group of emojis the bot adds to a messages. When an emoji is clicked, the bot executes the appropriate action. Interfaces can be bound manually with ReactionHandler.prototype.bindInterface()
See documentation, or they can be included in the options of an action return (This includes commands, awaits, and react commands).
const Command ReactInterface } = const ADMIN_ROLEID MUTED_ROLEID } const data = name: 'manage' desc: 'Open an administrative control panel for a user' options: args: name: 'username' mand: true { if !msgmemberroles return '`You are not authorized.`' const user = msgchannelguildmembers if !user return '`Could not find user.`' const muteButton = userroles ? emoji '😮' /* Unmute */ { return user } : emoji: '🤐' /* Mute */ { return user } const msgInterface = buttons: muteButton emoji: '👢' /* Kick */ user emoji: '🔨' /* Ban */ user options: deleteAfterUse: true return content: `**#**` options: reactInterface: msgInterface } moduleexports = data