Browse Source

Docs rework, prep for merge into DNET (#359)

* Appending previous changes

* Deprecating unique feature listing & unused branch

* Getting rid of old faq

* Add all missed changelog entries

This was painful :'')

* Appending suggestions, large interior rework

* Deleting unused entries

* Removing more unused entries

* Recover accidental deletion & append docfx file

* Resolve a few docfx errors

* Resolving more docfx errors

* Clearing up final warnings

* Appending suggestions

* Removing main nightly for dnetlabs

* Discord link updates

* Add migration guide

* Update v2_to_v3_guide.md

* Fix spelling mistake

Co-authored-by: quin lynch <lynchquin@gmail.com>
pull/1966/head
Armano den Boef GitHub 3 years ago
parent
commit
ff515d33d8
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
100 changed files with 2072 additions and 871 deletions
  1. +160
    -0
      CHANGELOG.md
  2. +3
    -3
      CONTRIBUTING.md
  3. +0
    -50
      FAQ.md
  4. +0
    -29
      README.md
  5. +2
    -2
      docs/_overwrites/Commands/ICommandContext.Inclusion.md
  6. +5
    -6
      docs/docfx.json
  7. +123
    -0
      docs/faq/basics/basic-operations.md
  8. +96
    -0
      docs/faq/basics/client-basics.md
  9. +82
    -0
      docs/faq/basics/getting-started.md
  10. BIN
      docs/faq/basics/images/dev-mode.png
  11. BIN
      docs/faq/basics/images/mention-escape.png
  12. BIN
      docs/faq/basics/images/role-copy.png
  13. BIN
      docs/faq/basics/images/scope.png
  14. BIN
      docs/faq/basics/images/snowflake.png
  15. +84
    -0
      docs/faq/basics/interactions.md
  16. +15
    -0
      docs/faq/basics/samples/cast.cs
  17. +18
    -0
      docs/faq/basics/samples/emoji-others.cs
  18. +17
    -0
      docs/faq/basics/samples/emoji-self.cs
  19. +21
    -0
      docs/faq/basics/samples/registerint.cs
  20. +54
    -0
      docs/faq/commands/dependency-injection.md
  21. +147
    -0
      docs/faq/commands/general.md
  22. +52
    -0
      docs/faq/commands/interaction.md
  23. +28
    -0
      docs/faq/commands/samples/DI.cs
  24. +20
    -0
      docs/faq/commands/samples/Remainder.cs
  25. +29
    -0
      docs/faq/commands/samples/missing-dep.cs
  26. +7
    -0
      docs/faq/commands/samples/runmode-cmdattrib.cs
  27. +10
    -0
      docs/faq/commands/samples/runmode-cmdconfig.cs
  28. +122
    -0
      docs/faq/misc/glossary.md
  29. +29
    -0
      docs/faq/misc/legacy.md
  30. +22
    -0
      docs/faq/toc.yml
  31. +1
    -1
      docs/guides/concepts/entities.md
  32. BIN
      docs/guides/getting_started/images/nightlies-vs-note.png
  33. BIN
      docs/guides/getting_started/images/nightlies-vs-step1.png
  34. BIN
      docs/guides/getting_started/images/nightlies-vs-step2.png
  35. BIN
      docs/guides/getting_started/images/nightlies-vs-step4.png
  36. +9
    -8
      docs/guides/getting_started/installing.md
  37. +30
    -0
      docs/guides/getting_started/labs.md
  38. +0
    -97
      docs/guides/getting_started/nightlies.md
  39. +10
    -5
      docs/guides/int_basics/application-commands/context-menu-commands/creating-context-menu-commands.md
  40. +0
    -0
      docs/guides/int_basics/application-commands/context-menu-commands/receiving-context-menu-command-events.md
  41. +51
    -0
      docs/guides/int_basics/application-commands/intro.md
  42. +0
    -0
      docs/guides/int_basics/application-commands/slash-commands/bulk-overwrite-of-global-slash-commands.md
  43. +0
    -0
      docs/guides/int_basics/application-commands/slash-commands/choice-slash-command.md
  44. +0
    -0
      docs/guides/int_basics/application-commands/slash-commands/creating-slash-commands.md
  45. +0
    -0
      docs/guides/int_basics/application-commands/slash-commands/images/ephemeral1.png
  46. +0
    -0
      docs/guides/int_basics/application-commands/slash-commands/images/feedback1.png
  47. +0
    -0
      docs/guides/int_basics/application-commands/slash-commands/images/feedback2.png
  48. +0
    -0
      docs/guides/int_basics/application-commands/slash-commands/images/listroles1.png
  49. +0
    -0
      docs/guides/int_basics/application-commands/slash-commands/images/listroles2.png
  50. +0
    -0
      docs/guides/int_basics/application-commands/slash-commands/images/oauth.png
  51. +0
    -0
      docs/guides/int_basics/application-commands/slash-commands/images/settings1.png
  52. +0
    -0
      docs/guides/int_basics/application-commands/slash-commands/images/settings2.png
  53. +0
    -0
      docs/guides/int_basics/application-commands/slash-commands/images/settings3.png
  54. +0
    -0
      docs/guides/int_basics/application-commands/slash-commands/images/slashcommand1.png
  55. +0
    -0
      docs/guides/int_basics/application-commands/slash-commands/images/slashcommand2.png
  56. +0
    -0
      docs/guides/int_basics/application-commands/slash-commands/parameters.md
  57. +0
    -0
      docs/guides/int_basics/application-commands/slash-commands/responding-ephemerally.md
  58. +0
    -0
      docs/guides/int_basics/application-commands/slash-commands/responding-to-slash-commands.md
  59. +0
    -0
      docs/guides/int_basics/application-commands/slash-commands/subcommands.md
  60. +0
    -0
      docs/guides/int_basics/intro.md
  61. +0
    -0
      docs/guides/int_basics/message-components/advanced.md
  62. +0
    -0
      docs/guides/int_basics/message-components/buttons-in-depth.md
  63. +0
    -0
      docs/guides/int_basics/message-components/images/image1.png
  64. +0
    -0
      docs/guides/int_basics/message-components/images/image2.png
  65. +0
    -0
      docs/guides/int_basics/message-components/images/image3.png
  66. +0
    -0
      docs/guides/int_basics/message-components/images/image4.png
  67. +0
    -0
      docs/guides/int_basics/message-components/images/image5.png
  68. +0
    -0
      docs/guides/int_basics/message-components/images/image6.png
  69. +1
    -1
      docs/guides/int_basics/message-components/intro.md
  70. +0
    -0
      docs/guides/int_basics/message-components/responding-to-buttons.md
  71. +0
    -0
      docs/guides/int_basics/message-components/select-menus.md
  72. +47
    -0
      docs/guides/int_framework/autocompletion.md
  73. +13
    -0
      docs/guides/int_framework/dependency-injection.md
  74. +353
    -0
      docs/guides/int_framework/intro.md
  75. +69
    -0
      docs/guides/int_framework/post-execution.md
  76. +77
    -0
      docs/guides/int_framework/preconditions.md
  77. +9
    -0
      docs/guides/int_framework/samples/intro/autocomplete.cs
  78. +5
    -0
      docs/guides/int_framework/samples/intro/button.cs
  79. +5
    -0
      docs/guides/int_framework/samples/intro/channelattribute.cs
  80. +14
    -0
      docs/guides/int_framework/samples/intro/context.cs
  81. +11
    -0
      docs/guides/int_framework/samples/intro/dropdown.cs
  82. +21
    -0
      docs/guides/int_framework/samples/intro/groupattribute.cs
  83. +5
    -0
      docs/guides/int_framework/samples/intro/messagecommand.cs
  84. +5
    -0
      docs/guides/int_framework/samples/intro/registering.cs
  85. +5
    -0
      docs/guides/int_framework/samples/intro/slashcommand.cs
  86. +1
    -0
      docs/guides/int_framework/samples/intro/summaryattribute.cs
  87. +5
    -0
      docs/guides/int_framework/samples/intro/usercommand.cs
  88. +28
    -0
      docs/guides/int_framework/samples/postexecution/error_review.cs
  89. +0
    -0
      docs/guides/int_framework/samples/preconditions/group_precondition.cs
  90. +3
    -0
      docs/guides/int_framework/samples/preconditions/precondition_usage.cs
  91. +30
    -0
      docs/guides/int_framework/samples/typeconverters/enum_converter.cs
  92. +118
    -0
      docs/guides/int_framework/typeconverters.md
  93. +0
    -32
      docs/guides/interactions/application-commands/01-getting-started.md
  94. +0
    -12
      docs/guides/interactions/application-commands/slash-commands/README.md
  95. +0
    -27
      docs/guides/interactions_framework/autocompleters.md
  96. +0
    -27
      docs/guides/interactions_framework/dependency-injection.md
  97. +0
    -360
      docs/guides/interactions_framework/intro.md
  98. +0
    -73
      docs/guides/interactions_framework/post_execution.md
  99. +0
    -8
      docs/guides/interactions_framework/preconditions.md
  100. +0
    -130
      docs/guides/interactions_framework/typeconverters.md

+ 160
- 0
CHANGELOG.md View File

@@ -1,5 +1,165 @@
# Changelog

## [3.4.9] - 12/06/2021

### Fixed

- NRE when responding to an interaction with just an embed

## [3.4.8] - 12/04/2021

### Added

- Check for creating threads in news channels.
- Back netstandard2.0 and netstandard2.1 builds.
- IApplicationCommandInteraction interface and make IUserCommandInteraction, IMessageCommandInteraction, and ISlashCommandInteraction inherit it.
- FollowupWithFilesAsync to interactions to allow uploading multiple attachments.
- IUser User to IDiscordInteraction.

### Fixed

- NRE on modifying messages allowed mentions again.

### Misc

- Deprecate ApplicationCommandException in favor for HttpException.
- Made RespondAsync return a RestInteractionMessage based off of the parameters sent over to discord. This allows direct calls to ModifyAsync and DeleteAsync without having to get the interaction response first.
- Change Followup / Respond method signatures to move RequestOptions to the last parameter as well as change component to components.
- Update async summaries to contain information about the task in the return tag.

## [3.4.7] - 28/11/2021

### Added

- Methods for manually registering global comands.

### Fixed

- NRE on service providerless command execution.
- Wrong link in interactions framework docs.

## [3.4.6] - 27/11/2021

### Fixed

- Self user presence throwing upon set.

## [3.4.5] - 27/11/2021

### Fixed

- Another NRE with presence.

## [3.4.4] - 27/11/2021

### Fixed

- NRE with presence causing guild members to basically not exist.

## [3.4.3] - 27/11/2021

### Added

- PresenceUpdate socket event to help alleviate GuildMemberUpdate event calls.
- Guild.ClearUserCache(Predicate) to socket guilds.
- Warnings to the gateway client about intents, you can disable them by setting LogGatewayIntentWarnings to false in the discord socket config.
- DefaultApplications enum with the default games in the discord games lab.
- Support for sending multiple files on Webhooks.
- MaxBitrate to the IGuild interface.

### Fixed

- Bi-directional unicode names getting formatted wrong when calling IUser.ToString().
- CurrentUser with ICommandContext on DiscordShardedClient being null.
- NRE on Emote.TryParse.

## [3.4.2] - 26/11/2021

### Fixed

- Improve the GuildFeatures converter.
- Message/User commands are not being executed when their name have spaces on it.

## [3.4.1] - 26/11/2021

### Fixed

- SocketVoiceChannel options are created as generic mentionables in Interaction service

## [3.4.0] - 26/11/2021

### Added

- Interaction Service framework.

### Fixed

- NRE when modifying allowed mentions.

### Misc

- Updated summaries of interaction related classes.

## [3.3.3] - 11/23/2021

### Added

- Emoji to roles
- Invitable and Slowmode to thread creation
- Better discord errors.
- UseInteractionSnowflakeDate to config.

### Fixed

- Components not showing on FollowUpWithFile.
- Change the minimum length of slash commands to 1.
- Ratelimit timings.

### Misc

- Make RestUserCommand public.

## [3.3.2] - 11/21/2021

### Added

- GuildScheduledEventUserAdd and GuildScheduledEventUserRemove.
- New Cacheable<> type for rest based downloads while maintaining strong typed entities.

### Fixed

- Autocomplete not accepting values

## [3.3.1] - 11/21/2021

### Added

- ConfigureAwait(false) to async calls in rest based interactions.

### Fixed

- Slash commands will now have populated data.

## [3.3.0] - 11/19/2021

### Added

- Guild events.
- Rest-based http interactions.
- RTCRegion to voice channel properties.
- Support Min and Max values on ApplicationCommandOptions.
- Automatically fix ordering of optional command options.
- Interaction Specific Interfaces.

### Fixed

- Maximum number of Select Menu Options.

### Misc

- Changed default sticker behavior. You can configure getting default stickers on startup and auto resolve stickers with AlwaysDownloadDefaultStickers and AlwaysResolveStickers.
- Logomark, doc settings edit.

## [3.2.0] - 11/09/2021

### Added


+ 3
- 3
CONTRIBUTING.md View File

@@ -17,7 +17,7 @@ any member of the community.

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)

+ 0
- 50
FAQ.md View File

@@ -1,50 +0,0 @@
# Frequently Asked Questions

#### Whats the difference between DNet and DNet Labs?
DNet Labs is mostly the same as DNet as it just adds additional features. Discord.NET-labs adds several features Discord.NET does not. Examples of this are: Threads, application commands, message components, stage channels, role icons & more small functionality changes. More details [here](https://github.com/discord-net/Discord.Net/pull/1923).

#### Should I use DNet Labs instead of DNet? or can I use both at the same time?
DNet Labs implements new experimental/unstable features and generally shouldn't be used in production environments. You should only use it if you want to test out new Discord features. As DNet Labs builds on top of DNet, you can not use both at the same time, however DNet Labs should be a pretty straight forward drop-in replacement for DNet.

#### Why is x not doing y when it should?
Double check you are on the most recent version of Discord .Net labs, if you are and it looks like an issue, report it on [Discord](https://discord.com/invite/dnet-labs) or create an issue on [GitHub](https://github.com/Discord-Net-Labs/Discord.Net-Labs)

#### When is feature x going to be added?
When someone adds it. If a new Discord feature is currently untouched, submit an issue on [GitHub](https://github.com/Discord-Net-Labs/Discord.Net-Labs) regarding the request.

#### What's the difference between RespondAsync, DeferAsync and FollowupAsync?
The difference between these 3 functions is in how you handle the command response. [RespondAsync](https://discord-net-labs.com/api/Discord.WebSocket.SocketCommandBase.html#Discord_WebSocket_SocketCommandBase_DeferAsync_System_Boolean_Discord_RequestOptions_) and [DeferAsync](https://discord-net-labs.com/api/Discord.WebSocket.SocketCommandBase.html#Discord_WebSocket_SocketCommandBase_DeferAsync_System_Boolean_Discord_RequestOptions_) 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 not. [FollowupAsync](https://discord-net-labs.com/api/Discord.WebSocket.SocketCommandBase.html#Discord_WebSocket_SocketCommandBase_DeferAsync_System_Boolean_Discord_RequestOptions_) follows up on succesful acknowledgement.

> [!WARNING]
> If you have not acknowledged the command FollowupAsync will not work.

#### What's the difference between global commands and guild commands? (Why isn't my command show up in discord?)
Global commands can be used in every guild your bot is in. However, it can take up to an hour for every guild to have access to the commands.
Guild commands can only be used in specific guilds. They are available within a few minutes. (This is great for testing purposes).

#### I'm getting a 50001: Missing access error while trying to create a guild command!
Guild commands require you give grant the bot the applications.commands OAuth2 scope in order to register guild commands in that guild. You can register global commands without this OAuth2 scope but will need it to use global commands in that guild.

#### I'm getting errors when trying to create a slash command (The application command failed to be created, 400 bad request, 50035: Invalid Form Body, etc)
This could be caused by several things but the most common one is an invalid "Name" for the command or any of the options/arguments for the command. Make sure your "Name" is all lowercase and only contains letters or dashes. It should also be less than 32 characters. If you are still having issues after checking this, read up on the other slash commands limits [here](https://discord.com/developers/docs/interactions/slash-commands#a-quick-note-on-limits).

> [!NOTE]
> In most cases, you can catch an [ApplicationCommandException](https://discord-net-labs.com/api/Discord.Net.ApplicationCommandException.html?q=applicationcommandexception) error from creation.
> This exception will tell you what part of your command is invalid as well as why.

#### How can I use Victoria with Labs?
You can add a special build of victoria that supports labs by adding the below to your references:
```xml
<PropertyGroup>
<RestoreAdditionalProjectSources>https://www.myget.org/F/yucked/api/v3/index.json</RestoreAdditionalProjectSources>
</PropertyGroup>
```

#### I'm getting a 10062 exception: Unknown Interaction. What can I do?
This exception happens when an app tries to send an initial response to an interaction twice. This can be caused by:
- 2 instances of your app running at once.
- Responding 3+ seconds after the interaction was received.
If you're positive that your app doesn't do this and you are still receiving the exception, please submit an issue.

#### Why is BannerId/AccentColour always null?
Currently SocketUser/SocketGuildUser does not expose the [BannerId](https://discord-net-labs.com/api/Discord.IUser.html#Discord_IUser_BannerId) nor [AccentColor](https://discord-net-labs.com/api/Discord.IUser.html#Discord_IUser_AccentColor). To get this info, a [RestUser](https://discord-net-labs.com/api/Discord.Rest.RestUser.html?q=RestUser) must be requested.

+ 0
- 29
README.md View File

@@ -50,32 +50,6 @@ Setting up labs in your project is really simple, here's how to do it:
2) Add Discord.Net Labs nuget to your project
3) That's all!

## Implementations
What Discord.NET-labs has that Discord.NET does not:

- Major changes
* Interaction Support.
* Application commands (slash, user, message).
* Message Components (buttons, select menus).
* Thread Channels.
* Stage Channels.
* Guild Events.
* Revamped Stickers.

- Minor changes
* Added `TimestampTag`.
* Made `Hierarchy` a `IGuildUser` property.
* Changes embed discription length to 4096.
* Added `Name` property to teams.
* Added url validation to embeds.
* Added `NsfwLevel` to Guilds.
* Added helpers to `Emoji` for parsing.
* Fixed gateway serialization to include nulls.
* Added banner and accent color to guild users.
* Fixed `CurrentUserId` in sharded clients being null.
* Fixed Guild owner and Admin `GuildPermissions.All`.
* Added `RatelimitCallback` to `RequestOptions`.

## Branches

### Dev
@@ -84,8 +58,5 @@ This branch is kept up to date with dnets dev branch. we pull of it to ensure th
### release/3.x
This branch is what will be pushed to nuget, sometimes its not up to date as we wait for other features to be finished.

### old/SlashCommandService
This branch is on pause and does not work currently, There is a pull request open to implement a working version of a slash command service. It can be found [here](https://github.com/Discord-Net-Labs/Discord.Net-Labs/pull/52)

### feature/xyz
These branches are features for new things, you are more than welcome to clone them and give feedback in the discord server or issues tab.

+ 2
- 2
docs/_overwrites/Commands/ICommandContext.Inclusion.md View File

@@ -1,5 +1,5 @@
An example of how this class is used the command system can be seen
below:

[!code[Sample module](../../guides/commands/samples/intro/empty-module.cs)]
[!code[Command handler](../../guides/commands/samples/intro/command_handler.cs)]
[!code[Sample module](../../guides/text_commands/samples/intro/empty-module.cs)]
[!code[Command handler](../../guides/text_commands/samples/intro/command_handler.cs)]

+ 5
- 6
docs/docfx.json View File

@@ -17,21 +17,20 @@
"build": {
"content": [
{
"files": ["api/**.yml", "api/index.md"]
"files": [ "api/**.yml", "api/index.md" ]
},
{
"files": ["toc.yml", "index.md"]
"files": [ "toc.yml", "index.md" ]
},
{
"src": "../",
"files": ["FAQ.md"]
"files": [ "faq/**.md", "faq/**/toc.yml" ]
},
{
"files": ["guides/**.md", "guides/**/toc.yml"]
"files": [ "guides/**.md", "guides/**/toc.yml" ]
},
{
"src": "../",
"files": ["CHANGELOG.md"]
"files": [ "CHANGELOG.md" ]
}
],
"resource": [


+ 123
- 0
docs/faq/basics/basic-operations.md View File

@@ -0,0 +1,123 @@
---
uid: FAQ.Basics.BasicOp
title: Questions about Basic Operations
---

# Basic Operations Questions

In the following section, you will find commonly asked questions and
answers regarding basic usage of the library, as well as
language-specific tips when using this library.

## How should I safely check a type?

> [!WARNING]
> Direct casting (e.g., `(Type)type`) is **the least recommended**
> way of casting, as it *can* throw an [InvalidCastException]
> when the object isn't the desired type.
>
> Please refer to [this post] for more details.

In Discord.Net, the idea of polymorphism is used throughout. You may
need to cast the object as a certain type before you can perform any
action.

A good and safe casting example:

[!code-csharp[Casting](samples/cast.cs)]

[InvalidCastException]: https://docs.microsoft.com/en-us/dotnet/api/system.invalidcastexception
[this post]: https://docs.microsoft.com/en-us/dotnet/csharp/how-to/safely-cast-using-pattern-matching-is-and-as-operators

## How do I send a message?

> [!TIP]
> The [GetChannel] method by default returns an [IChannel], allowing
> channel types such as [IVoiceChannel], [ICategoryChannel]
> to be returned; consequently, you cannot send a message
> to channels like those.

Any implementation of [IMessageChannel] has a [SendMessageAsync]
method. You can get the channel via [GetChannel] under the client.
Remember, when using Discord.Net, polymorphism is a common recurring
theme. This means an object may take in many shapes or form, which
means casting is your friend. You should attempt to cast the channel
as an [IMessageChannel] or any other entity that implements it to be
able to message.

[SendMessageAsync]: xref:Discord.IMessageChannel.SendMessageAsync*
[GetChannel]: xref:Discord.WebSocket.DiscordSocketClient.GetChannel*

## How can I tell if a message is from X, Y, Z channel?

You may check the message channel type. Visit [Glossary] to see the
various types of channels.

[Glossary]: xref:FAQ.Glossary#message-channels

## How can I get the guild from a message?

There are 2 ways to do this. You can do either of the following,

1. Cast the user as an [IGuildUser] and use its [IGuild] property.
2. Cast the channel as an [IGuildChannel] and use its [IGuild] property.

## How do I add hyperlink text to an embed?

Embeds can use standard [markdown] in the description field as well
as in field values. With that in mind, links can be added with
`[text](link)`.

[markdown]: https://support.discordapp.com/hc/en-us/articles/210298617-Markdown-Text-101-Chat-Formatting-Bold-Italic-Underline-

## How do I add reactions to a message?

Any entity that implements [IUserMessage] has an [AddReactionAsync]
method. This method expects an [IEmote] as a parameter.
In Discord.Net, an Emote represents a custom-image emote, while an
Emoji is a Unicode emoji (standard emoji). Both [Emoji] and [Emote]
implement [IEmote] and are valid options.

# [Adding a reaction to another message](#tab/emoji-others)

[!code-csharp[Emoji](samples/emoji-others.cs)]

# [Adding a reaction to a sent message](#tab/emoji-self)

[!code-csharp[Emoji](samples/emoji-self.cs)]

***

[AddReactionAsync]: xref:Discord.IMessage.AddReactionAsync*

## What is a "preemptive rate limit?"

A preemptive rate limit is Discord.Net's way of telling you to slow
down before you get hit by the real rate limit. Hitting a real rate
limit might prevent your entire client from sending any requests for
a period of time. This is calculated based on the HTTP header
returned by a Discord response.

## Why am I getting so many preemptive rate limits when I try to add more than one reactions?

This is due to how HTML header works, mistreating
0.25sec/action to 1sec. This causes the lib to throw preemptive rate
limit more frequently than it should for methods such as adding
reactions.

## Can I opt-out of preemptive rate limits?

Unfortunately, not at the moment. See [#401](https://github.com/discord-net/Discord.Net/issues/401).

[IChannel]: xref:Discord.IChannel
[ICategoryChannel]: xref:Discord.ICategoryChannel
[IGuildChannel]: xref:Discord.IGuildChannel
[ITextChannel]: xref:Discord.ITextChannel
[IGuild]: xref:Discord.IGuild
[IVoiceChannel]: xref:Discord.IVoiceChannel
[IGuildUser]: xref:Discord.IGuildUser
[IMessageChannel]: xref:Discord.IMessageChannel
[IUserMessage]: xref:Discord.IUserMessage
[IEmote]: xref:Discord.IEmote
[Emote]: xref:Discord.Emote
[Emoji]: xref:Discord.Emoji

+ 96
- 0
docs/faq/basics/client-basics.md View File

@@ -0,0 +1,96 @@
---
uid: FAQ.Basics.ClientBasics
title: Basic Questions about Client
---

# Client Basics Questions

In the following section, you will find commonly asked questions and
answers about common issues that you may face when utilizing the
various clients offered by the library.

## My client keeps returning 401 upon logging in!

> [!WARNING]
> Userbot/selfbot (logging in with a user token) is no
> longer supported with this library starting from 2.0, as
> logging in under a user account may result in account termination.
>
> For more information, see issue [827] & [958], as well as the official
> [Discord API Terms of Service].

There are few possible reasons why this may occur.

1. You are not using the appropriate [TokenType]. If you are using a
bot account created from the Discord Developer portal, you should
be using `TokenType.Bot`.
2. You are not using the correct login credentials. Please keep in
mind that a token is **different** from a *client secret*.

[TokenType]: xref:Discord.TokenType
[827]: https://github.com/discord-net/Discord.Net/issues/827
[958]: https://github.com/discord-net/Discord.Net/issues/958
[Discord API Terms of Service]: https://discord.com/developers/docs/legal

## How do I do X, Y, Z when my bot connects/logs on? Why do I get a `NullReferenceException` upon calling any client methods after connect?

Your bot should **not** attempt to interact in any way with
guilds/servers until the [Ready] event fires. When the bot
connects, it first has to download guild information from
Discord for you to get access to any server
information; the client is not ready at this point.

Technically, the [GuildAvailable] event fires once the data for a
particular guild has downloaded; however, it is best to wait for all
guilds to be downloaded. Once all downloads are complete, the [Ready]
event is triggered, then you can proceed to do whatever you like.

[Ready]: xref:Discord.WebSocket.DiscordSocketClient.Ready
[GuildAvailable]: xref:Discord.WebSocket.BaseSocketClient.GuildAvailable

## How do I get a message's previous content when that message is edited?

If you need to do anything with messages (e.g., checking Reactions,
checking the content of edited/deleted messages), you must set the
[MessageCacheSize] in your [DiscordSocketConfig] settings in order to
use the cached message entity. Read more about it [here](xref:Guides.Concepts.Events#cacheable).

1. Message Cache must be enabled.
2. Hook the MessageUpdated event. This event provides a *before* and
*after* object.
3. Only messages received *after* the bot comes online will be
available in the cache.

[MessageCacheSize]: xref:Discord.WebSocket.DiscordSocketConfig.MessageCacheSize
[DiscordSocketConfig]: xref:Discord.WebSocket.DiscordSocketConfig
[MessageUpdated]: xref:Discord.WebSocket.BaseSocketClient.MessageUpdated

## What is a shard/sharded client, and how is it different from the `DiscordSocketClient`?
As your bot grows in popularity, it is recommended that you should section your bot off into separate processes.
The [DiscordShardedClient] is essentially a class that allows you to easily create and manage multiple [DiscordSocketClient]
instances, with each one serving a different amount of guilds.

There are very few differences from the [DiscordSocketClient] class, and it is very straightforward
to modify your existing code to use a [DiscordShardedClient] when necessary.

1. You can specify the total amount of shards, or shard ids, via [DiscordShardedClient]'s constructors.
If the total shards are not specified then the library will get the recommended shard count via the
[Get Gateway Bot](https://discord.com/developers/docs/topics/gateway#get-gateway-bot) route.
2. The [Connected], [Disconnected], [Ready], and [LatencyUpdated] events
are replaced with [ShardConnected], [ShardDisconnected], [ShardReady], and [ShardLatencyUpdated].
3. Every event handler you apply/remove to the [DiscordShardedClient] is applied/removed to each shard.
If you wish to control a specific shard's events, you can access an individual shard through the `Shards` property.

If you do not wish to use the [DiscordShardedClient] and instead reuse the same [DiscordSocketClient] code and manually shard them,
you can do so by specifying the [ShardId] for the [DiscordSocketConfig] and pass that to the [DiscordSocketClient]'s constructor.

[DiscordSocketClient]: xref:Discord.WebSocket.DiscordSocketClient
[DiscordShardedClient]: xref:Discord.WebSocket.DiscordShardedClient
[Connected]: xref:Discord.WebSocket.DiscordSocketClient.Connected
[Disconnected]: xref:Discord.WebSocket.DiscordSocketClient.Disconnected
[LatencyUpdated]: xref:Discord.WebSocket.DiscordSocketClient.LatencyUpdated
[ShardConnected]: xref:Discord.WebSocket.DiscordShardedClient.ShardConnected
[ShardDisconnected]: xref:Discord.WebSocket.DiscordShardedClient.ShardDisconnected
[ShardReady]: xref:Discord.WebSocket.DiscordShardedClient.ShardReady
[ShardLatencyUpdated]: xref:Discord.WebSocket.DiscordShardedClient.ShardLatencyUpdated
[ShardId]: xref:Discord.WebSocket.DiscordSocketConfig.ShardId

+ 82
- 0
docs/faq/basics/getting-started.md View File

@@ -0,0 +1,82 @@
---
uid: FAQ.Basics.GetStarted
title: Beginner Questions / How to Get Started
---

# Basic Concepts / Getting Started

In this following section, you will find commonly asked questions and
answers about how to get started with Discord.Net, as well as basic
introduction to the Discord API ecosystem.

## How do I add my bot to my server/guild?

You can do so by using the [permission calculator] provided
by [FiniteReality].
This tool allows you to set permissions that the bot will be assigned
with, and invite the bot into your guild. With this method, bots will
also be assigned a unique role that a regular user cannot use; this
is what we call a `Managed` role. Because you cannot assign this
role to any other users, it is much safer than creating a single
role which, intentionally or not, can be applied to other users
to escalate their privilege.

[FiniteReality]: https://github.com/FiniteReality/permissions-calculator
[permission calculator]: https://finitereality.github.io/permissions-calculator

## What is a token?

A token is a credential used to log into an account. This information
should be kept **private** and for your eyes only. Anyone with your
token can log into your account. This risk applies to both user
and bot accounts. That also means that you should **never** hardcode
your token or add it into source control, as your identity may be
stolen by scrape bots on the internet that scours through
constantly to obtain a token.

## What is a client/user/object ID?

Each user and object on Discord has its own snowflake ID generated
based on various conditions.

![Snowflake Generation](images/snowflake.png)

Anyone can see the ID; it is public. It is merely used to
identify an object in the Discord ecosystem. Many things in the
Discord ecosystem require an ID to retrieve or identify the said
object.

There are 2 common ways to obtain the said ID.

### [Discord Developer Mode](#tab/dev-mode)

By enabling the developer mode you can right click on most objects
to obtain their snowflake IDs (please note that this may not apply to
all objects, such as role IDs, or DM channel IDs).

![Developer Mode](images/dev-mode.png)

### [Escape Character](#tab/escape-char)

You can escape an object by using `\` in front the object in the
Discord client. For example, when you do `\@Example#1234` in chat,
it will return the user ID of the aforementioned user.

![Escaping mentions](images/mention-escape.png)

***

## How do I get the role ID?

> [!WARNING]
> Right-clicking on the role and copying the ID will **not** work.
> This will only copy the message ID.

Several common ways to do this:

1. (Easiest) Right click on the role either in the Server Settings
or in the user's role list.
![Roles](images/role-copy.png)
2. Make the role mentionable and mention the role, and escape it
using the `\` character in front.
3. Inspect the roles collection within the guild via your debugger.

BIN
docs/faq/basics/images/dev-mode.png View File

Before After
Width: 1366  |  Height: 727  |  Size: 79 KiB

BIN
docs/faq/basics/images/mention-escape.png View File

Before After
Width: 1603  |  Height: 400  |  Size: 19 KiB

BIN
docs/faq/basics/images/role-copy.png View File

Before After
Width: 384  |  Height: 530  |  Size: 16 KiB

BIN
docs/faq/basics/images/scope.png View File

Before After
Width: 446  |  Height: 317  |  Size: 16 KiB

BIN
docs/faq/basics/images/snowflake.png View File

Before After
Width: 700  |  Height: 365  |  Size: 71 KiB

+ 84
- 0
docs/faq/basics/interactions.md View File

@@ -0,0 +1,84 @@
---
uid: FAQ.Basics.InteractionBasics
title: Basics of interactions, common practice
---

# Interactions basics, where to get started

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

## 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].

[Discord Developer Docs]: https://discord.com/developers/docs/interactions/application-commands#application-commands
[here]: https://discord.com/developers/docs/interactions/message-components#message-components

#### Is your subcommand branching correct?

Branching structure is covered properly here: xref:Guides.SlashCommands.SubCommand

## My interaction commands are not showing up?

If you registered your commands globally, it can take up to 1 hour for them to register.
Did you register a guild command (should be instant), or waited more than an hour and still don't have them show up?

- Try to check for any errors in the console, there is a good chance something might have been thrown.

- Register your commands after the Ready event in the client. The client is not configured to register commands before this moment.

- Check if no bad form exception is thrown; If so, refer to the above question.

- Do you have the application commands scope checked when adding your bot to guilds?

![Scope check](images/scope.png)

## There are many options for creating commands, which do I use?

[!code-csharp[Register examples](samples/registerint.cs)]

> [!NOTE]
> You can use bulkoverwrite even if there are no commands in guild, nor globally.
> The bulkoverwrite method disposes the old set of commands and replaces it with the new.

## Do I need to create commands on startup?

If you are registering your commands for the first time, it is required to create them once.
After this, commands will exist indefinitely until you overwrite them.
Overwriting is only required if you make changes to existing commands, or add new ones.

## I can't see all of my user/message commands, why?

Message and user commands have a limit of 5 per guild, and another 5 globally.
If you have more than 5 guild-only message commands being registered, no more than 5 will actually show up.
You can get up to 10 entries to show if you register 5 per guild, and another 5 globally.

+ 15
- 0
docs/faq/basics/samples/cast.cs View File

@@ -0,0 +1,15 @@
public async Task MessageReceivedHandler(SocketMessage msg)
{
// Option 1:
// Using the `as` keyword, which will return `null` if the object isn't the desired type.
var usermsg = msg as SocketUserMessage;
// We bail when the message isn't the desired type.
if (msg == null) return;
// Option 2:
// Using the `is` keyword to cast (C#7 or above only)
if (msg is SocketUserMessage usermsg)
{
// Do things
}
}

+ 18
- 0
docs/faq/basics/samples/emoji-others.cs View File

@@ -0,0 +1,18 @@
// bail if the message is not a user one (system messages cannot have reactions)
var usermsg = msg as IUserMessage;
if (usermsg == null) return;

// standard Unicode emojis
Emoji emoji = new Emoji("👍");
// or
// Emoji emoji = new Emoji("\uD83D\uDC4D");

// custom guild emotes
Emote emote = Emote.Parse("<:dotnet:232902710280716288>");
// using Emote.TryParse may be safer in regards to errors being thrown;
// please note that the method does not verify if the emote exists,
// it simply creates the Emote object for you.

// add the reaction to the message
await usermsg.AddReactionAsync(emoji);
await usermsg.AddReactionAsync(emote);

+ 17
- 0
docs/faq/basics/samples/emoji-self.cs View File

@@ -0,0 +1,17 @@
// capture the message you're sending in a variable
var msg = await channel.SendMessageAsync("This will have reactions added.");

// standard Unicode emojis
Emoji emoji = new Emoji("👍");
// or
// Emoji emoji = new Emoji("\uD83D\uDC4D");

// custom guild emotes
Emote emote = Emote.Parse("<:dotnet:232902710280716288>");
// using Emote.TryParse may be safer in regards to errors being thrown;
// please note that the method does not verify if the emote exists,
// it simply creates the Emote object for you.

// add the reaction to the message
await msg.AddReactionAsync(emoji);
await msg.AddReactionAsync(emote);

+ 21
- 0
docs/faq/basics/samples/registerint.cs View File

@@ -0,0 +1,21 @@
private async Task ReadyAsync()
{
// pull your commands from some array, everyone has a different approach for this.
var commands = _builders.ToArray();

// write your list of commands globally in one go.
await _client.Rest.BulkOverwriteGlobalCommands(commands);

// write your array of commands to one guild in one go.
// You can do a foreach (... in _client.Guilds) approach to write to all guilds.
await _client.Rest.BulkOverwriteGuildCommands(commands, /* some guild ID */);

foreach (var c in commands)
{
// Create a global command, repeating usage for multiple commands.
await _client.Rest.CreateGlobalCommand(c);

// Create a guild command, repeating usage for multiple commands.
await _client.Rest.CreateGuildCommand(c, guildId);
}
}

+ 54
- 0
docs/faq/commands/dependency-injection.md View File

@@ -0,0 +1,54 @@
---
uid: FAQ.Commands.DI
title: Questions about Dependency Injection with Commands
---

# Dependency-injection-related Questions

In the following section, you will find common questions and answers
to utilizing dependency injection with @Discord.Commands, as well as
common troubleshooting steps regarding DI.

## What is a service? Why does my module not hold any data after execution?

In Discord.Net, modules are created similarly to ASP.NET, meaning
that they have a transient nature; modules are spawned whenever a
request is received, and are killed from memory when the execution
finishes. In other words, you cannot store persistent
data inside a module. Consider using a service if you wish to
workaround this.

Service is often used to hold data externally so that they persist
throughout execution. Think of it like a chest that holds
whatever you throw at it that won't be affected by anything unless
you want it to. Note that you should also learn Microsoft's
implementation of [Dependency Injection] \([video]) before proceeding,
as well as how it works in [Discord.Net](xref:Guides.TextCommands.DI#usage-in-modules).

A brief example of service and dependency injection can be seen below.

[!code-csharp[DI](samples/DI.cs)]

[Dependency Injection]: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection
[video]: https://www.youtube.com/watch?v=QtDTfn8YxXg

## Why is my `CommandService` complaining about a missing dependency?

If you encounter an error similar to `Failed to create MyModule,
dependency MyExternalDependency was not found.`, you may have
forgotten to add the external dependency to the dependency container.

Starting from Discord.Net 2.0, all dependencies required by each
module must be present when the module is loaded into the
[CommandService]. This means when loading the module, you must pass a
valid [IServiceProvider] with the dependency loaded before the module
can be successfully registered.

For example, if your module, `MyModule`, requests a `DatabaseService`
in its constructor, the `DatabaseService` must be present in the
[IServiceProvider] when registering `MyModule`.

[!code-csharp[Missing Dependencies](samples/missing-dep.cs)]

[IServiceProvider]: xref:System.IServiceProvider
[CommandService]: xref:Discord.Commands.CommandService

+ 147
- 0
docs/faq/commands/general.md View File

@@ -0,0 +1,147 @@
---
uid: FAQ.Commands.General
title: General Questions about chat Commands
---

# Chat Command-related Questions

In the following section, you will find commonly asked questions and
answered regarding general command usage when using @Discord.Commands.

## How can I restrict some of my commands so only specific users can execute them?

Based on how you want to implement the restrictions, you can use the
built-in [RequireUserPermission] precondition, which allows you to
restrict the command based on the user's current permissions in the
guild or channel (*e.g., `GuildPermission.Administrator`,
`ChannelPermission.ManageMessages`*).

If, however, you wish to restrict the commands based on the user's
role, you can either create your custom precondition or use
Joe4evr's [Preconditions Addons] that provides a few custom
preconditions that aren't provided in the stock library.
Its source can also be used as an example for creating your
custom preconditions.

[RequireUserPermission]: xref:Discord.Commands.RequireUserPermissionAttribute
[Preconditions Addons]: https://github.com/Joe4evr/Discord.Addons/tree/master/src/Discord.Addons.Preconditions

## Why am I getting an error about `Assembly.GetEntryAssembly`?

You may be confusing @Discord.Commands.CommandService.AddModulesAsync*
with @Discord.Commands.CommandService.AddModuleAsync*. The former
is used to add modules via the assembly, while the latter is used to
add a single module.

## What does [Remainder] do in the command signature?

The [RemainderAttribute] leaves the string unparsed, meaning you
do not have to add quotes around the text for the text to be
recognized as a single object. Please note that if your method has
multiple parameters, the remainder attribute can only be applied to
the last parameter.

[!code-csharp[Remainder](samples/Remainder.cs)]

[RemainderAttribute]: xref:Discord.Commands.RemainderAttribute

## Discord.Net keeps saying that a `MessageReceived` handler is blocking the gateway, what should I do?

By default, the library warns the user about any long-running event
handler that persists for **more than 3 seconds**. Any event
handlers that are run on the same thread as the gateway task, the task
in charge of keeping the connection alive, may block the processing of
heartbeat, and thus terminating the connection.

In this case, the library detects that a `MessageReceived`
event handler is blocking the gateway thread. This warning is
typically associated with the command handler as it listens for that
particular event. If the command handler is blocking the thread, then
this **might** mean that you have a long-running command.

> [!NOTE]
> In rare cases, runtime errors can also cause blockage, usually
> associated with Mono, which is not supported by this library.

To prevent a long-running command from blocking the gateway
thread, a flag called [RunMode] is explicitly designed to resolve
this issue.

There are 2 main `RunMode`s.

1. `RunMode.Sync`
2. `RunMode.Async`

`Sync` is the default behavior and makes the command to be run on the
same thread as the gateway one. `Async` will spin the task off to a
different thread from the gateway one.

> [!IMPORTANT]
> While specifying `RunMode.Async` allows the command to be spun off
> to a different thread, keep in mind that by doing so, there will be
> **potentially unwanted consequences**. Before applying this flag,
> please consider whether it is necessary to do so.
>
> Further details regarding `RunMode.Async` can be found below.

You can set the `RunMode` either by specifying it individually via
the `CommandAttribute` or by setting the global default with
the [DefaultRunMode] flag under `CommandServiceConfig`.

# [CommandAttribute](#tab/cmdattrib)

[!code-csharp[Command Attribute](samples/runmode-cmdattrib.cs)]

# [CommandServiceConfig](#tab/cmdconfig)

[!code-csharp[Command Service Config](samples/runmode-cmdconfig.cs)]

***

***

[RunMode]: xref:Discord.Commands.RunMode
[CommandAttribute]: xref:Discord.Commands.CommandAttribute
[DefaultRunMode]: xref:Discord.Commands.CommandServiceConfig.DefaultRunMode

## How does `RunMode.Async` work, and why is Discord.Net *not* using it by default?

`RunMode.Async` works by spawning a new `Task` with an unawaited
[Task.Run], essentially making the task that is used to invoke the
command task to be finished on a different thread. This design means
that [ExecuteAsync] will be forced to return a successful
[ExecuteResult] regardless of the actual execution result.

The following are the known caveats with `RunMode.Async`,

1. You can potentially introduce a race condition.
2. Unnecessary overhead caused by the [async state machine].
3. [ExecuteAsync] will immediately return [ExecuteResult] instead of
other result types (this is particularly important for those who wish
to utilize [RuntimeResult] in 2.0).
4. Exceptions are swallowed in the `ExecuteAsync` result.

However, there are ways to remedy some of these.

For #3, in Discord.Net 2.0, the library introduces a new event called
[CommandService.CommandExecuted], which is raised whenever the command is executed.
This event will be raised regardless of
the `RunMode` type and will return the appropriate execution result
and the associated @Discord.Commands.CommandInfo if applicable.

For #4, exceptions are caught in [CommandService.Log] event under
[LogMessage.Exception] as [CommandException] and in the
[CommandService.CommandExecuted] event under the [IResult] as
[ExecuteResult.Exception].

[Task.Run]: https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.run
[async state machine]: https://www.red-gate.com/simple-talk/dotnet/net-tools/c-async-what-is-it-and-how-does-it-work/
[ExecuteAsync]: xref:Discord.Commands.CommandService.ExecuteAsync*
[ExecuteResult]: xref:Discord.Commands.ExecuteResult
[RuntimeResult]: xref:Discord.Commands.RuntimeResult
[CommandService.CommandExecuted]: xref:Discord.Commands.CommandService.CommandExecuted
[CommandService.Log]: xref:Discord.Commands.CommandService.Log
[LogMessage.Exception]: xref:Discord.LogMessage.Exception*
[ExecuteResult.Exception]: xref:Discord.Commands.ExecuteResult.Exception*
[CommandException]: xref:Discord.Commands.CommandException
[IResult]: xref:Discord.Commands.IResult

+ 52
- 0
docs/faq/commands/interaction.md View File

@@ -0,0 +1,52 @@
---
uid: FAQ.Commands.Interactions
title: Interaction service
---

# Interaction commands in services

A chapter talking about the interaction service framework.
For questions about interactions in general, refer to the [Interactions FAQ]

## Module dependencies aren't getting populated by Property Injection?

Make sure the properties are publicly accessible and publicly settable.

## How do I use this * interaction specific method/property?

If your interaction context holds a down-casted version of the interaction object, you need to up-cast it.
Ideally, use pattern matching to make sure its the type of interaction you are expecting it to be.

## `InteractionService.ExecuteAsync()` always returns a successful result, how do i access the failed command execution results?

If you are using `RunMode.Async` you need to setup your post-execution pipeline around `CommandExecuted` events.

## How do I check if the executing user has * permission?

Refer to the [documentation about preconditions]

## How do I send the HTTP Response from inside the command modules.

Set the `RestResponseCallback` property of [InteractionServiceConfig] with a delegate for handling HTTP Responses and use
`RestInteractionModuleBase` to create your command modules. `RespondAsync()` and `DeferAsync()` methods of this module base will use the
`RestResponseCallback` to create interaction responses.

## Is there a cleaner way of creating parameter choices other than using `[Choice]`?

The default `enum` [TypeConverter] of the Interaction Service will
automatically register `enum`s as multiple choice options.

## How do I add an optional `enum` parameter but make the default value not visible to the user?

The default `enum` [TypeConverter] of the Interaction Service comes with `[Hide]` attribute that
can be used to prevent certain enum values from getting registered.

## How does the InteractionService determine the generic TypeConverter to use for a parameter type?

It compares the _target base type_ key of the
[TypeConverter] and chooses the one that sits highest on the inheritance hierarchy.

[TypeConverter]: xref:Discord.Interactions.TypeConverter
[Interactions FAQ]: xref: FAQ.Basics.Interactions
[InteractionServiceConfig]: xref:Discord.Interactions.InteractionServiceConfig
[documentation about preconditions]: xref: Guides.ChatCommands.Preconditions

+ 28
- 0
docs/faq/commands/samples/DI.cs View File

@@ -0,0 +1,28 @@
public class MyService
{
public string MyCoolString { get; set; }
}
public class Setup
{
public IServiceProvider BuildProvider() =>
new ServiceCollection()
.AddSingleton<MyService>()
.BuildServiceProvider();
}
public class MyModule : ModuleBase<SocketCommandContext>
{
// Inject via public settable prop
public MyService MyService { get; set; }
// ...or via the module's constructor

// private readonly MyService _myService;
// public MyModule (MyService myService) => _myService = myService;
[Command("string")]
public Task GetOrSetStringAsync(string input)
{
if (string.IsNullOrEmpty(_myService.MyCoolString)) _myService.MyCoolString = input;
return ReplyAsync(_myService.MyCoolString);
}
}

+ 20
- 0
docs/faq/commands/samples/Remainder.cs View File

@@ -0,0 +1,20 @@
// Input:
// !echo Coffee Cake

// Output:
// Coffee Cake
[Command("echo")]
public Task EchoRemainderAsync([Remainder]string text) => ReplyAsync(text);

// Output:
// CommandError.BadArgCount
[Command("echo-hassle")]
public Task EchoAsync(string text) => ReplyAsync(text);

// The message would be seen as having multiple parameters,
// while the method only accepts one.
// Wrapping the message in quotes solves this.
// This way, the system knows the entire message is to be parsed as a
// single String.
// e.g.,
// !echo "Coffee Cake"

+ 29
- 0
docs/faq/commands/samples/missing-dep.cs View File

@@ -0,0 +1,29 @@
public class MyModule : ModuleBase<SocketCommandContext>
{
private readonly DatabaseService _dbService;
public MyModule(DatabaseService dbService)
=> _dbService = dbService;
}
public class CommandHandler
{
private readonly CommandService _commands;
private readonly IServiceProvider _services;
public CommandHandler(DiscordSocketClient client)
{
_services = new ServiceCollection()
.AddService<CommandService>()
.AddService(client)
// We are missing DatabaseService!
.BuildServiceProvider();
}
public async Task RegisterCommandsAsync()
{
// ...
// The method fails here because DatabaseService is a required
// dependency and cannot be resolved by the dependency
// injection service at runtime since the service is not
// registered in this instance of _services.
await _commands.AddModulesAsync(Assembly.GetEntryAssembly(), _services);
// ...
}
}

+ 7
- 0
docs/faq/commands/samples/runmode-cmdattrib.cs View File

@@ -0,0 +1,7 @@
[Command("process", RunMode = RunMode.Async)]
public async Task ProcessAsync(string input)
{
// Does heavy calculation here.
await Task.Delay(TimeSpan.FromMinute(1));
await ReplyAsync(input);
}

+ 10
- 0
docs/faq/commands/samples/runmode-cmdconfig.cs View File

@@ -0,0 +1,10 @@
public class Setup
{
private readonly CommandService _command;
public Setup()
{
var config = new CommandServiceConfig{ DefaultRunMode = RunMode.Async };
_command = new CommandService(config);
}
}

+ 122
- 0
docs/faq/misc/glossary.md View File

@@ -0,0 +1,122 @@
---
uid: FAQ.Glossary
title: Common Terminologies / Glossary
---

# Glossary

This is an additional chapter for quick references to various common
types that you may see within Discord.Net. To see more information
regarding each type of object, click on the object to navigate
to our API documentation page where you might find more explanation
about it.

## Common Types

* A **Guild** ([IGuild]) is an isolated collection of users and
channels, and are often referred to as "servers".
- Example: [Discord API](https://discord.gg/jkrBmQR)
* A **Channel** ([IChannel]) represents a generic channel.
- Example: #dotnet_discord-net
- See [Channel Types](#channel-types)

[IGuild]: xref:Discord.IGuild
[IChannel]: xref:Discord.IChannel

## Channel Types

### Message Channels
* A **Text Channel** ([ITextChannel]) is a message channel from a Guild.
* A **Thread Channel** ([IThreadChannel]) is a thread channel from a Guild.
* A **News Channel** ([INewsChannel]) (also goes as announcement channel) is a news channel from a Guild.
* A **DM Channel** ([IDMChannel]) is a message channel from a DM.
* A **Group Channel** ([IGroupChannel]) is a message channel from a Group.
- This is rarely used due to the bot's inability to join groups.
* A **Private Channel** ([IPrivateChannel]) is a DM or a Group.
* A **Message Channel** ([IMessageChannel]) can be any of the above.

### Misc Channels
* A **Guild Channel** ([IGuildChannel]) is a guild channel in a guild.
- This can be any channels that may exist in a guild.
* A **Voice Channel** ([IVoiceChannel]) is a voice channel in a guild.
* A **Stage Channel** ([IStageChannel]) is a stage channel in a guild.
* A **Category Channel** ([ICategoryChannel]) (2.0+) is a category that
holds one or more sub-channels.
* A **Nested Channel** ([INestedChannel]) (2.0+) is a channel that can
exist under a category.

> [!NOTE]
> A Channel ([IChannel]) can be all types of channels.

[INestedChannel]: xref:Discord.INestedChannel
[IGuildChannel]: xref:Discord.IGuildChannel
[IMessageChannel]: xref:Discord.IMessageChannel
[ITextChannel]: xref:Discord.ITextChannel
[IGroupChannel]: xref:Discord.IGroupChannel
[IDMChannel]: xref:Discord.IDMChannel
[IPrivateChannel]: xref:Discord.IPrivateChannel
[IVoiceChannel]: xref:Discord.IVoiceChannel
[ICategoryChannel]: xref:Discord.ICategoryChannel
[IChannel]: xref:Discord.IChannel
[IThreadChannel]: xref:Discord.IThreadChannel
[IStageChannel]: xref:Discord.IStageChannel
[INewsChannel]: xref:Discord.INewsChannel

## Message Types

* An **User Message** ([IUserMessage]) is a message sent by a user.
* A **System Message** ([ISystemMessage]) is a message sent by Discord itself.
* A **Message** ([IMessage]) can be any of the above.

[IUserMessage]: xref:Discord.IUserMessage
[ISystemMessage]: xref:Discord.ISystemMessage
[IMessage]: xref:Discord.IMessage

## User Types

* A **Guild User** ([IGuildUser]) is a user available inside a guild.
* A **Group User** ([IGroupUser]) is a user available inside a group.
- This is rarely used due to the bot's inability to join groups.
* A **Self User** ([ISelfUser]) is the bot user the client is currently logged in as.
* An **User** ([IUser]) can be any of the above.

[IGuildUser]: xref:Discord.IGuildUser
[IGroupUser]: xref:Discord.IGroupUser
[ISelfUser]: xref:Discord.ISelfUser
[IUser]: xref:Discord.IUser

## Emoji Types

* An **Emote** ([Emote]) is a custom emote from a guild.
- Example: `<:dotnet:232902710280716288>`
* An **Emoji** ([Emoji]) is a Unicode emoji.
- Example: `👍`

[Emote]: xref:Discord.Emote
[Emoji]: xref:Discord.Emoji


## Sticker Types

* A **Sticker** ([ISticker]) is a standard Discord sticker.
* A **Custom Sticker ([ICustomSticker]) is a Guild-unique sticker.

[ISticker]: xref:Discord.ISticker
[ICustomSticker]: xref:Discord.ICustomSticker

## Activity Types

* A **Game** ([Game]) refers to a user's game activity.
* A **Rich Presence** ([RichGame]) refers to a user's detailed
gameplay status.
- Visit [Rich Presence Intro] on Discord docs for more info.
* A **Streaming Status** ([StreamingGame]) refers to user's activity
for streaming on services such as Twitch.
* A **Spotify Status** ([SpotifyGame]) (2.0+) refers to a user's
activity for listening to a song on Spotify.

[Game]: xref:Discord.Game
[RichGame]: xref:Discord.RichGame
[StreamingGame]: xref:Discord.StreamingGame
[SpotifyGame]: xref:Discord.SpotifyGame
[Rich Presence Intro]: https://discord.com/developers/docs/rich-presence/best-practices

+ 29
- 0
docs/faq/misc/legacy.md View File

@@ -0,0 +1,29 @@
---
uid: FAQ.Legacy
title: Questions about Legacy Versions
---

# Legacy Questions

This section refers to legacy library-related questions that do not
apply to the latest or recent version of the Discord.Net library.

## X, Y, Z does not work! It doesn't return a valid value anymore.

If you are currently using an older version of the stable branch,
please upgrade to the latest pre-release version to ensure maximum
compatibility. Several features may be broken in older
versions and will likely not be fixed in the version branch due to
their breaking nature.

Visit the repo's [release tag] to see the latest public pre-release.

[release tag]: https://github.com/discord-net/Discord.Net/releases

## I came from an earlier version of Discord.Net 1.0, and DependencyMap doesn't seem to exist anymore in the later revision? What happened to it?

The `DependencyMap` has been replaced with Microsoft's
[DependencyInjection] Abstractions. An example usage can be seen
[here](https://github.com/foxbot/DiscordBotBase/blob/csharp/src/DiscordBot/Program.cs#L36).

[DependencyInjection]: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection

+ 22
- 0
docs/faq/toc.yml View File

@@ -0,0 +1,22 @@
- name: Basic Concepts
items:
- name: Getting Started
topicUid: FAQ.Basics.GetStarted
- name: Basic Operations
topicUid: FAQ.Basics.BasicOp
- name: Client Basics
topicUid: FAQ.Basics.ClientBasics
- name: Interactions
topicUid: FAQ.Basics.InteractionBasics
- name: Commands
items:
- name: String commands
topicUid: FAQ.Commands.General
- name: Interaction commands
topicUid: FAQ.Commands.Interactions
- name: Dependency Injection
topicUid: FAQ.Commands.DI
- name: Glossary
topicUid: FAQ.Glossary
- name: Legacy or Upgrade
topicUid: FAQ.Legacy

+ 1
- 1
docs/guides/concepts/entities.md View File

@@ -63,4 +63,4 @@ a variant of the type that you need.

## Sample

[!code-csharp[Entity Sample](samples/entities.cs)]
[!code-csharp[Entity Sample](samples/entities.cs)]

BIN
docs/guides/getting_started/images/nightlies-vs-note.png View File

Before After
Width: 1572  |  Height: 191  |  Size: 9.9 KiB

BIN
docs/guides/getting_started/images/nightlies-vs-step1.png View File

Before After
Width: 640  |  Height: 497  |  Size: 13 KiB

BIN
docs/guides/getting_started/images/nightlies-vs-step2.png View File

Before After
Width: 744  |  Height: 434  |  Size: 13 KiB

BIN
docs/guides/getting_started/images/nightlies-vs-step4.png View File

Before After
Width: 461  |  Height: 334  |  Size: 8.0 KiB

+ 9
- 8
docs/guides/getting_started/installing.md View File

@@ -11,9 +11,9 @@ may also compile this library yourself should you so desire.

## Supported Platforms

Discord.Net targets [.NET Standard] both 1.3 and 2.0; this also means
that creating applications using the latest version of [.NET Core] is
the most recommended. If you are bound by Windows-specific APIs or
Discord.Net targets [.NET 5.0], but is also available on older versions, like [.NET Standard] and [.NET Core]; this still means
that creating applications using the latest version of .NET (6.0)
is most recommended. If you are bound by Windows-specific APIs or
other limitations, you may also consider targeting [.NET Framework]
4.6.1 or higher.

@@ -23,6 +23,7 @@ other limitations, you may also consider targeting [.NET Framework]
> implementation and may crash the application upon startup.

[Mono]: https://www.mono-project.com/
[.NET 5.0]: https://docs.microsoft.com/en-us/dotnet/core/whats-new/dotnet-5
[.NET Standard]: https://docs.microsoft.com/en-us/dotnet/articles/standard/library
[.NET Core]: https://docs.microsoft.com/en-us/dotnet/articles/core/
[.NET Framework]: https://docs.microsoft.com/en-us/dotnet/framework/get-started/
@@ -90,15 +91,15 @@ In order to compile Discord.Net, you will need the following:

### Using Visual Studio

* [Visual Studio 2019](https://visualstudio.microsoft.com/)
* [.NET Core SDK]
* [Visual Studio 2019](https://visualstudio.microsoft.com/) or later.
* [.NET 5 SDK]

The .NET Core and Docker workload is required during Visual Studio
The .NET 5 and Docker workload is required during Visual Studio
installation.

### Using Command Line

* [.NET Core SDK]
* [.NET 5 SDK]

## Additional Information

@@ -141,4 +142,4 @@ over the default ones.

***

[.NET Core SDK]: https://dotnet.microsoft.com/download
[.NET 5 SDK]: https://dotnet.microsoft.com/download

+ 30
- 0
docs/guides/getting_started/labs.md View File

@@ -0,0 +1,30 @@
---
uid: Guides.GettingStarted.Installation.Labs
title: Installing Labs builds
---

# Installing Discord.NET Labs

Discord.NET Labs is the experimental repository that introduces new features & chips away at all bugs until ready for merging into Discord.NET.
Are you looking to test or play with new features?

> [!IMPORTANT]
> It is very ill advised to use Discord.NET Labs in a production environment normally,
> considering it can include bugs that have not been discovered yet, as features are freshly added.
> However if approached correctly, will work as a pre-release to Discord.NET.
> Make sure to report any bugs at the Labs [repository] or on [Discord]

[Discord]: https://discord.gg/dnet
[repository]: https://github.com/Discord-Net-Labs/Discord.Net-Labs

## Installation:

[NuGet] - This only includes releases, on which features are ready to test.

> [!NOTE]
> Installing NuGet packages is covered fully at [Installing Discord NET](xref:Guides.GettingStarted.Installation)

[MyGet] - Available for current builds and unreleased features.

[NuGet]: https://www.nuget.org/packages/Discord.Net.Labs/
[MyGet]: https://www.myget.org/feed/Packages/discord-net-labs

+ 0
- 97
docs/guides/getting_started/nightlies.md View File

@@ -1,97 +0,0 @@
---
uid: Guides.GettingStarted.Installation.Nightlies
title: Installing Nightly Build
---

# Installing Discord.Net Nightly Build

Before Discord.Net pushes a new set of features into the stable
version, we use nightly builds to test the features with the
community for an extensive period of time. Each nightly build is
compiled by AppVeyor whenever a new commit is made and will be pushed
to our MyGet feed.

> [!IMPORTANT]
> Although nightlies are generally stable and have more features
> and bug fixes than the current stable build on NuGet, there
> will be breaking changes during the development or
> breaking bugs; these bugs are usually fixed as soon as they
> are discovered, but you should still be aware of that.

## Installing with MyGet (Recommended)

MyGet is typically used by many development teams to publish their
latest pre-release packages before the features are finalized and
pushed to NuGet.

The following is the feed link of Discord.Net,

* `https://www.myget.org/F/discord-net/api/v3/index.json`

Depending on which IDE you use, there are many different ways of
adding the feed to your package source.

### [Using Visual Studio](#tab/vs)

1. Go to `Tools` > `NuGet Package Manager` > `Package Manager Settings`

![VS](images/nightlies-vs-step1.png)

2. Go to `Package Sources`

![Package Sources](images/nightlies-vs-step2.png)

3. Click on the add icon
4. Fill in the desired name and source as shown below and hit `Update`

![Add Source](images/nightlies-vs-step4.png)

> [!NOTE]
> Remember to tick the `Include pre-release` checkbox to see the
> nightly builds!
> ![Checkbox](images/nightlies-vs-note.png)

### [Using dotnet CLI](#tab/cli)

1. Launch a terminal of your choice
2. Navigate to where your `*.csproj` is located
3. Type `dotnet add package Discord.Net --source https://www.myget.org/F/discord-net/api/v3/index.json`

### [Using Local NuGet.Config](#tab/local-nuget-config)

If you plan on deploying your bot or developing outside of Visual
Studio, you will need to create a local NuGet configuration file for
your project.

To do this, create a file named `NuGet.Config` alongside the root of
your application, where the project is located.

Paste the following snippets into this configuration file, adding any
additional feeds if necessary.

[!code[NuGet Configuration](samples/nuget.config)]

After which, you may install the packages by directly modifying the
project file and specifying a version, or by using
the [Package Manager Console](https://docs.microsoft.com/en-us/nuget/tools/powershell-reference)
(`Install-Package Discord.Net -IncludePrerelease`).

***

## Installing from AppVeyor Artifacts

As mentioned in the first paragraph, we utilize AppVeyor to perform
automated tests and publish the new build. During the publishing
process, we also upload the NuGet packages onto
AppVeyor's Artifact collection.

The latest build status can be found within our [AppVeyor project].

[AppVeyor project]: https://ci.appveyor.com/project/rogueexception/discord-net

1. In the project, you may find our latest build including the
aforementioned artifacts.
![Artifacts](images/appveyor-artifacts.png)
2. In the artifacts collection, you should see the latest packages
packed in `*.nupkg` form which you could download from and use.
![NuPkgs](images/appveyor-nupkg.png)

docs/guides/interactions/application-commands/context-menu-commands/creating-context-menu-commands.md → docs/guides/int_basics/application-commands/context-menu-commands/creating-context-menu-commands.md View File

@@ -16,9 +16,9 @@ Guild commands are specific to the guild you specify when making them. Guild com
- 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 5 global context menu commands, and an additional 5 guild-specific context menu commands per guild.
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).
[!IMPORTANT]
> Apps can have a maximum of 5 global context menu commands,
> and an additional 5 guild-specific context menu commands per guild.

## UserCommandBuilder

@@ -40,7 +40,9 @@ The context menu message command builder will help you create message commands.
| WithName | Function | Sets the field name. |
| Build | Function | Builds the builder into the appropriate `MessageCommandProperties` class used to make Menu commands |

**Note**: Context Menu command names can be upper and lowercase, and use spaces.
> [!NOTE]
> Context Menu command names can be upper and lowercase, and use spaces.
> They cannot be registered pre-ready.

Let's use the user command builder to make a global and guild command.

@@ -102,4 +104,7 @@ public async Task Client_Ready()
```

> [!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.
> 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.

docs/guides/interactions/application-commands/context-menu-commands/receiving-context-menu-command-events.md → docs/guides/int_basics/application-commands/context-menu-commands/receiving-context-menu-command-events.md View File


+ 51
- 0
docs/guides/int_basics/application-commands/intro.md View File

@@ -0,0 +1,51 @@
---
uid: Guides.SlashCommands.Intro
title: Introduction to slash commands
---


# Getting started with application commands.

This guide will show you how to use application commands.
If you have extra questions that aren't covered here you can come to our
[Discord](https://discord.com/invite/dvSfUTet3K) server and ask around there.

## What is an application command?

Application commands consist of three different types. Slash commands, context menu User commands and context menu Message commands.
Slash commands are made up of a name, description, and a block of options, which you can think of like arguments to a function.
The name and description help users find your command among many others, and the options validate user input as they fill out your command.
Message and User commands are only a name, to the user. So try to make the name descriptive.
They're accessed by right clicking (or long press, on mobile) a user or a message, respectively.

> [!IMPORTANT]
> Context menu commands are currently not supported on mobile.

All three varieties of application commands have both Global and Guild variants.
Your global commands are available in every guild that adds your application.
You can also make commands for a specific guild; they're only available in that guild.
The User and Message commands are more limited in quantity than the slash commands.
For specifics, check out their respective guide pages.

An Interaction is the message that your application receives when a user uses a command.
It includes the values that the user submitted, as well as some metadata about this particular instance of the command being used:
the guild_id,
channel_id,
member and other fields.
You can find all the values in our data models.

## Authorizing your bot for application commands

There is a new special OAuth2 scope for applications called `applications.commands`.
In order to make Application Commands work within a guild, the guild must authorize your application
with the `applications.commands` scope. The bot scope is not enough.

Head over to your discord applications OAuth2 screen and make sure to select the `application.commands` scope.

![OAuth2 scoping](slash-commands/images/oauth.png)

From there you can then use the link to add your bot to a server.

> [!NOTE]
> In order for users in your guild to use your slash commands, they need to have
> the "Use Application Commands" permission on the guild.

docs/guides/interactions/application-commands/slash-commands/08-bulk-overwrite-of-global-slash-commands.md → docs/guides/int_basics/application-commands/slash-commands/bulk-overwrite-of-global-slash-commands.md View File


docs/guides/interactions/application-commands/slash-commands/07-choice-slash-command.md → docs/guides/int_basics/application-commands/slash-commands/choice-slash-command.md View File


docs/guides/interactions/application-commands/slash-commands/02-creating-slash-commands.md → docs/guides/int_basics/application-commands/slash-commands/creating-slash-commands.md View File


docs/guides/interactions/application-commands/slash-commands/images/ephemeral1.png → docs/guides/int_basics/application-commands/slash-commands/images/ephemeral1.png View File


docs/guides/interactions/application-commands/slash-commands/images/feedback1.png → docs/guides/int_basics/application-commands/slash-commands/images/feedback1.png View File


docs/guides/interactions/application-commands/slash-commands/images/feedback2.png → docs/guides/int_basics/application-commands/slash-commands/images/feedback2.png View File


docs/guides/interactions/application-commands/slash-commands/images/listroles1.png → docs/guides/int_basics/application-commands/slash-commands/images/listroles1.png View File


docs/guides/interactions/application-commands/slash-commands/images/listroles2.png → docs/guides/int_basics/application-commands/slash-commands/images/listroles2.png View File


docs/guides/interactions/application-commands/slash-commands/images/oauth.png → docs/guides/int_basics/application-commands/slash-commands/images/oauth.png View File


docs/guides/interactions/application-commands/slash-commands/images/settings1.png → docs/guides/int_basics/application-commands/slash-commands/images/settings1.png View File


docs/guides/interactions/application-commands/slash-commands/images/settings2.png → docs/guides/int_basics/application-commands/slash-commands/images/settings2.png View File


docs/guides/interactions/application-commands/slash-commands/images/settings3.png → docs/guides/int_basics/application-commands/slash-commands/images/settings3.png View File


docs/guides/interactions/application-commands/slash-commands/images/slashcommand1.png → docs/guides/int_basics/application-commands/slash-commands/images/slashcommand1.png View File


docs/guides/interactions/application-commands/slash-commands/images/slashcommand2.png → docs/guides/int_basics/application-commands/slash-commands/images/slashcommand2.png View File


docs/guides/interactions/application-commands/slash-commands/04-parameters.md → docs/guides/int_basics/application-commands/slash-commands/parameters.md View File


docs/guides/interactions/application-commands/slash-commands/05-responding-ephemerally.md → docs/guides/int_basics/application-commands/slash-commands/responding-ephemerally.md View File


docs/guides/interactions/application-commands/slash-commands/03-responding-to-slash-commands.md → docs/guides/int_basics/application-commands/slash-commands/responding-to-slash-commands.md View File


docs/guides/interactions/application-commands/slash-commands/06-subcommands.md → docs/guides/int_basics/application-commands/slash-commands/subcommands.md View File


docs/guides/interactions/intro.md → docs/guides/int_basics/intro.md View File


docs/guides/interactions/message-components/05-advanced.md → docs/guides/int_basics/message-components/advanced.md View File


docs/guides/interactions/message-components/03-buttons-in-depth.md → docs/guides/int_basics/message-components/buttons-in-depth.md View File


docs/guides/interactions/message-components/images/image1.png → docs/guides/int_basics/message-components/images/image1.png View File


docs/guides/interactions/message-components/images/image2.png → docs/guides/int_basics/message-components/images/image2.png View File


docs/guides/interactions/message-components/images/image3.png → docs/guides/int_basics/message-components/images/image3.png View File


docs/guides/interactions/message-components/images/image4.png → docs/guides/int_basics/message-components/images/image4.png View File


docs/guides/interactions/message-components/images/image5.png → docs/guides/int_basics/message-components/images/image5.png View File


docs/guides/interactions/message-components/images/image6.png → docs/guides/int_basics/message-components/images/image6.png View File


docs/guides/interactions/message-components/01-getting-started.md → docs/guides/int_basics/message-components/intro.md View File

@@ -1,5 +1,5 @@
---
uid: Guides.MessageComponents.GettingStarted
uid: Guides.MessageComponents.Intro
title: Getting Started with Components
---


docs/guides/interactions/message-components/02-responding-to-buttons.md → docs/guides/int_basics/message-components/responding-to-buttons.md View File


docs/guides/interactions/message-components/04-select-menus.md → docs/guides/int_basics/message-components/select-menus.md View File


+ 47
- 0
docs/guides/int_framework/autocompletion.md View File

@@ -0,0 +1,47 @@
---
uid: Guides.IntFw.AutoCompletion
title: Command Autocompletion
---

# AutocompleteHandlers

[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.

[AutoCompleteHandlers]: xref:Discord.Interactions.AutocompleteHandler
[AutoCompleteHandler]: xref:Discord.Interactions.AutocompleteHandler
[AutoCompleteAttribute]:

+ 13
- 0
docs/guides/int_framework/dependency-injection.md View File

@@ -0,0 +1,13 @@
---
uid: Guides.IntFw.DI
title: Dependency Injection
---

# Dependency Injection

Dependency injection in the Interaction Service is mostly based on that of the Text-based command service,
for which further information is found [here](xref:Guides.TextCommands.DI).

> [!NOTE]
> The 2 are nearly identical, except for one detail:
> [Resolving Module Dependencies](xref:Guides.IntFw.Intro#resolving-module-dependencies)

+ 353
- 0
docs/guides/int_framework/intro.md View File

@@ -0,0 +1,353 @@
---
uid: Guides.IntFw.Intro
title: Introduction to the Interaction Service
---

# Getting Started

The Interaction Service provides an attribute based framework for creating Discord Interaction handlers.

To start using the Interaction Service, you need to create a service instance.
Optionally you can provide the [InteractionService] constructor with a
[InteractionServiceConfig] to change the services behaviour to suit your needs.

```csharp
...
// _client here is DiscordSocketClient.
// A different approach to passing in a restclient is also possible.
var _interactionService = new InteractionService(_client.Rest);

...
```

## Modules

Attribute based Interaction handlers must be defined within a command module class.
Command modules are responsible for executing the Interaction handlers and providing them with the necessary execution info and helper functions.

Command modules are transient objects.
A new module instance is created before a command execution starts then it will be disposed right after the method returns.

Every module class must:

- be public
- inherit [InteractionModuleBase]

Optionally you can override the included :

- OnModuleBuilding (executed after the module is built)
- BeforeExecute (executed before a command execution starts)
- AfterExecute (executed after a command execution concludes)

methods to configure the modules behaviour.

Every command module exposes a set of helper methods, namely:

- `RespondAsync()` => Respond to the interaction
- `FollowupAsync()` => Create a followup message for an interaction
- `ReplyAsync()` => Send a message to the origin channel of the interaction
- `DeleteOriginalResponseAsync()` => Delete the original interaction response

## Commands

Valid **Interaction Commands** must comply with the following requirements:

| | return type | max parameter count | allowed parameter types | attribute |
|-------------------------------|------------------------------|---------------------|-------------------------------|--------------------------|
|[Slash Command](#slash-commands)| `Task`/`Task<RuntimeResult>` | 25 | any* | `[SlashCommand]` |
|[User Command](#user-commands) | `Task`/`Task<RuntimeResult>` | 1 | Implementations of `IUser` | `[UserCommand]` |
|[Message Command](#message-commands)| `Task`/`Task<RuntimeResult>` | 1 | Implementations of `IMessage` | `[MessageCommand]` |
|[Component Interaction Command](#component-interaction-commands)| `Task`/`Task<RuntimeResult>` | inf | `string` or `string[]` | `[ComponentInteraction]` |
|[Autocomplete Command](#autocomplete-commands)| `Task`/`Task<RuntimeResult>` | - | - | `[AutocompleteCommand]`|

> [!NOTE]
> a `TypeConverter` that is capable of parsing type in question must be registered to the [InteractionService] instance.
> You should avoid using long running code in your command module.
> Depending on your setup, long running code may block the Gateway thread of your bot, interrupting its connection to Discord.

## Slash Commands

Slash Commands are created using the [SlashCommandAttribute].
Every Slash Command must declare a name and a description.
You can check Discords **Application Command Naming Guidelines**
[here](https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-naming).

[!code-csharp[Slash Command](samples/intro/slashcommand.cs)]

### Parameters

Slash Commands can have up to 25 method parameters. You must name your parameters in accordance with
[Discords Naming Guidelines](https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-naming).
[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.*
| interface | Channel Type |
|---------------------|-------------------------------|
| `IStageChannel` | Stage Channels |
| `IVoiceChannel` | Voice Channels |
| `IDMChannel` | DM Channels |
| `IGroupChannel` | Group Channels |
| `ICategory Channel` | Category Channels |
| `INewsChannel` | News Channels |
| `IThreadChannel` | Public, Private, News Threads |
| `ITextChannel` | Text Channels |

---

#### Optional Parameters

Parameters with default values (ie. `int count = 0`) will be displayed as optional parameters on Discord Client.

#### Parameter Summary

By using the [SummaryAttribute] you can customize the displayed name and description of a parameter

[!code-csharp[Summary Attribute](samples/intro/summaryattribute.cs)]

#### Parameter Choices

[ChoiceAttribute] can be used to add choices to a parameter.

[!code-csharp[Choice Attribute](samples/intro/groupattribute.cs)]

This Slash Command will be displayed exactly the same as the previous example.

#### Channel Types

Channel types for an [IChannel] parameter can also be restricted using the [ChannelTypesAttribute].

[!code-csharp[Channel Attribute](samples/intro/channelattribute.cs)]

In this case, user can only input Stage Channels and Text Channels to this parameter.

#### Min/Max Value

You can specify the permitted max/min value for a number type parameter using the [MaxValueAttribute] and [MinValueAttribute].

## User Commands

A valid User Command must have the following structure:

[!code-csharp[User Command](samples/intro/usercommand.cs)]

> [!WARNING]
> User commands can only have one parameter and its type must be an implementation of [IUser].

## Message Commands

A valid Message Command must have the following structure:

[!code-csharp[Message Command](samples/intro/messagecommand.cs)]

> [!WARNING]
> Message commands can only have one parameter and its type must be an implementation of [IMessage].

## Component Interaction Commands

Component Interaction Commands are used to handle interactions that originate from **Discord Message Component**s.
This pattern is particularly useful if you will be reusing a set a **Custom ID**s.

Component Interaction Commands support wild card matching,
by default `*` character can be used to create a wild card pattern.
Interaction Service will use lazy matching to capture the words corresponding to the wild card character.
And the captured words will be passed on to the command method in the same order they were captured.

[!code-csharp[Button](samples/intro/button.cs)]

You may use as many wild card characters as you want.

> [!NOTE]
> If Interaction Service recieves a component interaction with **player:play,rickroll** custom id,
> `op` will be *play* and `name` will be *rickroll*

## Select Menus

Unlike button interactions, select menu interactions also contain the values of the selected menu items.
In this case, you should structure your method to accept a string array.

[!code-csharp[Dropdown](samples/intro/dropdown.cs)]

> [!NOTE]
> Wildcards may also be used to match a select menu ID,
> though keep in mind that the array containing the select menu values should be the last parameter.

## Autocomplete Commands

Autocomplete commands must be parameterless methods. A valid Autocomplete command must have the following structure:

[!code-csharp[Autocomplete Command](samples/intro/autocomplete.cs)]

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`.

[!code-csharp[Context Example](samples/intro/context.cs)]

## Loading Modules

[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:

| Method | Mean | Error | StdDev |
|----------------- |----------:|---------:|---------:|
| ReflectionInvoke | 225.93 ns | 4.522 ns | 7.040 ns |
| CompiledLambda | 48.79 ns | 0.981 ns | 1.276 ns |

## Registering Commands to Discord

Application commands loaded to the Interaction Service can be registered to Discord using a number of different methods.
In most cases `RegisterCommandsGloballyAsync()` and `RegisterCommandsToGuildAsync()` are the methods to use.
Command registration methods can only be used after the gateway client is ready or the rest client is logged in.

[!code-csharp[Registering Commands Example](samples/intro/registering.cs)]

Methods like `AddModulesToGuildAsync()`, `AddCommandsToGuildAsync()`, `AddModulesGloballyAsync()` and `AddCommandsGloballyAsync()`
can be used to register cherry picked modules or commands to global/guild scopes.

> [!NOTE]
> In debug environment, since Global commands can take up to 1 hour to register/update,
> it is adviced to register your commands to a test guild for your changes to take effect immediately.
> You can use preprocessor directives to create a simple logic for registering commands as seen above

## Interaction Utility

Interaction Service ships with a static `InteractionUtiliy`
class which contains some helper methods to asynchronously waiting for Discord Interactions.
For instance, `WaitForInteractionAsync()` method allows you to wait for an Interaction for a given amount of time.
This method returns the first encountered Interaction that satisfies the provided predicate.

> [!WARNING]
> If you are running the Interaction Service on `RunMode.Sync` you should avoid using this method in your commands,
> as it will block the gateway thread and interrupt your bots connection.

## Webhook Based Interactions

Instead of using the gateway to recieve Discord Interactions, Discord allows you to recieve Interaction events over Webhooks.
Interaction Service also supports this Interaction type but to be able to
respond to the Interactions within your command modules you need to perform the following:

- Make your modules inherit `RestInteractionModuleBase`
- Set the `ResponseCallback` property of `InteractionServiceConfig` so that the `ResponseCallback`
delegate can be used to create HTTP responses from a deserialized json object string.
- Use the interaction endpoints of the module base instead of the interaction object (ie. `RespondAsync()`, `FollowupAsync()`...).

[AutocompleteHandlers]: xref:Guides.IntFw.AutoCompletion
[DependencyInjection]: xref:Guides.TextCommands.DI

[GroupAttribute]: xref:Discord.Interactions.GroupAttribute
[InteractionService]: xref:Discord.Interactions.InteractionService
[InteractionServiceConfig]: xref:Discord.Interactions.InteractionServiceConfig
[InteractionModuleBase]: xref:Discord.Interactions.InteractionModuleBase
[SlashCommandAttribute]: xref:Discord.Interactions.SlashCommandAttribute
[InteractionCreated]: xref:Discord.WebSocket.BaseSocketClient
[ButtonExecuted]: xref:Discord.WebSocket.BaseSocketClient
[SelectMenuExecuted]: xref:Discord.WebSocket.BaseSocketClient
[AutocompleteExecuted]: xref:Discord.WebSocket.BaseSocketClient
[UserCommandExecuted]: xref:Discord.WebSocket.BaseSocketClient
[MessageCommandExecuted]: xref:Discord.WebSocket.BaseSocketClient
[DiscordSocketClient]: xref:Discord.WebSocket.DiscordSocketClient
[DiscordRestClient]: xref:Discord.Rest.DiscordRestClient
[SocketInteractionContext]: xref:Discord.Interactions.SocketInteractionContext
[ShardedInteractionContext]: xref:Discord.Interactions.ShardedInteractionContext
[InteractionContext]: xref:Discord.Interactions.InteractionContext
[IInteractionContect]: xref:Discord.Interactions.IInteractionContext
[RestInteractionContext]: xref:Discord.Rest.RestInteractionContext
[SummaryAttribute]: xref:Discord.Interactions.SummaryAttribute
[ChoiceAttribute]: xref:Discord.Interactions.ChoiceAttribute
[ChannelTypesAttribute]: xref:Discord.Interactions.ChannelTypesAttribute
[MaxValueAttribute]: xref:Discord.Interactions.MaxValueAttribute
[MinValueAttribute]: xref:Discord.Interactions.MinValueAttribute

[IChannel]: xref:Discord.IChannel
[IRole]: xref:Discord.IRole
[IUser]: xref:Discord.IUser
[IMessage]: xref:Discord.IMessage
[IMentionable]: xref:Discord.IMentionable

+ 69
- 0
docs/guides/int_framework/post-execution.md View File

@@ -0,0 +1,69 @@
---
uid: Guides.IntFw.PostExecution
title: Post-Command execution
---

# Post-Execution Logic

Interaction Service uses [IResult] to provide information about the state of command execution.
These can be used to log internal exceptions or provide some insight to the command user.

If you are running your commands using `RunMode.Sync` these command results can be retrieved from
the return value of [InteractionService.ExecuteCommandAsync] method or by
registering delegates to Interaction Service events.

If you are using the `RunMode.Async` to run your commands,
you must use the Interaction Service events to get the execution results. When using `RunMode.Async`,
[InteractionService.ExecuteCommandAsync] will always return a successful result.

[InteractionService.ExecuteCommandAsync]: xref: Discord.Interactions.InteractionService.ExecuteCommandAsync*

## Results

Interaction Result come in a handful of different flavours:

1. [AutocompletionResult]: returned by Autocompleters
2. [ExecuteResult]: contains the result of method body execution process
3. [PreconditionGroupResult]: returned by Precondition groups
4. [PreconditionResult]: returned by preconditions
5. [RuntimeResult]: a user implementable result for returning user defined results
6. [SearchResult]: returned by command lookup map
7. [TypeConverterResult]: returned by TypeConverters

> [!NOTE]
> You can either use the [IResult.Error] property of an Interaction result or create type check for the
> afformentioned result types to branch out your post-execution logic to handle different situations.


[AutocompletionResult]: xref:Discord.AutocompleteResult
[ExecuteResult]: xref:Discord.Interactions.ExecuteResult
[PreconditionGroupResult]: xref:Discord.Interactions.PreconditionGroupResult
[PreconditionResult]: xref:Discord.Interactions.PreconditionResult
[SearchResult]: xref:Discord.Interactions.SearchResult
[TypeConverterResult]: xref:Discord.Interactions.TypeConverterResult
[IResult.Error]: xref:Discord.Interactions.IResult.Error*

## CommandExecuted Events

Every time a command gets executed, Interaction Service raises a `CommandExecuted` event.
These events can be used to create a post-execution pipeline.

[!code-csharp[Error Review](samples/postexecution/error_review.cs)

## Log Event

InteractionService regularly outputs information about the occuring events to keep the developer informed.

## Runtime Result

Interaction commands allow you to return `Task<RuntimeResult>` to pass on additional information about the command execution
process back to your post-execution logic.

Custom [RuntimeResult] classes can be created by inheriting the base [RuntimeResult] class.

If command execution process reaches the method body of the command and no exceptions are thrown during
the execution of the method body, [RuntimeResult] returned by your command will be accessible by casting/type-checking the
[IResult] parameter of the `CommandExecuted` event delegate.

[RuntimeResult]: xref:Discord.Interactions.RuntimeResult
[IResult]: xref:Discord.Interactions.IResult

+ 77
- 0
docs/guides/int_framework/preconditions.md View File

@@ -0,0 +1,77 @@
---
uid: Guides.IntFw.Preconditions
title: Preconditions
---

# Preconditions

Precondition logic is the same as it is for Text-based commands.
A list of attributes and usage is still given for people who are new to both.

There are two types of Preconditions you can use:

* [PreconditionAttribute] can be applied to Modules, Groups, or Commands.
* [ParameterPreconditionAttribute] can be applied to Parameters.

You may visit their respective API documentation to find out more.

[PreconditionAttribute]: xref:Discord.Interactions.PreconditionAttribute
[ParameterPreconditionAttribute]: xref:Discord.Interactions.ParameterPreconditionAttribute

## Bundled Preconditions

@Discord.Interactions ships with several bundled Preconditions for you
to use.

* @Discord.Interactions.RequireContextAttribute
* @Discord.Interactions.RequireOwnerAttribute
* @Discord.Interactions.RequireBotPermissionAttribute
* @Discord.Interactions.RequireUserPermissionAttribute
* @Discord.Interactions.RequireNsfwAttribute
* @Discord.Interactions.RequireRoleAttribute

## Using Preconditions

To use a precondition, simply apply any valid precondition candidate to
a command method signature as an attribute.

[!code-csharp[Precondition usage](samples/preconditions/precondition_usage.cs)]

## ORing Preconditions

When writing commands, you may want to allow some of them to be
executed when only some of the precondition checks are passed.

This is where the [Group] property of a precondition attribute comes in
handy. By assigning two or more preconditions to a group, the command
system will allow the command to be executed when one of the
precondition passes.

### Example - ORing Preconditions

[!code-csharp[OR Precondition](samples/preconditions/group_precondition.cs)]

[Group]: xref:Discord.Commands.PreconditionAttribute.Group

## Custom Preconditions

To write your own Precondition, create a new class that inherits from
either [PreconditionAttribute] or [ParameterPreconditionAttribute]
depending on your use.

In order for your Precondition to function, you will need to override
the [CheckPermissionsAsync] method.

If the context meets the required parameters, return
[PreconditionResult.FromSuccess], otherwise return
[PreconditionResult.FromError] and include an error message if
necessary.

> [!NOTE]
> Visual Studio can help you implement missing members
> from the abstract class by using the "Implement Abstract Class"
> IntelliSense hint.

[CheckPermissionsAsync]: xref:Discord.Commands.PreconditionAttribute.CheckPermissionsAsync*
[PreconditionResult.FromSuccess]: xref:Discord.Commands.PreconditionResult.FromSuccess*
[PreconditionResult.FromError]: xref:Discord.Commands.PreconditionResult.FromError*

+ 9
- 0
docs/guides/int_framework/samples/intro/autocomplete.cs View File

@@ -0,0 +1,9 @@
[AutocompleteCommand("parameter_name", "command_name")]
public async Task Autocomplete()
{
IEnumerable<AutocompleteResult> results;

...

await (Context.Interaction as SocketAutocompleteInteraction).RespondAsync(results);
}

+ 5
- 0
docs/guides/int_framework/samples/intro/button.cs View File

@@ -0,0 +1,5 @@
[ComponentInteraction("player:*,*")]
public async Task Play(string op, string name)
{
...
}

+ 5
- 0
docs/guides/int_framework/samples/intro/channelattribute.cs View File

@@ -0,0 +1,5 @@
[SlashCommand("name", "Description")]
public async Task Command([ChannelTypes(ChannelType.Stage, ChannelType.Text)] IChannel channel)
{
...
}

+ 14
- 0
docs/guides/int_framework/samples/intro/context.cs View File

@@ -0,0 +1,14 @@
discordClient.ButtonExecuted += async (interaction) =>
{
var ctx = new SocketInteractionContext<SocketMessageComponent>(discordClient, interaction);
await _interactionService.ExecuteAsync(ctx, serviceProvider);
};

public class MessageComponentModule : InteractionModuleBase<SocketInteractionContext<SocketMessageComponent>>
{
[ComponentInteraction("custom_id")]
public async Command()
{
Context.Interaction.UpdateAsync(...);
}
}

+ 11
- 0
docs/guides/int_framework/samples/intro/dropdown.cs View File

@@ -0,0 +1,11 @@
[ComponentInteraction("role_selection")]
public async Task RoleSelection(string[] selectedRoles)
{
...
}

[ComponentInteraction("role_selection_*")]
public async Task RoleSelection(string id, string[] selectedRoles)
{
...
}

+ 21
- 0
docs/guides/int_framework/samples/intro/groupattribute.cs View File

@@ -0,0 +1,21 @@
[SlashCommand("blep", "Send a random adorable animal photo")]
public async Task Blep([Choice("Dog", "dog"), Choice("Cat", "cat"), Choice("Penguin", "penguin")] string animal)
{
...
}

// In most cases, you can use an enum to replace the seperate choice attributes in a command.

public enum Animal
{
Cat,
Dog,
Penguin
}

[SlashCommand("blep", "Send a random adorable animal photo")]
public async Task Blep(Animal animal)
{
...
}
```

+ 5
- 0
docs/guides/int_framework/samples/intro/messagecommand.cs View File

@@ -0,0 +1,5 @@
[MessageCommand("Bookmark")]
public async Task Bookmark(IMessage msg)
{
...
}

+ 5
- 0
docs/guides/int_framework/samples/intro/registering.cs View File

@@ -0,0 +1,5 @@
#if DEBUG
await interactionService.RegisterCommandsToGuildAsync(<test_guild_id>);
#else
await interactionService.RegisterCommandsGloballyAsync();
#endif

+ 5
- 0
docs/guides/int_framework/samples/intro/slashcommand.cs View File

@@ -0,0 +1,5 @@
[SlashCommand("echo", "Echo an input")]
public async Task Echo(string input)
{
await RespondAsync(input);
}

+ 1
- 0
docs/guides/int_framework/samples/intro/summaryattribute.cs View File

@@ -0,0 +1 @@
[Summary(description: "this is a parameter description")] string input

+ 5
- 0
docs/guides/int_framework/samples/intro/usercommand.cs View File

@@ -0,0 +1,5 @@
[UserCommand("Say Hello")]
public async Task SayHello(IUser user)
{
...
}

+ 28
- 0
docs/guides/int_framework/samples/postexecution/error_review.cs View File

@@ -0,0 +1,28 @@
interactionService.SlashCommandExecuted += SlashCommandExecuted;

async Task SlashCommandExecuted(SlashCommandInfo arg1, Discord.IInteractionContext arg2, IResult arg3)
{
if (!arg3.IsSuccess)
{
switch (arg3.Error)
{
case InteractionCommandError.UnmetPrecondition:
await arg2.Interaction.RespondAsync($"Unmet Precondition: {arg3.ErrorReason}");
break;
case InteractionCommandError.UnknownCommand:
await arg2.Interaction.RespondAsync("Unknown command");
break;
case InteractionCommandError.BadArgs:
await arg2.Interaction.RespondAsync("Invalid number or arguments");
break;
case InteractionCommandError.Exception:
await arg2.Interaction.RespondAsync("Command exception:{arg3.ErrorReason}");
break;
case InteractionCommandError.Unsuccessful:
await arg2.Interaction.RespondAsync("Command could not be executed");
break;
default:
break;
}
}
}

docs/guides/commands/samples/preconditions/group_precondition.cs → docs/guides/int_framework/samples/preconditions/group_precondition.cs View File


+ 3
- 0
docs/guides/int_framework/samples/preconditions/precondition_usage.cs View File

@@ -0,0 +1,3 @@
[RequireOwner]
[SlashCommand("hi")]
public Task SayHiAsync() => RespondAsync("hello owner!");

+ 30
- 0
docs/guides/int_framework/samples/typeconverters/enum_converter.cs View File

@@ -0,0 +1,30 @@
internal sealed class EnumConverter<T> : TypeConverter<T> where T : struct, Enum
{
public override ApplicationCommandOptionType GetDiscordType() => ApplicationCommandOptionType.String;

public override Task<TypeConverterResult> ReadAsync(IInteractionCommandContext context, SocketSlashCommandDataOption option, IServiceProvider services)
{
if (Enum.TryParse<T>((string)option.Value, out var result))
return Task.FromResult(TypeConverterResult.FromSuccess(result));
else
return Task.FromResult(TypeConverterResult.FromError(InteractionCommandError.ConvertFailed, $"Value {option.Value} cannot be converted to {nameof(T)}"));
}

public override void Write(ApplicationCommandOptionProperties properties, IParameterInfo parameterInfo)
{
var names = Enum.GetNames(typeof(T));
if (names.Length <= 25)
{
var choices = new List<ApplicationCommandOptionChoiceProperties>();

foreach (var name in names)
choices.Add(new ApplicationCommandOptionChoiceProperties
{
Name = name,
Value = name
});

properties.Choices = choices;
}
}
}

+ 118
- 0
docs/guides/int_framework/typeconverters.md View File

@@ -0,0 +1,118 @@
---
uid: Guides.IntFw.TypeConverters
title: Parameter Type Converters
---

# TypeConverters

[TypeConverters] are responsible for registering command parameters to Discord and parsing the user inputs into method parameters.

By default, TypeConverters for the following types are provided with @Discord.Interactions library.

- 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`
- `DateTime`
- `TimeSpan`

## Creating TypeConverters

Depending on your needs, there are two types of TypeConverters you can create:

- Concrete type
- Generic type

A valid converter must inherit [TypeConverter] base type. And override the abstract base methods.

### CanConvertTo() Method

This method is used by Interaction Service to search for alternative Type Converters.

Interaction Services determines the most suitable [TypeConverter] for a parameter type in the following order:

1. It searches for a [TypeConverter] that is registered to specifically target that parameter type
2. It searches for a [TypeConverter] that returns `true` when its `CanConvertTo()` method is invoked for thaty parameter type.
3. It searches for a generic `TypeConverter<T>` with a matching type constraint. If there are more multiple matches,
the one whose type constraint is the most specialized will be chosen.

> [!NOTE}
> Alternatively, you can use the generic variant (`TypeConverter<T>`) of the
> [TypeConverter] base class which implements the following method body for `CanConvertTo()` method

```csharp
public sealed override bool CanConvertTo (Type type) =>
typeof(T).IsAssignableFrom(type);
```

### GetDiscordType() Method

This method is used by [InteractionService] to determine the
[Discord Application Command Option type](https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-type)
of a parameter type.

### ReadAsync() Method

This method is used by [InteractionService] to parse the user input.
This method should return @Discord.Interactions.TypeConverterResult.FromSuccess* if the parsing operation is successful,
otherwise it should return @Discord.Interactions.TypeConverterResult.FromError* .
The inner logic of this method is totally up to you,
however you should avoid using long running code.

### Write() Method

This method is used to configure the **Discord Application Command Option** before it gets registered to Discord.
Command Option is configured by modifying the `ApplicationCommandOptionProperties` instance.

> [!WARNING]
> The default parameter building pipeline is isolated and will not be disturbed by the [TypeConverter] workflow.
> But changes made in this method will override the values generated by the
> [InteractionService] for a **Discord Application Command Option**.

## Example Enum TypeConverter

[!code-csharp[Enum Converter](samples/typeconverters/enum_converter.cs)]

> [!IMPORTANT]
> TypeConverters must be registered prior to module discovery.
> If Interaction Service encounters a parameter type that doesn't belong to any of the
> registered [TypeConverters] during this phase, it will throw an exception.

## Concrete TypeConverters

Registering Concrete TypeConverters are as simple as creating an instance of your custom converter and invoking `AddTypeConverter()` method.

```csharp
interactionService.AddTypeConverter<string[]>(new StringArrayConverter());
```

## Generic TypeConverters

To register a generic `TypeConverter<T>`, you need to invoke the `AddGenericTypeConverter()` method of the Interaction Service class.
You need to pass the type of your `TypeConverter<T>` and a target base type to this method.

For instance, to register the previously mentioned enum converter the following can be used:

```csharp
interactionService.AddGenericTypeConverter<Enum>(typeof(EnumConverter<>));
```

Interaction service checks if the target base type satisfies the type constraints of the Generic `TypeConverter` class.

> [!NOTE]
> Dependencies of Generic TypeConverters are also resolved using the Dependency Injection pattern.

[TypeConverter]: xref:Discord.Interactions.TypeConverter
[InteractionService]: xref:Discord.Interactions.InteractionService
[IChannel]: xref:Discord.IChannel
[IRole]: xref:Discord.IRole
[IUser]: xref:Discord.IUser
[IMentionable]: xref:Discord.IMentionable

+ 0
- 32
docs/guides/interactions/application-commands/01-getting-started.md View File

@@ -1,32 +0,0 @@
---
uid: Guides.SlashCommands.Intro
title: Introduction to slash commands
---


# Getting started with application commands.

Welcome! This guide will show you how to use application commands.

## What is an application command?

Application commands consist of three different types. Slash commands, context menu User commands and context menu Message commands.
Slash commands are made up of a name, description, and a block of options, which you can think of like arguments to a function. The name and description help users find your command among many others, and the options validate user input as they fill out your command.
Message and User commands are only a name, to the user. So try to make the name descriptive. They're accessed by right clicking (or long press, on mobile) a user or a message, respectively.

All three varieties of application commands have both Global and Guild variants. Your global commands are available in every guild that adds your application. You can also make commands for a specific guild; they're only available in that guild. The User and Message commands are more limited in quantity than the slash commands. For specifics, check out their respective guide pages.

An Interaction is the message that your application receives when a user uses a command. It includes the values that the user submitted, as well as some metadata about this particular instance of the command being used: the guild_id, channel_id, member and other fields. You can find all the values in our data models.

## Authorizing your bot for application commands

There is a new special OAuth2 scope for applications called `applications.commands`. In order to make Application Commands work within a guild, the guild must authorize your application with the `applications.commands` scope. The bot scope is not enough.

Head over to your discord applications OAuth2 screen and make sure to select the `application.commands` scope.

![OAuth2 scoping](slash-commands/images/oauth.png)

From there you can then use the link to add your bot to a server.

> [!NOTE]
> In order for users in your guild to use your slash commands, they need to have the "Use Slash Command" permission on the guild.

+ 0
- 12
docs/guides/interactions/application-commands/slash-commands/README.md View File

@@ -1,12 +0,0 @@
## Slash command guides

Here you can find some guides on how to use slash commands.

1. [Getting started](https://github.com/Discord-Net-Labs/Discord.Net-Labs/blob/Interactions/docs/guides/slash-commands/01-getting-started.md)
2. [Creating a slash command](https://github.com/Discord-Net-Labs/Discord.Net-Labs/blob/Interactions/docs/guides/slash-commands/02-creating-slash-commands.md)
3. [Responding to slash commands](https://github.com/Discord-Net-Labs/Discord.Net-Labs/blob/Interactions/docs/guides/slash-commands/03-responding-to-slash-commands.md)
4. [Parameters in slash commands](https://github.com/Discord-Net-Labs/Discord.Net-Labs/blob/Interactions/docs/guides/slash-commands/04-parameters.md)
5. [Responding ephemerally](https://github.com/Discord-Net-Labs/Discord.Net-Labs/blob/Interactions/docs/guides/slash-commands/05-responding-ephemerally.md)
6. [Subcommands](https://github.com/Discord-Net-Labs/Discord.Net-Labs/blob/Interactions/docs/guides/slash-commands/06-subcommands.md)
7. [Choices](https://github.com/Discord-Net-Labs/Discord.Net-Labs/blob/Interactions/docs/guides/slash-commands/07-choice-slash-command.md)
7. [Bulk overwrite of global slash commands](https://github.com/Discord-Net-Labs/Discord.Net-Labs/blob/release/3.x/docs/guides/interactions/application-commands/slash-commands/08-bulk-overwrite-of-global-slash-commands.md)

+ 0
- 27
docs/guides/interactions_framework/autocompleters.md View File

@@ -1,27 +0,0 @@
---
uid: Guides.InteractionsFramework.Autocompleters
title: Autocompleters
---

# Autocompleters

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 Autocompleters, use the `[AutocompleteAttribute(Type autocompleterType)]` overload of the `[AutocompleteAttribute]`. This will dynamically link the parameter to the Autocompleter type.

## Creating Autocompleters

A valid Autocompleter must inherit `AutocompleteHandler` base type and implement all of its abstract methods.

### GenerateSuggestionsAsync()

Interactions Service uses this method to generate a response to a Autocomplete Interaction. This method should return `AutocompletionResult.FromSuccess(IEnumerable<AutocompleteResult>)` to display parameter sugesstions to the user. If there are no suggestions to be presented to the user, you have two options:

1. Returning the parameterless `AutocompletionResult.FromSuccess()` will display "No options match your search." message to the user.
2. Returning `AutocompleteResult.FromError()` will make the Interaction Service not respond to the interation, consequently displaying the user "Loading options failed." message.

## Resolving Autocompleter Dependencies

Autocompleter 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 Autocompleters are constructed at service startup, class dependencies are resolved only once. If you need to access per-request dependencies you can use the IServiceProvider parameter of the `GenerateSuggestionsAsync()` method.

+ 0
- 27
docs/guides/interactions_framework/dependency-injection.md View File

@@ -1,27 +0,0 @@
---
uid: Guides.InteractionsFramework.DependencyInjection
title: Dependency Injection
---

# Dependency Injection

Interaction Service uses dependency injection to perform most of its operations. This way, you can access service dependencies throughout the framework.

## Setup

1. Create a `Microsoft.Extensions.DependencyInjection.ServiceCollection`.
2. Add the dependencies you wish to use in the modules.
3. Build a `IServiceProvider` using the `BuildServiceProvider()` method of the `ServiceCollection`.
4. Pass the `IServiceProvider` to `AddModulesAsync()`, `AddModuleAsync()` and `ExecuteAsync()` methods.

## Accessing the Dependencies

Services of a `IServiceProvider` can be accessed using *Contructor Injection* and *Property Injection*.

Interaction Service will populate the constructor parameters using the provided `IServiceProvider`. Any public settable class Property will also be populated in the same manner.

## Service Scopes

Interaction Service has built-in support for scoped service types. Scoped lifetime services are instantiated once per command execution. Including the Preconditon checks, every module operation is executed within a single service scope (which is sepearate from the global service scope).

> For more in-depth information about service lifetimes check out [Microsoft Docs](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-5.0#service-lifetimes-1).

+ 0
- 360
docs/guides/interactions_framework/intro.md View File

@@ -1,360 +0,0 @@
---
uid: Guides.InteractionsFramework.Intro
title: Introduction to the Interaction Framework
---

# Getting Started

Interaction Service provides an attribute based framework for creating Discord Interaction handlers.

To start using the Interaction Service, you need to create a service instance. Optionally you can provide the `InterctionService` constructor with a `InteractionServiceConfig` to change the services behaviour to suit your needs.

```csharp
...

var commands = new InteractionService(discord);

...
```

## Modules

Attribute based Interaction handlers must be defined within a command module class. Command modules are responsible for executing the Interaction handlers and providing them with the necessary execution info and helper functions.

Command modules are transient objects. A new module instance is created before a command execution starts then it will be disposed right after the method returns.

Every module class must:

- be public
- inherit `InteractionModuleBase`

Optionally you can override the included :

- OnModuleBuilding (executed after the module is built)
- BeforeExecute (executed before a command execution starts)
- AfterExecute (executed after a command execution concludes)

methods to configure the modules behaviour.

Every command module exposes a set of helper methods, namely:

- `RespondAsync()` => Respond to the interaction
- `FollowupAsync()` => Create a followup message for an interaction
- `ReplyAsync()` => Send a message to the origin channel of the interaction
- `DeleteOriginalResponseAsync()` => Delete the original interaction response

## Commands

Valid **Interaction Commands** must comply with the following requirements:

| | return type | max parameter count | allowed parameter types | attribute |
|-------------------------------|------------------------------|---------------------|-------------------------------|--------------------------|
|[Slash Command](#slash-commands)| `Task`/`Task<RuntimeResult>` | 25 | any* | `[SlashCommand]` |
|[User Command](#user-commands) | `Task`/`Task<RuntimeResult>` | 1 | Implementations of `IUser` | `[UserCommand]` |
|[Message Command](#message-commands)| `Task`/`Task<RuntimeResult>` | 1 | Implementations of `IMessage` | `[MessageCommand]` |
|[Component Interaction Command](#component-interaction-commands)| `Task`/`Task<RuntimeResult>` | inf | `string` or `string[]` | `[ComponentInteraction]` |
|[Autocomplete Command](#autocomplete-commands)| `Task`/`Task<RuntimeResult>` | - | - | `[AutocompleteCommand]`|

> [!NOTE]
> a `TypeConverter` that is capable of parsing type in question must be registered to the `InteractionService` instance.

You should avoid using long running code in your command module. Depending on your setup, long running code may block the Gateway thread of your bot, interrupting its connection to Discord.

### Slash Commands

Slash Commands are created using the `[SlashCommandAttribute]`. Every Slash Command must declare a name and a description. You can check Discords **Application Command Naming Guidelines** [here](https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-naming).

```csharp
[SlashCommand("echo", "Echo an input")]
public async Task Echo(string input)
{
await RespondAsync(input);
}
```

#### Parameters

Slash Commands can have up to 25 method parameters. You must name your parameters in accordance with [Discords Naming Guidelines](https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-naming). Interaction Service 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.*
| interface | Channel Type |
|---------------------|-------------------------------|
| `IStageChannel` | Stage Channels |
| `IVoiceChannel` | Voice Channels |
| `IDMChannel` | DM Channels |
| `IGroupChannel` | Group Channels |
| `ICategory Channel` | Category Channels |
| `INewsChannel` | News Channels |
| `IThreadChannel` | Public, Private, News Threads |
| `ITextChannel` | Text Channels |

---

##### Optional Parameters

Parameters with default values (ie. `int count = 0`) will be displayed as optional parameters on Discord Client.

##### Parameter Summary

By using the `[SummaryAttribute]` you can customize the displayed name and description of a parameter

```csharp
[Summary(description: "this is a parameter description")] string input
```

##### Parameter Choices

`[ChoiceAttribute]` can be used to add choices to a parameter.

```csharp
[SlashCommand("blep", "Send a random adorable animal photo")]
public async Task Blep([Choice("Dog","dog"), Choice("Cat", "cat"), Choice("Penguin", "penguin")] string animal)
{
...
}
```

In most cases, instead of relying on this attribute, you should use an `Enum` to create multiple choice parameters. Ex.

```csharp
public enum Animal
{
Cat,
Dog,
Penguin
}

[SlashCommand("blep", "Send a random adorable animal photo")]
public async Task Blep(Animal animal)
{
...
}
```

This Slash Command will be displayed exactly the same as the previous example.

##### Channel Types

Channel types for an `IChannel` parameter can also be restricted using the `[ChannelTypesAttribute]`.

```csharp
[SlashCommand("name", "Description")]
public async Task Command([ChannelTypes(ChannelType.Stage, ChannelType.Text)]IChannel channel)
{
...
}
```

In this case, user can only input Stage Channels and Text Channels to this parameter.

##### Autocomplete

You can enable Autocomple Interactions for a Slash Command parameter using the `[AutocompleteAttribute]`. To handle the Autocomplete Interactions raised by this parameter you can either create [Autocomplete Commands](#autocomplete-commands) or you can opt to use the [Autocompleters Pattern](./autocompleters)

##### Min/Max Value

You can specify the permitted max/min value for a number type parameter using the `[MaxValueAttribute]` and `[MinValueAttribute]`.

### User Commands

A valid User Command must have the following structure:

```csharp
[UserCommand("Say Hello")]
public async Task SayHello(IUser user)
{
...
}
```

User commands can only have one parameter and its type must be an implementation of `IUser`.

### Message Commands

A valid Message Command must have the following structure:

```csharp
[MessageCommand("Bookmark")]
public async Task Bookmark(IMessage message)
{
...
}
```

Message commands can only have one parameter and its type must be an implementation of `IMessage`.

### Component Interaction Commands

Component Interaction Commands are used to handle interactions that originate from **Discord Message Component**s. This pattern is particularly useful if you will be reusing a set a **Custom ID**s.

```csharp
[ComponentInteraction("custom_id")]
public async Task RoleSelection()
{
...
}
```

Component Interaction Commands support wild card matching, by default `*` character can be used to create a wild card pattern. Interaction Service will use lazy matching to capture the words corresponding to the wild card character. And the captured words will be passed on to the command method in the same order they were captured.

*Ex.*

If Interaction Service recieves a component interaction with **player:play,rickroll** custom id, `op` will be *play* and `name` will be *rickroll*

```csharp
[ComponentInteraction("player:*,*")]
public async Task Play(string op, string name)
{
...
}
```

You may use as many wild card characters as you want.

#### Select Menus

Unlike button interactions, select menu interactions also contain the values of the selected menu items. In this case, you should structure your method to accept a string array.

```csharp
[ComponentInteraction("role_selection")]
public async Task RoleSelection(string[] selectedRoles)
{
...
}
```

Wild card pattern can also be used to match select menu custom ids but remember that the array containing the select menu values should be the last parameter.

```csharp
[ComponentInteraction("role_selection_*")]
public async Task RoleSelection(string id, string[] selectedRoles)
{
...
}
```

### Autocomplete Commands

Autocomplete commands must be parameterless methods. A valid Autocomplete command must have the following structure:

```csharp
[AutocompleteCommand("command_name", "parameter_name")]
public async Task Autocomplete()
{
IEnumerable<AutocompleteResult> results;

...

await (Context.Interaction as SocketAutocompleteInteraction).RespondAsync(results);
}
```

Alternatively, you can use the *Autocompleters* 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`.

> Context type must be consistent throughout the project, or you will run into issues during runtime.

Interaction Service ships with 4 different kinds of `InteractionContext`s:

1. InteractionContext: A bare-bones execution context consisting of only implementation netural 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 `IInteracitonContext` 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.

Ex.
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`.

```csharp
discordClient.ButtonExecuted += async (interaction) =>
{
var ctx = new SocketInteractionContext<SocketMessageComponent>(discordClient, interaction);
await interactionService.ExecuteAsync(ctx, serviceProvider);
};

public class MessageComponentModule : InteractionModuleBase<SocketInteractionContext<SocketMessageComponent>>
{
[ComponentInteraction("custom_id")]
public async Command()
{
Context.Interaction.UpdateAsync(...);
}
}
```

## Loading Modules

Interaction Service can automatically discover and load modules that inherit `InteractionModuleBase` from an `Assembly`. Call `InteractionService.AddModulesAsync()` to use this functionality.

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, check out [Dependency Injection](./dependency-injection.md)

## 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.

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:

| Method | Mean | Error | StdDev |
|----------------- |----------:|---------:|---------:|
| ReflectionInvoke | 225.93 ns | 4.522 ns | 7.040 ns |
| CompiledLambda | 48.79 ns | 0.981 ns | 1.276 ns |

## Registering Commands to Discord

Application commands loaded to the Interaction Service can be registered to Discord using a number of different methods. In most cases `RegisterCommandsGloballyAsync()` and `RegisterCommandsToGuildAsync()` are the methods to use. Command registration methods can only be used after the gateway client is ready or the rest client is logged in.

In debug environment, since Global commands can take up to 1 hour to register/update, you should register your commands to a test guild for your changes to take effect immediately. You can use the preprocessor directives to create a simple logic for registering commands:

```csharp
#if DEBUG
await interactionService.RegisterCommandsToGuildAsync(<test_guild_id>);
#else
await interactionService.RegisterCommandsGloballyAsync();
#endif
```

+ 0
- 73
docs/guides/interactions_framework/post_execution.md View File

@@ -1,73 +0,0 @@
---
uid: Guides.InteractionsFramework.PostEx
title: Post-Execution
---

# Post-Execution Logic

Interaction Service uses `IResult`s to provide information about the state of command execution. These can be used to log internal exceptions or provide some insight to the command user.

If you are running your commands using `RunMode.Sync` these command results can be retrieved from the return value of `InteractionService.ExecuteCommandAsync()` method or by registering delegates to Interaction Service events.

If you are using the `RunMode.Async` to run your commands, you must use the Interaction Service events to get the execution results. When using `RunMode.Async`, `InteractionService.ExecuteCommandAsync()` will always return a successful result.

## Results

Interaction Result come in a handful of different flavours:

1. `AutocompletionResult`: returned by Autocompleters
2. `ExecuteResult`: contains the result of method body execution process
3. `PreconditionGroupResult`: returned by Precondition groups
4. `PreconditionResult`: returned by preconditions
5. `RuntimeResult`: a user implementable result for returning user defined results
6. `SearchResult`: returned by command lookup map
7. `TypeConverterResult`: returned by TypeConverters

You can either use the `IResult.Error` property of an Interaction result or create type check for the afformentioned result types to branch out your post-execution logic to handle different situations.

## CommandExecuted Events

Every time a command gets executed, Interaction Service raises a *CommandExecuted event. These events can be used to create a post-execution pipeline.

```csharp
interactionService.SlashCommandExecuted += SlashCommandExecuted;

async Task SlashCommandExecuted (SlashCommandInfo arg1, Discord.IInteractionContext arg2, IResult arg3)
{
if (!arg3.IsSuccess)
{
switch (arg3.Error)
{
case InteractionCommandError.UnmetPrecondition:
await arg2.Interaction.RespondAsync($"Unmet Precondition: {arg3.ErrorReason}");
break;
case InteractionCommandError.UnknownCommand:
await arg2.Interaction.RespondAsync("Unknown command");
break;
case InteractionCommandError.BadArgs:
await arg2.Interaction.RespondAsync("Invalid number or arguments");
break;
case InteractionCommandError.Exception:
await arg2.Interaction.RespondAsync($"Command exception:{arg3.ErrorReason}");
break;
case InteractionCommandError.Unsuccessful:
await arg2.Interaction.RespondAsync("Command could not be executed");
break;
default:
break;
}
}
}
```

## Log Event

InteractionService regularly outputs information about the occuring events to keep the developer informed.

## Runtime Result

Interaction commands allow you to return `Task<RuntimeResult>` to pass on additional information about the command execution process back to your post-execution logic.

Custom `RuntimeResult` classes can be created by inheriting the base `RuntimeResult` class.

If command execution process reaches the method body of the command and no exceptions are thrown during the execution of the method body, `RuntimeResult` returned by your command will be accessible by casting/type-checking the `IResult` parameter of the *CommandExecuted event delegate.

+ 0
- 8
docs/guides/interactions_framework/preconditions.md View File

@@ -1,8 +0,0 @@
---
uid: Guides.InteractionsFramework.Preconditions
title: Preconditions
---

# Preconditions

Preconditions in Interaction Service work exactly the same as they do in ***Discord.Net.Commands***. For more information, check out [Preconditions](../commands/preconditions.md)

+ 0
- 130
docs/guides/interactions_framework/typeconverters.md View File

@@ -1,130 +0,0 @@
---
uid: Guides.InteractionsFramework.TypeConverters
title: Type Converters
---

# TypeConverters

TypeConverters are responsible for registering command parameters to Discord and parsing the user inputs into method parameters.

By default, TypeConverters for the following types are provided with `Discord.Net.Interactions` library.

- 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`
- `DateTime`
- `TimeSpan`

## Creating TypeConverters

Depending on your needs, there are two types of `TypeConverter`s you can create:

- Concrete type
- Generic type

A valid converter must inherit `TypeConverter` base type. And override the abstract base methods.

### CanConvertTo() Method

This method is used by Interaction Service to search for alternative Type Converters.

Interaction Services determines the most suitable `TypeConverter` for a parameter type in the following order:

1. It searches for a `TypeConverter` that is registered to specifically target that parameter type
2. It searches for a generic `TypeConverter` with a matching type constraint. If there are more multiple matches, the one whose type constraint is the most specialized will be chosen.
3. It searches for a `TypeConverter` that returns `true` when its `CanConvertTo()` method is invoked for thaty parameter type.

> Alternatively, you can use the generic variant (`TypeConverter<T>`) of the `TypeConverter` base class which implements the following method body for `CanConvertTo()` method

```csharp
public sealed override bool CanConvertTo (Type type) =>
typeof(T).IsAssignableFrom(type);
```

### GetDiscordType() Method

This method is used by Interaction Service to determine the [Discord Application Command Option type](https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-type) of a parameter type.

### ReadAsync() Method

This method is used by Interaction Service to parse the user input. This method should return `TypeConverterResult.FromSuccess` if the parsing operation is successful, otherwise it should return `TypeConverterResult.FromError`. The inner logic of this method is totally up to you, however you should avoid using long running code.

### Write() Method

This method is used to configure the **Discord Application Command Option** before it gets registered to Discord. Command Option is configured by modifying the `ApplicationCommandOptionProperties` instance.

The default parameter building pipeline is isolated and will not be disturbed by the `TypeConverter` workflow. But changes made in this method will override the values generated by the Interaction Service for a **Discord Application Command Option**.

---

### Example Enum TypeConverter

```csharp
internal sealed class EnumConverter<T> : TypeConverter<T> where T : struct, Enum
{
public override ApplicationCommandOptionType GetDiscordType ( ) => ApplicationCommandOptionType.String;

public override Task<TypeConverterResult> ReadAsync (IInteractionCommandContext context, SocketSlashCommandDataOption option, IServiceProvider services)
{
if (Enum.TryParse<T>((string)option.Value, out var result))
return Task.FromResult(TypeConverterResult.FromSuccess(result));
else
return Task.FromResult(TypeConverterResult.FromError(InteractionCommandError.ConvertFailed, $"Value {option.Value} cannot be converted to {nameof(T)}"));
}

public override void Write (ApplicationCommandOptionProperties properties, IParameterInfo parameterInfo)
{
var names = Enum.GetNames(typeof(T));
if (names.Length <= 25)
{
var choices = new List<ApplicationCommandOptionChoiceProperties>();

foreach (var name in names)
choices.Add(new ApplicationCommandOptionChoiceProperties
{
Name = name,
Value = name
});

properties.Choices = choices;
}
}
}
```

---

## Registering TypeConverters

> TypeConverters must be registered prior to module discovery. If Interaction Service encounters a parameter type that doesn't belong to any of the registered `TypeConverter`s during this phase, it will throw an exception.

### Concrete TypeConverters

Registering Concrete TypeConverters are as simple as creating an instance of your custom converter and invoking `AddTypeConverter()` method.

```csharp
interactionService.AddTypeConverter<string[]>(new StringArrayConverter());
```

### Generic TypeConverters

To register a generic TypeConverter, you need to invoke the `AddGenericTypeConverter()` method of the Interaction Service class. You need to pass the type of your `TypeConverter` and a target base type to this method.

For instance, to register the previously mentioned [Example Enum Converter](#example-enum-converter) the following can be used:

```csharp
interactionService.AddGenericTypeConverter<Enum>(typeof(EnumConverter<>));
```

Interaction service checks if the target base type satisfies the type constraints of the Generic TypeConverter class.

> Dependencies of Generic TypeConverters are also resolved using the Dependency Injection pattern.

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save