|
9 months ago | |
---|---|---|
assets | 11 months ago | |
spec | 9 months ago | |
src | 9 months ago | |
.gitattributes | 10 months ago | |
.gitignore | 11 months ago | |
.travis.yml | 1 year ago | |
Dockerfile | 10 months ago | |
LICENSE | 9 months ago | |
Makefile | 10 months ago | |
README.md | 11 months ago | |
docker-compose.yml | 11 months ago | |
shard.lock | 9 months ago | |
shard.yml | 9 months ago |
Amaranth is a Discord bot written Crystal using discordcr and discordcr-middleware.
Anything in src/amaranth
could get moved to an external repo at any time.
Amaranth now supports plugins and namespaced commands! Available commands are:
bot: rename
carc: eval, langs
chan: rename
dota: latest
github: add, list, remove
patches: check, disable, enable, games, gids, list, list_all, stop_all
rust: crate?, crates, eval, versions
clear, commands, echo, help
So to run a command, use <group>.<command>
or <command>
.
Commands have several initialization methods. You must specify a name
and desc
, but min_args
, max_args
and permissions
are optional.
name
and desc
are of type String.
desc
shows up when a user types help <command>
.permissions
are of the type Discord::Permissions.Example description and output:
desc = <<-DESC
Gets latest dota match.
Usage: dota.latest [dotaID] where ID is optional.
You can save your ID using dota.add. You can find your ID at opendota.com.
DESC
alias ExecType = Proc(Array(String), Discord::Context, CommandReturn)
def initialize(@name, @desc, &@exec : ExecType)
def initialize(@name, @desc, @permissions, &@exec : ExecType)
def initialize(@name, @desc, @min_args : Int32, &@exec : ExecType)
def initialize(@name, @desc, @min_args : Int32, @max_args : Int32, &@exec : ExecType)
def initialize(@name, @desc, @min_args : Int32, @max_args : Int32, @permissions : Discord::Permissions, &@exec : ExecType)
desc = <<-DESC
This command is an example command.
Usage: name
DESC
command "name", desc, do |args, context|
# etc
end
perms = Discord::Permissions.flags(ReadMessages, SendMessages, KickPeople)
command "example", desc, 1, 2, perms do |args, context|
end
PreCommands are a limited version of Commands:
Discord::Message | Nil
pre_command do |context|
# something to be run before any command
end
PreCommands are new to Amaranth so they are prone to change.
The plugin class needs to inherit from Plugin.
class ExamplePlugin < Plugin::Plugin
end
To make a grouped command that says Hello, world!
:
class ExamplePlugin < Plugin::Plugin
group "example" do
desc = "My description"
command "hello", desc do |args, context|
"Hello, world!"
end
end
end
# this registers example.hello as a command!
To make a command without a group, omit group
. However, make sure there aren’t multiple commands with the same name.
class ExamplePlugin < Plugin::Plugin
desc = "My description"
command "hello", desc do |args, context|
"Hello, world!"
end
end
# this registers hello as a command!
Amaranth allows you to manually run context.client.create_message()
or use implicit returns and automatically handle it for you.
Implicit Return Types:
context.client.create_message(context.message.channel.id, <string>)
context.client.create_message(context.message.channel.id, "", <embed>)
NamedTuple(msg: String, embed: Discord::Embed)
: Amaranth will run context.client.create_message(context.message.channel.id, <string>, <embed>)
Discord::Message
: No message will be created.Discord::Channel
: No message will be created.Discord::Guild
: No message will be created.Return types like Discord::Channel
get returned from context.client
commands and thus do not warrant a message.
Note: Returning an empty string (“”) also causes no message to be created.
To get access to helper methods for saving a config, you need two things:
Extend
your plugin class with the config type of your Config.class ExampleConfig
MessagePack.mapping({
ids: Array(UInt64),
channels: Array(UInt64)
})
end
class ExamplePlugin < Plugin::Plugin
extend Plugin::Config(ExampleConfig)
end
Now you get access to two methods:
get_config(name : String)
which returns an existing config or creates a new onesave_config(name : String, config : ConfigType)
which saves your configclass ExampleConfig
MessagePack.mapping({
ids: Array(UInt64),
channels: Array(UInt64)
})
end
class ExamplePlugin < Plugin::Plugin
extend Plugin::Config(ExampleConfig)
group "example" do
command "list" do |args, context|
config = get_config("example")
config.channels.each do |channel|
context.client.create_message(channel, "Hello!")
end
end
end
end
You’ve created a plugin. Great! Now, how do you run it?
Amaranth runs on discordcr-middleware, so what you’ll want to do is create a stack
.
module ExampleBot
# in src/main.cr, etc
class_property client = Discord::Client.new(token)
class_property cache = Discord::Cache.new(client)
@@client.cache = @@cache
@@client.stack(:dota,
Common.new,
DiscordMiddleware::Error.new("%exception%"),
DiscordMiddleware::Prefix.new(prefix),
ParserMW.new(prefix),
PluginHandler.new(
[ExamplePlugin],
))
end
ExampleBot.client.run
PluginHandler
can take an array of an arbitary amount of plugins. Keep in mind to namespace your commands to avoid overwriting issues with commands of the same name.
plugin_handler.cr
manages the instantiation and hashing of group and command names, as well as command executionplugin/*
defines Plugin
, Group
, Command
, PreCommand
, Config
in the Plugin
namespaceparser/*
defines Parser::Parser
, Parser::Lexer
help
property for each command, so one can run help command
to get more information.Interested in development? Message @ Andrei#8263 (9132965190) on Discord.