-
Notifications
You must be signed in to change notification settings - Fork 4
Lua Commands
⚠ This Wiki page is under construction, and will receive frequent updates as features are added.
Lua commands are a powerful way to extend Administrator's own functionality into truly, fully custom commands for your server. You control everything - the name, description, options, and even what the command physically does!
- Lua commands utilize a basic Lua installation ONLY. Other flavors or variants of Lua are not supported, though they may share some syntax with Lua.
- The below libraries are enabled by default. If you have a good reason to request another standard library be enabled, feel free to ask.
- Base
- Math
- String
- Table
- Non-native Lua methods provided for additional functionality are subject to strict rate-limits. To prevent abuse and spam, most external and/or Discord-related methods can only be used a limited number of times before command execution will fail due to exceeding the rate-limit.
This feature is intended for power users who know what they are doing. Basic programming knowledge is a must, and knowledge of Lua itself will only make things easier. There are plenty of resources and tutorials out there, but you're always welcome to start with Lua's official site.
When you submit your file to /lua-command set, a certain file structure is expected for the sake of how Lua commands are parsed and handled. Your submitted file must have the .lua file extension, and must follow the below design, or an error will be returned when attempting to create it.
-- A 'metadata' object MUST be defined.
local metadata = {
name = "echo",
permissions = Permission.MANAGE_MESSAGES,
description = "Repeat some text back to yourself.",
options = {
text = {
description = "The text to echo."
}
}
}
-- The END METADATA comment must appear exactly like the below line to indicate an unambiguous metadata/command separation.
-- END METADATA --
-- After the END METADATA comment, you should begin the "execution" section of your command. This is the code that is actually called when a user uses your custom command.
return ctx.parameters.textCommand metadata is defined and expressed via the metadata object. While this section is far from exhaustive, it can give you a good idea of what to expect when defining metadata for a command. Any options commented with (optional) are not required for command metadata. Again using our /echo example:
Metadata example
local metadata = {
-- The name of the command. This is what is displayed in the command menu.
-- This is absolutely required.
name = "echo",
-- (optional) The permissions required to see and execute this command.
-- For a full list of permission names, see https://discord.com/developers/docs/topics/permissions#permissions-bitwise-permission-flags
permissions = Permission.MANAGE_MESSAGES,
-- (optional) The description of the command. This is displayed under the name in the command menu.
description = "Repeat some text back to yourself.",
-- (optional) The options for this command. These are displayed after the name in the command menu.
options = {
-- The name of the option. This is required, can only be lowercase characters, hyphens (-), and underscores (_), and must be unique per-command.
text = {
-- (optional) The description for this option.
description = "The text to echo.",
-- (optional) The type for this option. Defaults to "string".
--[[
Available options are:
"string"
"integer"
"boolean"
"user"
"channel"
"role"
"mentionable"
"number"
"attachment"
"subcommand"
"subcommandgroup"
--]]
type = "string",
-- (optional) Whether this option is required (true) or optional (false) for the command. Defaults to required (true).
required = true,
-- (optional) If type = "channel", an array of channel types this option accepts.
--[[
Available options are:
"text"
"direct"
"voice"
"group"
"category"
"news"
"newsthread"
"publicthread"
"privatethread"
"stage"
"directory"
"forum"
--]]
-- channelTypes = { "text", "publicthread" },
-- (optional) The minimum value for an "integer" or "number" option, or the minimum length for a "string" option. Defaults to no minimum.
-- minimum = 5,
-- (optional) The maximum value for an "integer" or "number" option, or the maximum length for a "string" option. Defaults to no maximum.
-- maximum = 500,
-- (optional) If type = "subcommand" or "subcommandgroup", specifies a table of nested options below this option.
-- More detailed documentation on this Discord feature can be found here: https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-structure
--[[
This is used for more advanced command structure, such as the following:
/something create <name>
/something delete <name>
/something modify <name>
--]]
-- options = { },
}
}
}Your command's "context" table, ctx, stores various data pertaining to the command, where it was executed, who executed it, and what information was passed to the command, if any. Several methods and properties are available to you.
| Property | Description |
|---|---|
ctx.author |
A user object representing the user who used the command. |
ctx.channel |
A channel object representing the channel this command was used in. |
ctx.guild |
A guild object representing the guild (server) this command was used in. |
ctx.parameters |
A table containing parameters passed to the command, as well as their values if they were provided. |
ctx.path |
A table (array) containing each part of the command path. Example: /command sub sub1 → {"command", "sub", "sub1"}
|
Users have the following structure, with an example variable user:
| Property/Method | Description |
|---|---|
user.id |
The unique ID of the user. |
user.name |
The unique username of the user. |
user.mention |
The mention of the user as it would appear in chat. |
user.tag |
The user's tag. |
user.discriminator |
The user's classic Discord discriminator, if set. |
user.globalName |
The user's global name, if set. |
user.avatar |
The user's global avatar URL. |
user.bot |
Whether this user is a bot. |
user.member |
Whether this user is a server member (the below properties will evaluate to nil if this is false) |
user.roles |
An array of the user's role IDs, if any. |
user.joined |
When the user joined the server (in UTC*). |
user.nickname |
The user's nickname, or nil if they don't have a nickname. |
user.muted |
Whether the user is server muted. |
user.deafened |
Whether the user is server deafened. |
user.boosted |
When the user first started boosting the server (in UTC*), or nil if they aren't boosting. |
user.pending |
Whether the user is still pending membership screening/verification. |
user.guildAvatar |
The user's server (guild) avatar, or their global avatar if they don't have one. |
user.timedOutUntil |
When the user is timed out until (in UTC*), or nil if they aren't timed out. |
user.permissions |
The user's total calculated server permissions. You can check individual permissions via hasPermission(permission) instead. |
user:hasPermission(permission) |
Returns whether the user has a specific permission or permissions set. |
user:setNickname(nickname) |
Updates the user's nickname. |
user:kick(reason) |
Kicks the user out. |
user:ban(reason) |
Bans the user. |
user:grantRole(roleId) |
Grants (gives) the user a role. |
user:revokeRole(roleId) |
Revokes (removes) a role from the user. |
Channels have the following structure, with an example variable channel:
| Property/Method | Description |
|---|---|
ctx.channel.id |
The unique ID for this channel. |
ctx.channel.name |
The name for this channel. |
ctx.channel.type |
The type of this channel. See channelTypes in the metadata section for a |
ctx.channel.mention |
The mention for this channel as it would appear in chat. |
ctx.channel.position |
The position of this channel, relative to other nearby channels. |
ctx.channel:setName(name) |
Attempts to rename the channel. |
ctx.channel:lastMessageId |
The most recent message's ID in the channel, or nil if it doesn't exist. |
ctx.channel.tag |
The channel's tag. |
ctx.channel.lastPin |
When a message was most recently pinned (in UTC*), or nil if it doesn't exist. |
ctx.channel.ageRestricted |
Whether this channel is marked as age restricted (formerly NSFW). |
ctx.channel.slowmode |
The slowmode on this channel, in seconds. |
ctx.channel.topic |
The topic for this channel, or nil if it doesn't exist. |
ctx.channel.categoryId |
The unique ID of the category this channel belongs to, or nil if it doesn't belong to one. |
ctx.channel.news |
Whether this channel is a new channel. |
ctx.channel.archiveThreadsAfter |
The span of time after which inactive threads are automatically archived, or nil if it doesn't exist. |
ctx.channel:setTopic(topic) |
Attempts to set the channel topic. |
ctx.channel:delete() |
Attempts to delete the channel. |
ctx.channel:sendMessage(msg) |
Sends a message to the channel. |
ctx.channel:getMessage(id) |
Returns a message with the specified ID in the channel, or nil if it doesn't exist. |
ctx.channel.parentId |
If the channel is a thread, the ID of the channel the thread belongs to. |
ctx.channel.creatorId |
If the channel is a thread, the ID of the user who created it. |
ctx.channel.tags |
If the channel is a forum thread, an array of IDs representing the tags on it. |
ctx.channel.memberLimit |
If the channel is a voice channel, the maximum number of members allowed to connect. |
Guilds have the following structure, with an example variable guild:
| Property/Method | Description |
|---|---|
ctx.guild.id |
The unique ID for this guild. |
ctx.guild.name |
The name for this guild. |
ctx.guild.icon |
The icon URL for this guild, or nil if it doesn't exist. |
ctx.guild.splash |
The splash image URL for this guild, or nil if it doesn't exist. |
ctx.guild.discoverySplash |
The discovery splash image URL for this guild, or nil if it doesn't exist. |
ctx.guild.ownerId |
The ID of the owner of this guild. |
ctx.guild.verificationLevel |
The verification level of this guild. |
ctx.guild.notificationLevel |
The notification level of this guild. |
ctx.guild.contentFilterLevel |
The content filter level of this guild. |
ctx.guild.roles |
An array of roles belonging to this guild. |
ctx.guild.emojis |
An array of emojis belonging to this guild. |
ctx.guild.features |
An array of strings representing features enabled on this guild. |
ctx.guild.systemChannelId |
The ID of the guild's system channel, or nil if it doesn't exist. |
ctx.guild.rulesChannelId |
The ID of the guild's rules channel, or nil if it doesn't exist. |
ctx.guild.vanityInviteCode |
The invite code for this guild's vanity invite, or nil if it doesn't exist. |
ctx.guild.description |
The guild's description, or nil if it doesn't exist. |
ctx.guild.banner |
The banner image URL for this guild, or nil if it doesn't exist. |
ctx.guild.boostTier |
The boost tier for this guild. |
ctx.guild.boosters |
The number of users boosting this guild. |
ctx.guild.updateChannelId |
The ID of the guild's public update channel, or nil if it doesn't exist. |
ctx.guild.nsfwLevel |
The NSFW (age restriction) level of this guild. |
ctx.guild.safetyChannelId |
The ID of the guild's safety alert channel, or nil if it doesn't exist. |
ctx.guild:banUser(id, reason, pruneDays) |
Bans a user from the server with a reason and a number of days' worth of messages to prune (nil or 0-7) |
ctx.guild:sendMessage(id, msg) |
Sends a message to a specified channel ID. |
Roles have the following structure, with an example variable role:
| Property/Method | Description |
|---|---|
role.id: The unique ID of this role. |
|
role.name: The name of this role. |
|
role.mention |
The mention for this role as it would appear in chat. |
role.color |
The HTML hex code for this role. |
role.icon |
If a default emoji, the raw emoji string. If an icon image, the URL to that image, or nil if it doesn't exist. |
role.hoisted |
Whether this role is "hoisted" or shown separately in the member list. |
role.position |
The position of this role, relative to other roles. |
role.permissions |
The role's total calculated permissions. |
role.managed |
Whether this role is managed by an integration, like a bot or third-party service. |
role.mentionable |
Whether this role can be directly mentioned in chat to notify its members. |
Emojis have the following structure, with an example variable emoji:
| Property/Method | Description |
|---|---|
emoji.id |
The unique ID of this emoji. |
emoji.tag |
The tag of this emoji. |
emoji.animated |
Whether this emoji animates in chat. |
emoji.name |
The name of this emoji. |
emoji.roleIds |
An array of role IDs allowed to use this emoji. |
emoji.creator |
A user object representing the user that created this emoji, or nil if it can't be found. |
emoji.managed |
Whether this emoji is managed by an integration, like a bot or third-party service. |
The parameters passed to the command with their values, if any.
-
ctx.parameters.[NAME]: The[NAME]parameter. In the/echoexample, you could access the valuectx.parameters.text.
On top of the ctx table, there are also several other features available to assist with making your Lua commands more flexible and further increasing their utility.
Discord permissions are stored in a handy Permission Lua table mimicking an enumeration. A full list of Discord permission names can be found on the official API documentation. For example, the "Manage Messages" permission can be expressed as Permission.MANAGE_MESSAGES.
Emojis can help spice up a command response and make it feel less boring. Similar to permissions, most to all emojis can be easily accessed via the Emoji Lua table. For most emojis, you can access them via Emoji.FULL_EMOJI_NAME (using the name as it appears in Discord), but for any emoji such as 🎱 (8BALL) which starts with a non-numeric character, you can index the table as usual, in this case Emoji["8BALL"].
To allow Lua commands to store data between executions for long-term storage, an extremely basic persistence library is provided. At the moment, only a single string value can be stored and retrieved, but what you can use the string to store is entirely up to you.
| Method | Description |
|---|---|
persistence.get() |
Returns the current value of this command's persistent data as a string, or nil if no data has been set before. |
persistence.set(value) |
Updates the persistent data with the supplied string value, returning a boolean value indicating if the save was successful. |
To allow Lua commands to, for example, query a remote web API (such as for displaying website data to users), a very basic REST request library is provided. This library is subject to extremely strict rate-limits, only allowing one request per method per command to prevent abuse.
| Method | Description |
|---|---|
http.get(url) |
Returns the response content located at url as a string, or nil if the request fails. |
To further extend both the Persistence and HTTP libraries, a JSON serialization and deserialization library is provided. This can allow remote web data returned as JSON to be more easily consumed, or to store complex persistent data in a more convenient format.
| Method | Description |
|---|---|
json.serialize(value) |
Returns the provided object, array, or value converted into a JSON string. |
json.deserialize(json) |
Converts the provided JSON string into a Lua table, or nil if the deserialization fails. |
Lua provides a helpful math.random() method for obtaining a random number. However, for security concerns, os.time() is not available in Lua commands, so you can utilize the helper method now() for seeding Lua's random number generator like so:
math.randomseed(now())
-- Now, calls to math.random() will be...random!