We prefer pull-requests that are descriptive of the changes being made
and highlight any potential benefits/drawbacks of the change, but these
types of write-ups are not required. See this [merge request](https://github.com/RogueException/Discord.Net/pull/793)
types of write-ups are not required. See this [merge request](https://github.com/discord-net/Discord.Net/pull/793)
for an example of a well-written description.
## Semantic Versioning
@@ -28,7 +28,7 @@ that are SemVer compliant with the latest version of the library in
development.
The working release should be the latest build off of the `dev` branch,
but can also be found on the [development board](https://github.com/RogueException/Discord.Net/projects/1).
but can also be found on the [development board](https://github.com/discord-net/Discord.Net/projects/1).
We follow the .NET Foundation's [Breaking Change Rules](https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/breaking-change-rules.md)
when determining the SemVer compliance of a change.
@@ -59,4 +59,4 @@ The length of the documentation should also follow the ruler as suggested by our
#### Recommended Reads
* [Official Microsoft Documentation](https://docs.microsoft.com)
* [Sandcastle User Manual](https://ewsoftware.github.io/XMLCommentsGuide/html/4268757F-CE8D-4E6D-8502-4F7F2E22DDA3.htm)
* [Sandcastle User Manual](https://ewsoftware.github.io/XMLCommentsGuide/html/4268757F-CE8D-4E6D-8502-4F7F2E22DDA3.htm)
Nightly builds are available through our MyGet feed (`https://www.myget.org/F/discord-net/api/v3/index.json`).
### Unstable (Labs)
Labs builds are available on nuget (`https://www.nuget.org/packages/Discord.Net.Labs/`) and myget (`https://www.myget.org/F/discord-net-labs/api/v3/index.json`).
## Compiling
In order to compile Discord.Net, you require the following:
### Using Visual Studio
- [Visual Studio 2017](https://www.microsoft.com/net/core#windowsvs2017)
.NET Core 1.1 does not support WebSockets on Win7 and earlier. This issue has been fixed since the release of .NET Core 2.1. It is recommended to target .NET Core 2.1 or above for your project if you wish to run your bot on legacy platforms; alternatively, you may choose to install the [Discord.Net.Providers.WS4Net](https://www.nuget.org/packages/Discord.Net.Providers.WS4Net/) package.
This section answers basic questions and common mistakes in handling application commands, and responding to them.
## What's the difference between RespondAsync, DeferAsync and FollowupAsync?
The difference between these 3 functions is in how you handle the command response.
[RespondAsync] and
[DeferAsync] let the API know you have succesfully received the command. This is also called 'acknowledging' a command.
DeferAsync will not send out a response, RespondAsync will.
[FollowupAsync] follows up on succesful acknowledgement.
> [!WARNING]
> If you have not acknowledged the command FollowupAsync will not work! the interaction has not been resonded to, so you cannot follow it up!
[RespondAsync]: xref:Discord.IDiscordInteraction
[DeferAsync]: xref:Discord.IDiscordInteraction
[FollowUpAsync]: xref:Discord.IDiscordInteraction
## Im getting System.TimeoutException: 'Cannot respond to an interaction after 3 seconds!'
This happens because your computers clock is out of sync or your trying to respond after 3 seconds. If your clock is out of sync and you cant fix it, you can set the `UseInteractionSnowflakeDate` to false in the config.
## Bad form Exception when I try to create my commands, why do I get this?
Bad form exceptions are thrown if the slash, user or message command builder has invalid values.
The following options could resolve your error.
#### Is your command name lowercase?
If your command name is not lowercase, it is not seen as a valid command entry.
`Avatar` is invalid; `avatar` is valid.
#### Are your values below or above the required amount? (This also applies to message components)
Discord expects all values to be below maximum allowed.
Going over this maximum amount of characters causes an exception.
> [!NOTE]
> All maximum and minimum value requirements can be found in the [Discord Developer Docs].
> For components, structure documentation is found [here].
Ratelimits are a core concept of any API - Discords API is no exception. each verified library must follow the ratelimit guidelines.
### Using the ratelimit callback
There is a new property within `RequestOptions` called RatelimitCallback. This callback is called when a request is made via the rest api. The callback is called with a `IRateLimitInfo` parameter:
| IsGlobal | bool | Whether or not this ratelimit info is global. |
| Limit | int? | The number of requests that can be made. |
| Remaining | int? | The number of remaining requests that can be made. |
| RetryAfter | int? | The total time (in seconds) of when the current rate limit bucket will reset. Can have decimals to match previous millisecond ratelimit precision. |
| Reset | DateTimeOffset? | The time at which the rate limit resets. |
| ResetAfter | TimeSpan? | The absolute time when this ratelimit resets. |
| Bucket | string | A unique string denoting the rate limit being encountered (non-inclusive of major parameters in the route path). |
| Lag | TimeSpan? | The amount of lag for the request. This is used to denote the precise time of when the ratelimit expires. |
| Endpoint | string | The endpoint that this ratelimit info came from. |
Let's set up a ratelimit callback that will print out the ratelimit info to the console.
```cs
public async Task MyRatelimitCallback(IRateLimitInfo info)
You can get a collection of users who are currently interested in the event by calling `GetUsersAsync`. This method works like any other get users method as in it returns an async enumerable. This method also supports pagination by user id.
```cs
// get all users and flatten the result into one collection.
var users = await event.GetUsersAsync().FlattenAsync();
// get users around the 613425648685547541 id.
var aroundUsers = await event.GetUsersAsync(613425648685547541, Direction.Around).FlattenAsync();
There are two kinds of Context Menu Commands: User Commands and Message Commands.
Each of these have a Global and Guild variant.
Global menu commands are available for every guild that adds your app. An individual app's global commands are also available in DMs if that app has a bot that shares a mutual guild with the user.
Guild commands are specific to the guild you specify when making them. Guild commands are not available in DMs. Command names are unique per application within each scope (global and guild). That means:
- Your app cannot have two global commands with the same name
- Your app cannot have two guild commands within the same name on the same guild
- Your app can have a global and guild command with the same name
- Multiple apps can have commands with the same names
[!IMPORTANT]
> Apps can have a maximum of 5 global context menu commands,
> and an additional 5 guild-specific context menu commands per guild.
## UserCommandBuilder
The context menu user command builder will help you create user commands. The builder has these available fields and methods:
// Now that we have our builder, we can call the BulkOverwriteApplicationCommandAsync to make our context commands. Note: this will overwrite all your previous commands with this array.
// If our command was invalid, we should catch an ApplicationCommandException. This exception contains the path of the error as well as the error message. You can serialize the Error field in the exception to get a visual of where your error is.
var json = JsonConvert.SerializeObject(exception.Error, Formatting.Indented);
// You can send this error somewhere or just print it to the console, for this example we're just going to print it.
Console.WriteLine(json);
}
}
```
> [!NOTE]
> Application commands only need to be created once. They do _not_ have to be
> 'created' on every startup or connection.
> The example simple shows creating them in the ready event
> as it's simpler than creating normal bot commands to register application commands.
User commands and Message commands have their own unique event just like the other interaction types. For user commands the event is `UserCommandExecuted` and for message commands the event is `MessageCommandExecuted`.
With slash command options you can add choices, making the user select between some set values. Lets create a command that asks how much they like our bot!
Let's set up our slash command:
```cs
private async Task Client_Ready()
{
ulong guildId = 848176216011046962;
var guildCommand = new SlashCommandBuilder()
.WithName("feedback")
.WithDescription("Tell us how much you are enjoying this bot!")
.AddOption(new SlashCommandOptionBuilder()
.WithName("rating")
.WithDescription("The rating your willing to give our bot")
var json = JsonConvert.SerializeObject(exception.Error, Formatting.Indented);
Console.WriteLine(json);
}
}
```
> [!NOTE]
> Your `ApplicationCommandOptionType` specifies which type your choices are, you need to use `ApplicationCommandOptionType.Integer` for choices whos values are whole numbers, `ApplicationCommandOptionType.Number` for choices whos values are doubles, and `ApplicationCommandOptionType.String` for string values.
We have defined 5 choices for the user to pick from, each choice has a value assigned to it. The value can either be a string or an int. In our case we're going to use an int. This is what the command looks like:
There are two kinds of Slash Commands: global commands and guild commands.
Global commands are available for every guild that adds your app. An individual app's global commands are also available in DMs if that app has a bot that shares a mutual guild with the user.
Guild commands are specific to the guild you specify when making them. Guild commands are not available in DMs. Command names are unique per application within each scope (global and guild). That means:
- Your app cannot have two global commands with the same name
- Your app cannot have two guild commands within the same name on the same guild
- Your app can have a global and guild command with the same name
- Multiple apps can have commands with the same names
**Note**: Apps can have a maximum of 100 global commands, and an additional 100 guild-specific commands per guild.
**Note**: Global commands will take up to 1 hour to create, delete or modify on guilds. If you need to update a command quickly for testing you can create it as a guild command.
If you don't have the code for a bot ready yet please follow [this guide](https://docs.stillu.cc/guides/getting_started/first-bot.html).
## SlashCommandBuilder
The slash command builder will help you create slash commands. The builder has these available fields and methods:
// Using the ready event is a simple implementation for the sake of the example. Suitable for testing and development.
// For a production bot, it is recommended to only run the CreateGlobalApplicationCommandAsync() once for each command.
}
catch(ApplicationCommandException exception)
{
// If our command was invalid, we should catch an ApplicationCommandException. This exception contains the path of the error as well as the error message. You can serialize the Error field in the exception to get a visual of where your error is.
var json = JsonConvert.SerializeObject(exception.Error, Formatting.Indented);
// You can send this error somewhere or just print it to the console, for this example we're just going to print it.
Console.WriteLine(json);
}
}
```
> [!NOTE]
> Slash commands only need to be created once. They do _not_ have to be 'created' on every startup or connection. The example simple shows creating them in the ready event as it's simpler than creating normal bot commands to register slash commands. The global commands take up to an hour to register every time the CreateGlobalApplicationCommandAsync() is called for a given command.
What is an ephemeral response? Basically, only the user who executed the command can see the result of it, this is pretty simple to implement.
> [!NOTE]
> You don't have to run arg.DeferAsync() to capture the interaction, you can use arg.RespondAsync() with a message to capture it, this also follows the ephemeral rule.
When responding with either `FollowupAsync` or `RespondAsync` you can pass in an `ephemeral` property. When setting it to true it will respond ephemerally, false and it will respond non-ephemerally.
Interactions are the base thing sent over by Discord. Slash commands are one of the interaction types. We can listen to the `SlashCommandExecuted` event to respond to them. Lets add this to our code:
With every type of interaction there is a `Data` field. This is where the relevant information lives about our command that was executed. In our case, `Data` is a `SocketSlashCommandData` instance. In the data class, we can access the name of the command triggered as well as the options if there were any. For this example, we're just going to respond with the name of the command executed.
> After receiving an interaction, you must respond to acknowledge it. You can choose to respond with a message immediately using `RespondAsync()` or you can choose to send a deferred response with `DeferAsync()`.
> If choosing a deferred response, the user will see a loading state for the interaction, and you'll have up to 15 minutes to edit the original deferred response using `ModifyOriginalResponseAsync()`. You can read more about response types [here](https://discord.com/developers/docs/interactions/slash-commands#interaction-response)
This seems to be working! Next, we will look at parameters for slash commands.
Subcommands allow you to have multiple commands available in a single command. They can be useful for representing sub options for a command. For example: A settings command. Let's first look at some limitations with subcommands set by discord.
- An app can have up to 25 subcommand groups on a top-level command
- An app can have up to 25 subcommands within a subcommand group
- commands can have up to 25 `options`
- options can have up to 25 `choices`
```
VALID
command
|
|__ subcommand
|
|__ subcommand
----
command
|
|__ subcommand-group
|
|__ subcommand
|
|__ subcommand-group
|
|__ subcommand
-------
INVALID
command
|
|__ subcommand-group
|
|__ subcommand-group
|
|__ subcommand-group
|
|__ subcommand-group
----
INVALID
command
|
|__ subcommand
|
|__ subcommand-group
|
|__ subcommand
|
|__ subcommand-group
```
Let's write a settings command that can change 3 fields in our bot.
```cs
public string FieldA { get; set; } = "test";
public int FieldB { get; set; } = 10;
public bool FieldC { get; set; } = true;
public async Task Client_Ready()
{
ulong guildId = 848176216011046962;
var guildCommand = new SlashCommandBuilder()
.WithName("settings")
.WithDescription("Changes some settings within the bot.")
Lets say you have some components on an ephemeral slash command, and you want to modify the message that the button is on. The issue with this is that ephemeral messages are not stored and can not be get via rest or other means.
Luckily, Discord thought of this and introduced a way to modify them with interactions.
### Using the UpdateAsync method
Components come with an `UpdateAsync` method that can update the message that the component was on. You can use it like a `ModifyAsync` method.
Lets use it with a command, we first create our command, in this example im just going to use a message command:
| label | `string` | The label text for the button. |
| customId | `string` | The custom id of the button. |
| style | `ButtonStyle` | The style of the button. |
| emote | `IEmote` | A IEmote to be used with this button. |
| url | `string` | A URL to be used only if the `ButtonStyle` is a Link. |
| disabled | `bool` | Whether or not the button is disabled. |
| row | `int` | The row to place the button if it has enough room, otherwise 0 |
### Label
This is the front facing text that the user sees. The maximum length is 80 characters.
### CustomId
This is the property sent to you by discord when a button is clicked. It is not required for link buttons as they do not emit an event. The maximum length is 100 characters.
### Style
Styling your buttons are important for indicating different actions:

You can do this by using the `ButtonStyle` which has all the styles defined.
### Emote
You can specify an `IEmote` when creating buttons to add them to your button. They have the same restrictions as putting guild based emotes in messages.
### Url
If you use the link style with your button you can specify a url. When this button is clicked the user is taken to that url.
### Disabled
You can specify if your button is disabled, meaning users won't be able to click on it.
Thank you for your continuous support to the Openl Qizhi Community AI Collaboration Platform. In order to protect your usage rights and ensure network security, we updated the Openl Qizhi Community AI Collaboration Platform Usage Agreement in January 2024. The updated agreement specifies that users are prohibited from using intranet penetration tools. After you click "Agree and continue", you can continue to use our services. Thank you for your cooperation and understanding.