Skip to content

Commands Behavior

Protected edited this page Nov 18, 2023 · 1 revision

A system for registering callbacks for text chat-based (cross-Environment friendly) commands. It has a built-in help system and alias support, and integrates with Users for permission-locking commands and providing account information to callbacks.

Commands are defined as a prefix followed by a list of words separated by spaces that identify the command itself, an optional space, and a further list of words that are passed to the command handler as arguments.

Double quotes can be used to include spaces in command arguments, aggregating multiple words together.

For example:

!my command argument1 "argument 2" might be interpreted as a command with two arguments, if my command was registered as a command.

Commands that are consumed by this Behavior interrupt the Environments' message event, so this Behavior should be declared near the top.

Command prefixes

The default prefix for commands is !, but can be replaced using the defaultprefix config parameter.

Additionally, you can define a different prefix for each Environment by using the prefixes config parameter, which maps Environment names to prefixes. If an Environment isn't in prefixes, the default prefix is assumed.

Environments can be excluded from Commands entirely using the allowedenvs config parameter. By default, all Environments respond to commands in both public and private.

Permissions

Behavior developers can restrict commands to users with certain permissions using the permissions system from the Users Behavior.

However, the default permissions associated with any command can be overridden using the permissions config parameter, which is a map:

permissions:
  COMMAND: PERMISSIONS
  ...

COMMAND should be the command whose permissions you want to redefine. All words of the command name must be listed (but not the command prefix).

PERMISSIONS can be:

  • A list of permissions, each one of which is sufficient for using the command;
  • true, which makes the command usable by anyone;
  • false, which disables and delists the command.

Aliases

The aliases config parameter can be used for declaring alternative names for commands.

aliases:
  COMMAND: [ALIAS, ...]

The original command and every listed alias will be active and usable at the same time.

It's possible to disable the original command without disabling its aliases, or to set different permissions for the original command and each alias, using the permission parameter. Permissions set for the original command do not propagate to its aliases; you must repeat any manual permission overrides for each alias.

The !help command

Commands provides a versatile built-in help system through the !help command. The syntax is:

  • !help - To receive a list of available commands via private message. This usage of !help is context-aware; only commands available to the user and channel where !help was used will be listed.
  • !help FULL COMMAND NAME - To receive the syntax, description and detailed information on a command in the current channel. This help request can be used anywhere, even if the user doesn't have permission to use the command itself or it can't be used in the current channel.
  • !help PARTIAL COMMAND NAME - For command names with multiple words, asking for help for just some of the words will result in a list of every command whose name starts with those words along with its description.

Registering commands

NOTE: This API is pending refactoring.

If you're developing a Behavior and want to register a command, use the registerCommand(behavior, command, options, callback) method, which expands to:

this.be("Commands").registerCommand(behavior, command,
    {
        args,
        minArgs,
        description,
        details,
        environments,
        types,
        permissions,
        requireAllPermissions,
        unobtrusive
    }, (env, type, authorid, channelid, command, args, handle, {reply, pub, priv, react, ok}) => {
        ...
        return true;
    }
);

The available options are:

  • args: A list of command line arguments that may be consumed from the words included in the text message, after the command. Each argument will contain a single word, unless multiple words are aggregated "using double quotes". In addition, if true is appended to the end of the list of arguments, the second to last argument will become a variable length argument that contains a list of all remaining words instead of just a single word.
  • minArgs: The minimum amount of required arguments. By default, this is the same as the amount of entires in the args list. If it's lower, then all the arguments above this number are optional arguments; it can also be higher if you want to set a minimum length for the variable length argument. If the minimum arguments check fails, the command syntax is returned instead.
  • description: A one line description of the command, displayed in !help and !help COMMAND.
  • details: A list of text lines that are displayed in !help COMMAND, meant to contain detailed information on how to use the command.
  • environments: A list of Environment types that the command can be used from (by default, all Environment types are allowed).
  • types: A list of message types that the command can be used from (by default, all message types are allowed - ie, public and private messages).
  • permissions: A list of permissions, one of which is required for the command to be usable, and which must be assigned manually to the user's account or provided by a permissions provider. By default, the command requires no permissions and no user account.
  • requireAllPermissions: Set to true if all of the permissions listed in the permissions option are required for the command to be used, rather than just one.
  • unobtrusive: Set to true if you want certain replies to the user to be delivered using a notice instead of msg, including failures to use the command and calls to priv.

The arguments passed to the callback are:

  • env: The Environment the command was invoked in.
  • type: The message type the command was used from.
  • authorid: The User ID (within the Environment) of the user of the command.
  • channelid: If the command was used in a channel, the ID of that channel; otherwise, the ID of the user again.
  • command: The command, not including arguments.
  • args: A map containing the value for each declared argument (optional arguments might be missing). If there's a variable length argument, it will contain a list of words.
  • handle: If the user of the command has a user account, this will be the handle of the account (optional).
  • reply(msg): A function that will deliver a reply to the user in the same context where the command was used.
  • pub(msg): A function that will attempt to deliver a reply to the user in public. If there is no public channel associated with the message, it may fail.
  • priv(msg): A function that will deliver a reply to the user by private message (or, if unobtrusive is true, by notification).
  • react(emoji): (EnvDiscord only) Reacts to the command message with the given emoji.
  • ok(): Reacts to the command message with ✅ if possible, or replies with "Ok." otherwise.

The command callback should return true. If the callback returns false, the command will be treated as failed and Commands will reply to the user with the command's syntax.

unregisterCommand(command) can be used by the Behavior that owns the command to unregister it.

Registering and extending a command root

The command root system provides a structured way for multiple Behaviors to register commands that start with the same word or words. In this event, we call these sub-commands under the same root command.

One of the Behaviors involved is the owner of the root. That Behavior should call:

registerRootDetails(behavior, commandroot, {description, details})

One or more other Behaviors will extend this root with additional commands. These Behaviors should first call:

registerRootExtension(behavior, rootBehaviorType, commandroot)

These Behaviors should have the owner in their requiredBehaviors, because registerRootDetails should be called before registerRootExtension for each commandroot.

Example:

class MyBehaviorA extends Behavior {

    get requiredBehaviors() {
        Commands: "Commands",
        BehaviorOfTypeMyBehaviorB: "MyBehaviorB"
    }

    constructor(name) {
        super('MyBehaviorA', name);
    }

    initialize(opt) {
        if (!super.initialize(opt)) return false;

        this.be("Commands").registerRootExtension(this, "MyBehaviorB", "color");

        this.be("Commands").registerCommand(this, "color red", {description: "A red command"},
            (env, type, authorid, channelid, command, args, handle, {reply}) => {
                reply("This command is red!");
                return true;
            }
        );

        return true;
    }

}

class MyBehaviorB extends Behavior {

    get requiredBehaviors() {
        Commands: "Commands"
    }

    constructor(name) {
        super('MyBehaviorB', name);
    }

    initialize(opt) {
        if (!super.initialize(opt)) return false;

        this.be("Commands").registerRootDetails(this, "color", {description: "Colorful commands"});

        this.be("Commands").registerCommand(this, "color blue", {description: "A blue command"},
            (env, type, authorid, channelid, command, args, handle, {reply}) => {
                reply("This command is blue!");
                return true;
            }
        );

        return true;
    }

}
Clone this wiki locally