We prefer pull-requests that are descriptive of the changes being made
We prefer pull-requests that are descriptive of the changes being made
and highlight any potential benefits/drawbacks of the change, but these
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.
for an example of a well-written description.
## Semantic Versioning
## Semantic Versioning
@@ -28,7 +28,7 @@ that are SemVer compliant with the latest version of the library in
development.
development.
The working release should be the latest build off of the `dev` branch,
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)
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.
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
#### Recommended Reads
* [Official Microsoft Documentation](https://docs.microsoft.com)
* [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`).
Nightly builds are available through our MyGet feed (`https://www.myget.org/F/discord-net/api/v3/index.json`).
### Unstable (Labs)
Labs builds are avaiable 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
## Compiling
In order to compile Discord.Net, you require the following:
In order to compile Discord.Net, you require the following:
### Using Visual Studio
### Using Visual Studio
- [Visual Studio 2017](https://www.microsoft.com/net/core#windowsvs2017)
- [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.
.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.
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.
Message components are a framework for adding interactive elements to a message your app or bot sends. They're accessible, customizable, and easy to use.
## What is a Component
Components are a new parameter you can use when sending messages with your bot. There are currently 2 different types of components you can use: Buttons and Select Menus.
## Creating components
Lets create a simple component that has a button. First thing we need is a way to trigger the message, this can be done via commands or simply a ready event. Lets make a command that triggers our button message.
```cs
[Command("spawner")]
public async Task Spawn()
{
// Reply with some components
}
```
We now have our command, but we need to actually send the buttons with the command. To do that, lets look at the `ComponentBuilder` class:
Lets handle the selection of an option, We can hook the `SelectMenuExecuted` event to handle our select menu:
```cs
client.SelectMenuExecuted += MyMenuHandler;
```
The `SelectMenuExecuted` also supplies a `SocketMessageComponent` argument, we can confirm that its a select menu by checking the `ComponentType` inside of the data field if we need, but the library will do that for us and only execute our handler if its a select menu.
The values that the user has selected will be inside of the `Values` collection in the Data field. we can list all of them back to the user for this example.
```cs
public async Task MyMenuHandler(SocketMessageComponent arg)
{
var text = string.Join(", ", arg.Data.Values);
await arg.RespondAsync($"You have selected {text}");
[Autocompleters] provide a similar pattern to TypeConverters.
[Autocompleters] are cached, singleton services and they are used by the
Interaction Service to handle Autocomplete Interations targeted to a specific Slash Command parameter.
To start using AutocompleteHandlers, use the `[AutocompleteAttribute(Type type)]` overload of the [AutocompleteAttribute].
This will dynamically link the parameter to the [AutocompleteHandler] type.
AutocompleteHandlers raise the `AutocompleteHandlerExecuted` event on execution. This event can be also used to create a post-execution logic, just like the `*CommandExecuted` events.
## Creating AutocompleteHandlers
A valid AutocompleteHandlers must inherit [AutocompleteHandler] base type and implement all of its abstract methods.
### GenerateSuggestionsAsync()
The Interactions Service uses this method to generate a response of an Autocomplete Interaction.
This method should return `AutocompletionResult.FromSuccess(IEnumerable<AutocompleteResult>)` to
display parameter suggestions to the user. If there are no suggestions to be presented to the user, you have two results:
1. Returning the parameterless `AutocompletionResult.FromSuccess()` will display a "No options match your search." message to the user.
2. Returning `AutocompleteResult.FromError()` will make the Interaction Service **not** respond to the interaction,
consequently displaying the user a "Loading options failed." message. `AutocompletionResult.FromError()` is solely used for error handling purposes. Discord currently doesn't allow
you to display custom error messages. This result type will be directly returned to the `AutocompleteHandlerExecuted` method.
## Resolving AutocompleteHandler Dependencies
AutocompleteHandler dependencies are resolved using the same dependency injection
pattern as the Interaction Modules.
Property injection and constructor injection are both valid ways to get service dependencies.
Because [AutocompleterHandlers] are constructed at service startup,
class dependencies are resolved only once.
> [!NOTE]
> If you need to access per-request dependencies you can use the
> IServiceProvider parameter of the `GenerateSuggestionsAsync()` method.
[InteractionService] also features a pascal casing seperator for formatting parameter names with
pascal casing into Discord compliant parameter names('parameterName' => 'parameter-name').
By default, your methods can feature the following parameter types:
- Implementations of [IUser]
- Implementations of [IChannel]
- Implementations of [IRole]
- Implementations of [IMentionable]
- `string`
- `float`, `double`, `decimal`
- `bool`
- `char`
- `sbyte`, `byte`
- `int16`, `int32`, `int64`
- `uint16`, `uint32`, `uint64`
- `enum` (Values are registered as multiple choice options and are enforced by Discord. Use `[HideAttribute]` on enum values to prevent them from getting registered.)
- `DateTime`
- `TimeSpan`
---
**You can use more specialized implementations of [IChannel] to restrict the allowed channel types for a channel type option.*
Alternatively, you can use the [AutocompleteHandlers] to simplify this workflow.
## Interaction Context
Every command module provides its commands with an execution context.
This context property includes general information about the underlying interaction that triggered the command execution.
The base command context.
You can design your modules to work with different implementation types of [IInteractionContext].
To achieve this, make sure your module classes inherit from the generic variant of the [InteractionModuleBase].
> [!NOTE]
> Context type must be consistent throughout the project, or you will run into issues during runtime.
The [InteractionService] ships with 4 different kinds of [InteractionContext]:
1. [InteractionContext]]: A bare-bones execution context consisting of only implementation neutral interfaces
2. [SocketInteractionContext]: An execution context for use with [DiscordSocketClient]. Socket entities are exposed in this context without the need of casting them.
3. [ShardedInteractionContext]: [DiscordShardedClient] variant of the [SocketInteractionContext]
4. [RestInteractionContext]: An execution context designed to be used with a [DiscordRestClient] and webhook based interactions pattern
You can create custom Interaction Contexts by implementing the [IInteractionContext] interface.
One problem with using the concrete type InteractionContexts is that you cannot access the information that is specific to different interaction types without casting. Concrete type interaction contexts are great for creating shared interaction modules but you can also use the generic variants of the built-in interaction contexts to create interaction specific interaction modules.
> [!INFO]
> Message component interactions have access to a special method called `UpdateAsync()` to update the body of the method the interaction originated from.
> Normally this wouldn't be accessable without casting the `Context.Interaction`.
[InteractionService] can automatically discover and load modules that inherit [InteractionModuleBase] from an `Assembly`.
Call `InteractionService.AddModulesAsync()` to use this functionality.
> [!NOTE]
> You can also manually add Interaction modules using the `InteractionService.AddModuleAsync()`
> method by providing the module type you want to load.
## Resolving Module Dependencies
Module dependencies are resolved using the Constructor Injection and Property Injection patterns.
Meaning, the constructor parameters and public settable properties of a module will be assigned using the `IServiceProvider`.
For more information on dependency injection, read the [DependencyInjection] guides.
> [!NOTE]
> On every command execution, module dependencies are resolved using a new service scope which allows you to utilize scoped service instances, just like in Asp.Net.
> Including the precondition checks, every module method is executed using the same service scope and service scopes are disposed right after the `AfterExecute` method returns.
## Module Groups
Module groups allow you to create sub-commands and sub-commands groups.
By nesting commands inside a module that is tagged with [GroupAttribute] you can create prefixed commands.
> [!WARNING]
> Although creating nested module stuctures are allowed,
> you are not permitted to use more than 2 [GroupAttribute]'s in module hierarchy.
## Executing Commands
Any of the following socket events can be used to execute commands:
- [InteractionCreated]
- [ButtonExecuted]
- [SelectMenuExecuted]
- [AutocompleteExecuted]
- [UserCommandExecuted]
- [MessageCommandExecuted]
Commands can be either executed on the gateway thread or on a seperate thread from the thread pool. This behaviour can be configured by changing the *RunMode* property of `InteractionServiceConfig` or by setting the *runMode* parameter of a command attribute.
You can also configure the way [InteractionService] executes the commands.
By default, commands are executed using `ConstructorInfo.Invoke()` to create module instances and
`MethodInfo.Invoke()` method for executing the method bodies.
By setting, `InteractionServiceConfig.UseCompiledLambda` to `true`, you can make [InteractionService] create module instances and execute commands using
*Compiled Lambda* expressions. This cuts down on command execution time but it might add some memory overhead.
Time it takes to create a module instance and execute a `Task.Delay(0)` method using the Reflection methods compared to Compiled Lambda expressions:
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.