Browse Source

Merge branch 'dev' into dev

pull/1888/head
Quin Lynch GitHub 3 years ago
parent
commit
216809ea81
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
100 changed files with 2510 additions and 250 deletions
  1. +115
    -2
      CHANGELOG.md
  2. +3
    -3
      CONTRIBUTING.md
  3. +48
    -35
      Discord.Net.sln
  4. +1
    -1
      LICENSE
  5. +15
    -1
      README.md
  6. +7
    -0
      azure/build.yml
  7. +1
    -0
      azure/deploy.yml
  8. +2
    -2
      docs/_overwrites/Commands/ICommandContext.Inclusion.md
  9. BIN
      docs/_template/description-generator/plugins/DocFX.Plugin.DescriptionGenerator.dll
  10. +8
    -0
      docs/_template/description-generator/plugins/LICENSE
  11. BIN
      docs/_template/last-modified/plugins/LastModifiedPostProcessor.dll
  12. BIN
      docs/_template/last-modified/plugins/LibGit2Sharp.dll
  13. +2
    -2
      docs/_template/last-modified/plugins/LibGit2Sharp.dll.config
  14. BIN
      docs/_template/last-modified/plugins/lib/linux-arm/libgit2-6777db8.so
  15. BIN
      docs/_template/last-modified/plugins/lib/linux-arm64/libgit2-6777db8.so
  16. BIN
      docs/_template/last-modified/plugins/lib/linux-musl-x64/libgit2-6777db8.so
  17. BIN
      docs/_template/last-modified/plugins/lib/linux-x64/libgit2-6777db8.so
  18. BIN
      docs/_template/last-modified/plugins/lib/osx/libgit2-6777db8.dylib
  19. BIN
      docs/_template/last-modified/plugins/lib/win32/x64/git2-6777db8.dll
  20. BIN
      docs/_template/last-modified/plugins/lib/win32/x86/git2-6777db8.dll
  21. +1
    -1
      docs/_template/light-dark-theme/partials/head.tmpl.partial
  22. +37
    -30
      docs/docfx.json
  23. +21
    -21
      docs/faq/basics/basic-operations.md
  24. +5
    -3
      docs/faq/basics/client-basics.md
  25. +1
    -1
      docs/faq/basics/getting-started.md
  26. BIN
      docs/faq/basics/images/scope.png
  27. +84
    -0
      docs/faq/basics/interactions.md
  28. +21
    -0
      docs/faq/basics/samples/registerint.cs
  29. +1
    -1
      docs/faq/commands/dependency-injection.md
  30. +3
    -3
      docs/faq/commands/general.md
  31. +52
    -0
      docs/faq/commands/interaction.md
  32. +44
    -4
      docs/faq/misc/glossary.md
  33. +2
    -2
      docs/faq/misc/legacy.md
  34. +5
    -1
      docs/faq/toc.yml
  35. +2
    -3
      docs/guides/concepts/entities.md
  36. +49
    -0
      docs/guides/concepts/ratelimits.md
  37. +5
    -3
      docs/guides/emoji/emoji.md
  38. BIN
      docs/guides/getting_started/images/nightlies-vs-note.png
  39. BIN
      docs/guides/getting_started/images/nightlies-vs-step1.png
  40. BIN
      docs/guides/getting_started/images/nightlies-vs-step2.png
  41. BIN
      docs/guides/getting_started/images/nightlies-vs-step4.png
  42. +36
    -34
      docs/guides/getting_started/installing.md
  43. +30
    -0
      docs/guides/getting_started/labs.md
  44. +0
    -97
      docs/guides/getting_started/nightlies.md
  45. +31
    -0
      docs/guides/guild_events/creating-guild-events.md
  46. +16
    -0
      docs/guides/guild_events/getting-event-users.md
  47. +41
    -0
      docs/guides/guild_events/intro.md
  48. +23
    -0
      docs/guides/guild_events/modifying-events.md
  49. +110
    -0
      docs/guides/int_basics/application-commands/context-menu-commands/creating-context-menu-commands.md
  50. +33
    -0
      docs/guides/int_basics/application-commands/context-menu-commands/receiving-context-menu-command-events.md
  51. +51
    -0
      docs/guides/int_basics/application-commands/intro.md
  52. +40
    -0
      docs/guides/int_basics/application-commands/slash-commands/bulk-overwrite-of-global-slash-commands.md
  53. +85
    -0
      docs/guides/int_basics/application-commands/slash-commands/choice-slash-command.md
  54. +98
    -0
      docs/guides/int_basics/application-commands/slash-commands/creating-slash-commands.md
  55. BIN
      docs/guides/int_basics/application-commands/slash-commands/images/ephemeral1.png
  56. BIN
      docs/guides/int_basics/application-commands/slash-commands/images/feedback1.png
  57. BIN
      docs/guides/int_basics/application-commands/slash-commands/images/feedback2.png
  58. BIN
      docs/guides/int_basics/application-commands/slash-commands/images/listroles1.png
  59. BIN
      docs/guides/int_basics/application-commands/slash-commands/images/listroles2.png
  60. BIN
      docs/guides/int_basics/application-commands/slash-commands/images/oauth.png
  61. BIN
      docs/guides/int_basics/application-commands/slash-commands/images/settings1.png
  62. BIN
      docs/guides/int_basics/application-commands/slash-commands/images/settings2.png
  63. BIN
      docs/guides/int_basics/application-commands/slash-commands/images/settings3.png
  64. BIN
      docs/guides/int_basics/application-commands/slash-commands/images/slashcommand1.png
  65. BIN
      docs/guides/int_basics/application-commands/slash-commands/images/slashcommand2.png
  66. +102
    -0
      docs/guides/int_basics/application-commands/slash-commands/parameters.md
  67. +23
    -0
      docs/guides/int_basics/application-commands/slash-commands/responding-ephemerally.md
  68. +40
    -0
      docs/guides/int_basics/application-commands/slash-commands/responding-to-slash-commands.md
  69. +219
    -0
      docs/guides/int_basics/application-commands/slash-commands/subcommands.md
  70. +10
    -0
      docs/guides/int_basics/intro.md
  71. +87
    -0
      docs/guides/int_basics/message-components/advanced.md
  72. +45
    -0
      docs/guides/int_basics/message-components/buttons-in-depth.md
  73. BIN
      docs/guides/int_basics/message-components/images/image1.png
  74. BIN
      docs/guides/int_basics/message-components/images/image2.png
  75. BIN
      docs/guides/int_basics/message-components/images/image3.png
  76. BIN
      docs/guides/int_basics/message-components/images/image4.png
  77. BIN
      docs/guides/int_basics/message-components/images/image5.png
  78. BIN
      docs/guides/int_basics/message-components/images/image6.png
  79. +66
    -0
      docs/guides/int_basics/message-components/intro.md
  80. +37
    -0
      docs/guides/int_basics/message-components/responding-to-buttons.md
  81. +76
    -0
      docs/guides/int_basics/message-components/select-menus.md
  82. +47
    -0
      docs/guides/int_framework/autocompletion.md
  83. +13
    -0
      docs/guides/int_framework/dependency-injection.md
  84. +353
    -0
      docs/guides/int_framework/intro.md
  85. +69
    -0
      docs/guides/int_framework/post-execution.md
  86. +77
    -0
      docs/guides/int_framework/preconditions.md
  87. +9
    -0
      docs/guides/int_framework/samples/intro/autocomplete.cs
  88. +5
    -0
      docs/guides/int_framework/samples/intro/button.cs
  89. +5
    -0
      docs/guides/int_framework/samples/intro/channelattribute.cs
  90. +14
    -0
      docs/guides/int_framework/samples/intro/context.cs
  91. +11
    -0
      docs/guides/int_framework/samples/intro/dropdown.cs
  92. +21
    -0
      docs/guides/int_framework/samples/intro/groupattribute.cs
  93. +5
    -0
      docs/guides/int_framework/samples/intro/messagecommand.cs
  94. +5
    -0
      docs/guides/int_framework/samples/intro/registering.cs
  95. +5
    -0
      docs/guides/int_framework/samples/intro/slashcommand.cs
  96. +1
    -0
      docs/guides/int_framework/samples/intro/summaryattribute.cs
  97. +5
    -0
      docs/guides/int_framework/samples/intro/usercommand.cs
  98. +28
    -0
      docs/guides/int_framework/samples/postexecution/error_review.cs
  99. +0
    -0
      docs/guides/int_framework/samples/preconditions/group_precondition.cs
  100. +3
    -0
      docs/guides/int_framework/samples/preconditions/precondition_usage.cs

+ 115
- 2
CHANGELOG.md View File

@@ -1,7 +1,86 @@
# Changelog

## [3.0.0] - 2021-12-13

### Added

- #1152 Add characters commonly use in links to Sanitize (b9274d1)
- #1518 Add default nullable enum typereader (f7a07ae)
- #1700 Added Implementation of ValidateAndGetBestMatch (3cd9f39)
- #1767 Add method to clear guild user cache (19a66bf)
- #1847 Bump API version to 9 (06a64b7)
- #1848 Remove obsolete sync voice regions methods and properties (ed8e573)
- #1851 Remove DM cache and fix references (7a201e9)
- #1860 Remove /users/@me call for socket and rework sharded client a bit (384ad85)
- #1863 Change GuildMemberUpdate before state to cacheable (c2e87f5)
- #1666 Added negative TimeSpan handling (6abdfcb)
- #1861 Add MaxBitrate to the interface (e0dbe7c)
- #1865 Add null check to AllowedMentions.ToModel() (3cb662f)
- #1879 Add Name property to Teams (c5b4b64)
- #1890 Add default avatar to WithAuthor extension (c200861)
- #1896 IVoiceChannel implements IMentionable (3395700)
- #1923 Add Interaction Support (933ea42)
- #1923 Add Application commands (933ea42)
- #1923 Add Message Components (933ea42)
- #1923 Add Thread Channels (933ea42)
- #1923 Add Stage Channels (933ea42)
- #1923 Add Guild Events (933ea42)
- #1923 Revamped Stickers (933ea42)
- #1923 Add TimestampTag (933ea42)
- #1923 Add name property to teams (933ea42)
- #1923 Add url validation on embeds (933ea42)
- #1923 Add NsfwLevel to Guilds (933ea42)
- #1923 Add helpers to Emoji for parsing (933ea42)
- #1923 Add banner and accent color to guild users (933ea42)
- #1923 Add RatelimitCallback to RequestOptions (933ea42)
- #1923 Add Emoji to roles (933ea42)
- #1923 Add UseInteractionSnowflakeDate to config (933ea42)
- #1923 Add checks for gateway intent in some methods (933ea42)
- #1923 Add SendFilesAsync to channels (933ea42)
- #1923 Add Attachments property to MessageProperties (933ea42)
- #1942 Add multi-file upload to webhooks (bc440ab)
- #1943 Handle bidirectional usernames (10afd96)
- #1945 Updated socket presence and add new presence event (9d6dc62)
- #1948 Added warnings on invalid gateway intents (51e06e9)
- #1949 Add default application games (82276e3)
- #1950 Add custom setter to Group property of ModuleBuilder to automatically invoke AddAliases (ba656e9)
- #1958 Add Discord.Interactions framework (aa6bb5e)

### Fixed

- #1832 Grab correct Uses value for vanity urls (8ed8714)
- #1849 Remove obsolete methods and properties (70aab6c)
- #1850 Create DM channel with id and author alone (95bae78)
- #1853 Fire GuildMemberUpdated without cached user (d176fef)
- #1854 Gateway events for DMs (a7ff6ce)
- #1858 MessageUpdated without author (8b29e0f)
- #1859 Fix missing AddRef and related (de7f9b5)
- #1862 Message update without author (fabe034)
- #1864 ApiClient.CurrentUser being null (08507c0)
- #1871 Fix empty role list if not present (f47001a)
- #1872 Connection deadlock when trying to Send and Disconnect (97d90b9)
- #1873 Remove OperationCanceledException handling in connecting logic (7cf8499)
- #1876 Fix SocketMessage type always being default (ac52a11)
- #1877 Fix RestMessage type always being default (22bb1b0)
- #1886 Change embed description max length to 4096 (8349cd7)
- #1923 Fix ReactionAdded cached parameters (933ea42)
- #1923 Fixed GuildMemberUpdated cached parameters (933ea42)
- #1923 Fixed UserIsTypeing cached parameters (933ea42)
- #1941 Fix Emote.TryParse (900c1f4)
- #1946 Fix NRE when adding parameters in ModuleBuilders (143ca6d)
- #1947 ShardedClient's CurrentUser interface property being null (d5f5ae1)

### Misc

- #1852 Internal change to GetOrCreateUser (dfaaa21)
- #1923 Make Hierarchy a IGuildUser property (933ea42)
- #1923 Fixed gateway serialization to include nulls for API v9 (933ea42)
- #1923 Removed error log for gateway reconnects (933ea42)

## [2.4.0] - 2021-05-22

### Added

- #1726 Add stickers (91a9063)
- #1753 Webhook message edit & delete functionality (f67cd8e)
- #1757 Add ability to add/remove roles by id (4c9910c)
@@ -12,15 +91,19 @@
- #1844 Add Discord Certified Moderator user flag (4b8d444)

### Fixed

- #1486 Add type reader when entity type reader exists (c46daaa)
- #1835 Cached message emoji cleanup at MESSAGE_REACTION_REMOVE_EMOJI (8afef82)

### Misc

- #1778 Remove URI check from EmbedBuilder (25b04c4)
- #1800 Fix spelling in SnowflakeUtils.FromSnowflake (6aff419)

## [2.3.1] - 2021-03-10

### Fixed

- #1761 Deadlock in DiscordShardedClient when Ready is never received (73e5cc2)
- #1773 Private methods aren't added as commands (0fc713a)
- #1780 NullReferenceException in pin/unpin audit logs (f794163)
@@ -29,10 +112,13 @@
- #1794 Audit log UserId can be null (d41aeee)

### Misc

- #1774 Add remark regarding CustomStatus as the activity (51b7afe)

## [2.3.0] - 2021-01-28

### Added

- #1491 Add INVITE_CREATE and INVITE_DELETE events (1ab670b)
- #1520 Support reading multiple activities (421a0c1)
- #1521 Allow for inherited commands in modules (a51cdf6)
@@ -57,6 +143,7 @@
- #1690 Add max bitrate value to SocketGuild (aacfea0)

### Fixed

- #1244 Missing AddReactions permission for DM channels. (e40ca4a)
- #1469 unsupported property causes an exception (468f826)
- #1525 AllowedMentions and AllowedMentionTypes (3325031)
@@ -99,6 +186,7 @@
- Missing MessageReference when sending files (2095701)

### Misc

- #1545 MutualGuilds optimization (323a677)
- #1551 Update webhook regex to support discord.com (7585789)
- #1556 Add SearchUsersAsync (57880de)
@@ -123,7 +211,9 @@
- Move bulk deletes remarks from <summary> to <remarks> (62539f0)

## [2.2.0] - 2020-04-16

### Added

- #1247 Implement Client Status Support (9da11b4)
- #1310 id overload for RemoveReactionAsync (c88b1da)
- #1319 BOOST (faf23de)
@@ -146,6 +236,7 @@
- suppress messages (cd28892)

### Fixed

- #1318 #1314 Don't parse tags within code blocks (c977f2e)
- #1333 Remove null coalescing on ToEmbedBuilder Color (120c0f7)
- #1337 Fixed attempting to access a non-present optional value (4edda5b)
@@ -161,11 +252,13 @@
- include MessageFlags and SuppressEmbedParams (d6d4429)

### Changed

- #1368 Update ISystemMessage interface to allow reactions (07f4d5f)
- #1417 fix #1415 Re-add support for overwrite permissions for news channels (e627f07)
- use millisecond precision by default (bcb3534)

### Misc

- #1290 Split Unit and Integration tests into separate projects (a797be9)
- #1328 Fix #1327 Color.ToString returns wrong value (1e8aa08)
- #1329 Fix invalid cref values in docs (363d1c6)
@@ -190,14 +283,16 @@
- 2.2.0 (4b602b4)
- target the Process env-var scope (3c6b376)
- fix metapackage build (1794f95)
- copy only _site to docs-static (a8cdadc)
- copy only \_site to docs-static (a8cdadc)
- do not exit on failed robocopy (fd204ee)
- add idn debugger (91aec9f)
- rename IsStream to IsStreaming (dcd9cdd)
- feature (40844b9)

## [2.1.1] - 2019-06-08

### Fixed

- #994: Remainder parameters now ignore character escaping, as there is no reason to escape characters here (2e95c49)
- #1316: `Emote.Equals` now pays no respect to the Name property, since Discord's API does not care about an emote's name (abf3e90)
- #1317: `Emote.GetHashCode` now pays no respect to the Name property, see above (1b54883)
@@ -206,16 +301,20 @@
- News embeds will be processed as `EmbedType.Unknown`, rather than throwing an error and dropping the message (d287ed1)

### Changed

- #1311: Members may now be disconnected from voice channels by passing `null` as `GuildUserProperties.Channel` (fc48c66)
- #1313: `IMessage.Tags` now includes the EveryoneRole on @everyone and @here mentions (1f55f01)
- #1320: The maximum value for setting slow-mode has been updated to 6 hours, per the new API limit (4433ca7)

### Misc

- This library's compatibility with Semantic Versioning has been clarified. Please see the README (4d7de17)
- The depency on System.Interactive.Async has been bumped to `3.2.0` (3e65e03)

## [2.1.0] - 2019-05-18

### Added

- #1236: Bulk deletes (for messages) may now be accessed via the `MessagesBulkDeleted` event (dec353e)
- #1240: OAuth applications utilizing the `guilds.join` scope may now add users to guilds through any client (1356ea9)
- #1255: Message and attachment spoilers may now be set or detected (f3b20b2)
@@ -227,9 +326,11 @@
- `ExclusiveBulkDelete` configuration setting can be used to control bulk delete event behavior (03e6401)

### Removed

- #1294: The `IGuildUser` overload of `EmbedBuilder.WithAuthor` no longer exists (b52b54d)

### Fixed

- #1256: Fetching audit logs no longer raises null reference exceptions when a webhook has been deleted (049b014)
- #1268: Null reference exceptions on `MESSAGE_CREATE` concerning partial member objects no longer occur (377622b)
- #1278: The token validator now internally pads tokens to the proper length (48b327b)
@@ -238,9 +339,11 @@
- Exceptions in event handlers are now always logged (f6e3200)

### Changed

- #1305: Token validation will fail when tokens contain whitespace (bb61efa)

### Misc

- #1241: Added documentation samples for Webhooks (655a006)
- #1243: Happy new year 🎉 (0275f7d)
- #1257: Improved clarity in comments in the command samples (2473619)
@@ -251,16 +354,20 @@
- IDisposableAnalyzers should now be a development dependency (8003ac8)

## [2.0.1] - 2019-01-04

### Fixed

- #1226: Only escape the closing quotation mark of non-remainder strings (65b8c09)
- Commands with async RunModes will now propagate exceptions up to CommandExecuted (497918e)

### Misc

- #1225: Commands sample no longer hooks the log event twice (552f34c)
- #1227: The logo on the docs index page should scale responsively (d39bf6e)
- #1230: Replaced precondition sample on docs (feed4fd)

## [2.0.0] - 2018-12-28

### Added

- #747: `CommandService` now has a `CommandExecuted` event (e991715)
@@ -316,6 +423,7 @@
- Reactions can now be added to messages in bulk (5421df1)

### Fixed

- #742: `DiscordShardedClient#GetGuildFor` will now direct null guilds to Shard 0 (d5e9d6f)
- #743: Various issues with permissions and inheritance of permissions (f996338)
- #755: `IRole.Mention` will correctly tag the @everyone role (6b5a6e7)
@@ -363,6 +471,7 @@
- The default WebSocket will now close correctly (ac389f5)

### Changed

- #731: `IUserMessage#GetReactionUsersAsync` now takes an `IEmote` instead of a `string` (5d7f2fc)
- #744: IAsyncEnumerable has been redesigned (5bbd9bb)
- #777: `IGuild#DefaultChannel` will now resolve the first accessible channel, per changes to Discord (1ffcd4b)
@@ -397,14 +506,15 @@
- The socket client will now use additional fields to fill in member/guild information on messages (8fb2c71)
- The Audio Client now uses Voice WS v3 (9ba38d7)


### Removed

- #790: Redundant overloads for `AddField` removed from EmbedBuilder (479361b)
- #925: RPC is no longer being maintained nor packaged (b30af57)
- #958: Remove support for user tokens (2fd4f56)
- User logins (including selfbots) are no longer supported (fc5adca)

### Misc

- #786: Unit tests for the Color structure (22b969c)
- #828: We now include a contributing guide (cd82a0f)
- #876: We now include a standard editorconfig (5c8c784)
@@ -425,11 +535,13 @@
- Fixed documentation layout for the logo (bafdce4)

## [1.0.2] - 2017-09-09

### Fixed

- Guilds utilizing Channel Categories will no longer crash bots on the `READY` event.

## [1.0.1] - 2017-07-05

### Fixed

- #732: Fixed parameter preconditions not being loaded from class-based modules (b6dcc9e)
@@ -438,4 +550,5 @@
- Fixed module auto-detection for nested modules (d2afb06)

### Changed

- ShardedCommandContext now inherits from SocketCommandContext (8cd99be)

+ 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)

+ 48
- 35
Discord.Net.sln View File

@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28407.52
# Visual Studio Version 17
VisualStudioVersion = 17.1.31903.286
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Core", "src\Discord.Net.Core\Discord.Net.Core.csproj", "{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}"
EndProject
@@ -12,16 +12,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Commands", "src
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.WebSocket", "src\Discord.Net.WebSocket\Discord.Net.WebSocket.csproj", "{688FD1D8-7F01-4539-B2E9-F473C5D699C7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Providers", "Providers", "{B0657AAE-DCC5-4FBF-8E5D-1FB578CF3012}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Providers.WS4Net", "src\Discord.Net.Providers.WS4Net\Discord.Net.Providers.WS4Net.csproj", "{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions", "Extensions", "{CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Webhook", "src\Discord.Net.Webhook\Discord.Net.Webhook.csproj", "{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Analyzers", "src\Discord.Net.Analyzers\Discord.Net.Analyzers.csproj", "{BBA8E7FB-C834-40DC-822F-B112CB7F0140}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{BB59D5B5-E7B0-4BF4-8F82-D14431B2799B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "01_basic_ping_bot", "samples\01_basic_ping_bot\01_basic_ping_bot.csproj", "{F2FF84FB-F6AD-47E5-9EE5-18206CAE136E}"
@@ -40,7 +34,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Analyzers.Tests
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Examples", "src\Discord.Net.Examples\Discord.Net.Examples.csproj", "{47820065-3CFB-401C-ACEA-862BD564A404}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "idn", "samples\idn\idn.csproj", "{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "idn", "samples\idn\idn.csproj", "{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Interactions", "src\Discord.Net.Interactions\Discord.Net.Interactions.csproj", "{137DB209-B357-4EE8-A6EE-4B6127F6DEE9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "04_interactions_framework", "samples\04_interactions_framework\04_interactions_framework.csproj", "{A23E46D2-1610-4AE5-820F-422D34810887}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Analyzers", "src\Discord.Net.Analyzers\Discord.Net.Analyzers.csproj", "{24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -100,18 +100,6 @@ Global
{688FD1D8-7F01-4539-B2E9-F473C5D699C7}.Release|x64.Build.0 = Release|Any CPU
{688FD1D8-7F01-4539-B2E9-F473C5D699C7}.Release|x86.ActiveCfg = Release|Any CPU
{688FD1D8-7F01-4539-B2E9-F473C5D699C7}.Release|x86.Build.0 = Release|Any CPU
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Debug|x64.ActiveCfg = Debug|Any CPU
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Debug|x64.Build.0 = Debug|Any CPU
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Debug|x86.ActiveCfg = Debug|Any CPU
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Debug|x86.Build.0 = Debug|Any CPU
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Release|Any CPU.Build.0 = Release|Any CPU
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Release|x64.ActiveCfg = Release|Any CPU
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Release|x64.Build.0 = Release|Any CPU
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Release|x86.ActiveCfg = Release|Any CPU
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Release|x86.Build.0 = Release|Any CPU
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -124,18 +112,6 @@ Global
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Release|x64.Build.0 = Release|Any CPU
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Release|x86.ActiveCfg = Release|Any CPU
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Release|x86.Build.0 = Release|Any CPU
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Debug|x64.ActiveCfg = Debug|Any CPU
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Debug|x64.Build.0 = Debug|Any CPU
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Debug|x86.ActiveCfg = Debug|Any CPU
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Debug|x86.Build.0 = Debug|Any CPU
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Release|Any CPU.Build.0 = Release|Any CPU
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Release|x64.ActiveCfg = Release|Any CPU
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Release|x64.Build.0 = Release|Any CPU
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Release|x86.ActiveCfg = Release|Any CPU
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Release|x86.Build.0 = Release|Any CPU
{F2FF84FB-F6AD-47E5-9EE5-18206CAE136E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F2FF84FB-F6AD-47E5-9EE5-18206CAE136E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F2FF84FB-F6AD-47E5-9EE5-18206CAE136E}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -232,6 +208,42 @@ Global
{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}.Release|x64.Build.0 = Release|Any CPU
{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}.Release|x86.ActiveCfg = Release|Any CPU
{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}.Release|x86.Build.0 = Release|Any CPU
{137DB209-B357-4EE8-A6EE-4B6127F6DEE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{137DB209-B357-4EE8-A6EE-4B6127F6DEE9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{137DB209-B357-4EE8-A6EE-4B6127F6DEE9}.Debug|x64.ActiveCfg = Debug|Any CPU
{137DB209-B357-4EE8-A6EE-4B6127F6DEE9}.Debug|x64.Build.0 = Debug|Any CPU
{137DB209-B357-4EE8-A6EE-4B6127F6DEE9}.Debug|x86.ActiveCfg = Debug|Any CPU
{137DB209-B357-4EE8-A6EE-4B6127F6DEE9}.Debug|x86.Build.0 = Debug|Any CPU
{137DB209-B357-4EE8-A6EE-4B6127F6DEE9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{137DB209-B357-4EE8-A6EE-4B6127F6DEE9}.Release|Any CPU.Build.0 = Release|Any CPU
{137DB209-B357-4EE8-A6EE-4B6127F6DEE9}.Release|x64.ActiveCfg = Release|Any CPU
{137DB209-B357-4EE8-A6EE-4B6127F6DEE9}.Release|x64.Build.0 = Release|Any CPU
{137DB209-B357-4EE8-A6EE-4B6127F6DEE9}.Release|x86.ActiveCfg = Release|Any CPU
{137DB209-B357-4EE8-A6EE-4B6127F6DEE9}.Release|x86.Build.0 = Release|Any CPU
{A23E46D2-1610-4AE5-820F-422D34810887}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A23E46D2-1610-4AE5-820F-422D34810887}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A23E46D2-1610-4AE5-820F-422D34810887}.Debug|x64.ActiveCfg = Debug|Any CPU
{A23E46D2-1610-4AE5-820F-422D34810887}.Debug|x64.Build.0 = Debug|Any CPU
{A23E46D2-1610-4AE5-820F-422D34810887}.Debug|x86.ActiveCfg = Debug|Any CPU
{A23E46D2-1610-4AE5-820F-422D34810887}.Debug|x86.Build.0 = Debug|Any CPU
{A23E46D2-1610-4AE5-820F-422D34810887}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A23E46D2-1610-4AE5-820F-422D34810887}.Release|Any CPU.Build.0 = Release|Any CPU
{A23E46D2-1610-4AE5-820F-422D34810887}.Release|x64.ActiveCfg = Release|Any CPU
{A23E46D2-1610-4AE5-820F-422D34810887}.Release|x64.Build.0 = Release|Any CPU
{A23E46D2-1610-4AE5-820F-422D34810887}.Release|x86.ActiveCfg = Release|Any CPU
{A23E46D2-1610-4AE5-820F-422D34810887}.Release|x86.Build.0 = Release|Any CPU
{24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}.Debug|x64.ActiveCfg = Debug|Any CPU
{24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}.Debug|x64.Build.0 = Debug|Any CPU
{24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}.Debug|x86.ActiveCfg = Debug|Any CPU
{24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}.Debug|x86.Build.0 = Debug|Any CPU
{24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}.Release|Any CPU.Build.0 = Release|Any CPU
{24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}.Release|x64.ActiveCfg = Release|Any CPU
{24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}.Release|x64.Build.0 = Release|Any CPU
{24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}.Release|x86.ActiveCfg = Release|Any CPU
{24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -240,9 +252,7 @@ Global
{BFC6DC28-0351-4573-926A-D4124244C04F} = {288C363D-A636-4EAE-9AC1-4698B641B26E}
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}
{688FD1D8-7F01-4539-B2E9-F473C5D699C7} = {288C363D-A636-4EAE-9AC1-4698B641B26E}
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7} = {B0657AAE-DCC5-4FBF-8E5D-1FB578CF3012}
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}
{BBA8E7FB-C834-40DC-822F-B112CB7F0140} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}
{F2FF84FB-F6AD-47E5-9EE5-18206CAE136E} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B}
{4E1F1F40-B1DD-40C9-A4B1-A2046A4C9C76} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B}
{9B4C4AFB-3D15-44C6-9E36-12ED625AAA26} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B}
@@ -251,6 +261,9 @@ Global
{FC67057C-E92F-4E1C-98BE-46F839C8AD71} = {C7CF5621-7D36-433B-B337-5A2E3C101A71}
{47820065-3CFB-401C-ACEA-862BD564A404} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B}
{4A03840B-9EBE-47E3-89AB-E0914DF21AFB} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B}
{137DB209-B357-4EE8-A6EE-4B6127F6DEE9} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}
{A23E46D2-1610-4AE5-820F-422D34810887} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B}
{24C231FD-8CF3-444A-9E7C-45C18BAD4A0D} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D2404771-EEC8-45F2-9D71-F3373F6C1495}


+ 1
- 1
LICENSE View File

@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2015-2019 Discord.Net Contributors
Copyright (c) 2015-2021 Discord.Net Contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal


+ 15
- 1
README.md View File

@@ -1,8 +1,9 @@
# Discord.Net

[![NuGet](https://img.shields.io/nuget/vpre/Discord.Net.svg?maxAge=2592000?style=plastic)](https://www.nuget.org/packages/Discord.Net)
[![MyGet](https://img.shields.io/myget/discord-net/vpre/Discord.Net.svg)](https://www.myget.org/feed/Packages/discord-net)
[![Build Status](https://dev.azure.com/discord-net/Discord.Net/_apis/build/status/discord-net.Discord.Net?branchName=dev)](https://dev.azure.com/discord-net/Discord.Net/_build/latest?definitionId=1&branchName=dev)
[![Discord](https://discord.com/api/guilds/81384788765712384/widget.png)](https://discord.gg/jkrBmQR)
[![Discord](https://discord.com/api/guilds/848176216011046962/widget.png)](https://discord.gg/dnet)

An unofficial .NET API Wrapper for the Discord client (https://discord.com).

@@ -12,34 +13,47 @@ An unofficial .NET API Wrapper for the Discord client (https://discord.com).
- [Latest CI repo](https://github.com/discord-net/docs-static)

## Installation

### Stable (NuGet)

Our stable builds available from NuGet through the Discord.Net metapackage:

- [Discord.Net](https://www.nuget.org/packages/Discord.Net/)

The individual components may also be installed from NuGet:

- [Discord.Net.Commands](https://www.nuget.org/packages/Discord.Net.Commands/)
- [Discord.Net.Rest](https://www.nuget.org/packages/Discord.Net.Rest/)
- [Discord.Net.WebSocket](https://www.nuget.org/packages/Discord.Net.WebSocket/)
- [Discord.Net.Webhook](https://www.nuget.org/packages/Discord.Net.Webhook/)

### Unstable (MyGet)

Nightly builds are available through our MyGet feed (`https://www.myget.org/F/discord-net/api/v3/index.json`).

### Unstable (Labs)

Labs builds are avaiable on nuget (`https://www.nuget.org/packages/Discord.Net.Labs/`) and myget (`https://www.myget.org/F/discord-net-labs/api/v3/index.json`).

## Compiling

In order to compile Discord.Net, you require the following:

### Using Visual Studio

- [Visual Studio 2017](https://www.microsoft.com/net/core#windowsvs2017)
- [.NET Core SDK](https://www.microsoft.com/net/download/core)

The .NET Core workload must be selected during Visual Studio installation.

### Using Command Line

- [.NET Core SDK](https://www.microsoft.com/net/download/core)

## Known Issues

### WebSockets (Win7 and earlier)

.NET Core 1.1 does not support WebSockets on Win7 and earlier. This issue has been fixed since the release of .NET Core 2.1. It is recommended to target .NET Core 2.1 or above for your project if you wish to run your bot on legacy platforms; alternatively, you may choose to install the [Discord.Net.Providers.WS4Net](https://www.nuget.org/packages/Discord.Net.Providers.WS4Net/) package.

## Versioning Guarantees


+ 7
- 0
azure/build.yml View File

@@ -1,4 +1,11 @@
steps:
- task: UseDotNet@2
displayName: 'Use .NET Core sdk'
inputs:
packageType: 'sdk'
version: '6.0.x'
includePreviewVersions: true
- task: DotNetCoreCLI@2
inputs:
command: 'restore'


+ 1
- 0
azure/deploy.yml View File

@@ -7,6 +7,7 @@ steps:
dotnet pack "src\Discord.Net.Webhook\Discord.Net.Webhook.csproj" --no-restore --no-build -v minimal -c $(buildConfiguration) -o "$(Build.ArtifactStagingDirectory)" /p:BuildNumber=$(buildNumber) /p:IsTagBuild=$(buildTag)
dotnet pack "src\Discord.Net.Providers.WS4Net\Discord.Net.Providers.WS4Net.csproj" --no-restore --no-build -v minimal -c $(buildConfiguration) -o "$(Build.ArtifactStagingDirectory)" /p:BuildNumber=$(buildNumber) /p:IsTagBuild=$(buildTag)
dotnet pack "src\Discord.Net.Analyzers\Discord.Net.Analyzers.csproj" --no-restore --no-build -v minimal -c $(buildConfiguration) -o "$(Build.ArtifactStagingDirectory)" /p:BuildNumber=$(buildNumber) /p:IsTagBuild=$(buildTag)
dotnet pack "src\Discord.Net.Interactions\Discord.Net.Interactions.csproj" --no-restore --no-build -v minimal -c $(buildConfiguration) -o "$(Build.ArtifactStagingDirectory)" /p:BuildNumber=$(buildNumber) /p:IsTagBuild=$(buildTag)
displayName: Pack projects

- task: NuGetCommand@2


+ 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)]

BIN
docs/_template/description-generator/plugins/DocFX.Plugin.DescriptionGenerator.dll View File


+ 8
- 0
docs/_template/description-generator/plugins/LICENSE View File

@@ -19,3 +19,11 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

==============================================================================

Humanizer (https://github.com/Humanizr/Humanizer)
The MIT License (MIT)
Copyright (c) .NET Foundation and Contributors

==============================================================================

BIN
docs/_template/last-modified/plugins/LastModifiedPostProcessor.dll View File


BIN
docs/_template/last-modified/plugins/LibGit2Sharp.dll View File


+ 2
- 2
docs/_template/last-modified/plugins/LibGit2Sharp.dll.config View File

@@ -1,4 +1,4 @@
<configuration>
<dllmap os="linux" cpu="x86-64" wordsize="64" dll="git2-ef5a385" target="lib/linux-x64/libgit2-ef5a385.so" />
<dllmap os="osx" cpu="x86,x86-64" dll="git2-ef5a385" target="lib/osx/libgit2-ef5a385.dylib" />
<dllmap os="linux" cpu="x86-64" wordsize="64" dll="git2-6777db8" target="lib/linux-x64/libgit2-6777db8.so" />
<dllmap os="osx" cpu="x86,x86-64" dll="git2-6777db8" target="lib/osx/libgit2-6777db8.dylib" />
</configuration>

BIN
docs/_template/last-modified/plugins/lib/linux-arm/libgit2-6777db8.so View File


BIN
docs/_template/last-modified/plugins/lib/linux-arm64/libgit2-6777db8.so View File


BIN
docs/_template/last-modified/plugins/lib/linux-musl-x64/libgit2-6777db8.so View File


BIN
docs/_template/last-modified/plugins/lib/linux-x64/libgit2-6777db8.so View File


BIN
docs/_template/last-modified/plugins/lib/osx/libgit2-6777db8.dylib View File


BIN
docs/_template/last-modified/plugins/lib/win32/x64/git2-6777db8.dll View File


BIN
docs/_template/last-modified/plugins/lib/win32/x86/git2-6777db8.dll View File


+ 1
- 1
docs/_template/light-dark-theme/partials/head.tmpl.partial View File

@@ -10,7 +10,7 @@
<meta property="og:locale" content="en-us">
<meta property="og:type" content="website">
<meta property="og:site_name" content="Discord.Net Docs">
<meta property="og:image" content="https://cdn.jsdelivr.net/gh/discord-net/Discord.Net/docs/marketing/logo/PackageLogo.png">
<meta property="og:image" content="https://raw.githubusercontent.com/Discord-Net/Discord.Net/dev/docs/marketing/logo/PackageLogo.png">
<meta property="og:image:alt" content="Discord.Net Logo">
<meta name="theme-color" content="#995EA7"/>
<meta name="generator" content="docfx {{_docfxVersion}}">


+ 37
- 30
docs/docfx.json View File

@@ -1,19 +1,22 @@
{
"metadata": [{
"src": [{
"src": "../src",
"files": [
"**.csproj"
]
}],
"dest": "api",
"filter": "filterConfig.yml",
"properties": {
"TargetFramework": "netstandard2.0"
"metadata": [
{
"src": [
{
"src": "../src",
"files": ["**.csproj"]
}
],
"dest": "api",
"filter": "filterConfig.yml",
"properties": {
"TargetFramework": "net5.0"
}
}
}],
],
"build": {
"content": [{
"content": [
{
"files": ["api/**.yml", "api/index.md"]
},
{
@@ -27,19 +30,21 @@
},
{
"src": "../",
"files": [ "CHANGELOG.md" ]
"files": ["CHANGELOG.md"]
}
],
"resource": [
{
"files": [
"**/images/**",
"**/samples/**",
"langwordMapping.yml",
"marketing/logo/**.svg",
"marketing/logo/**.png",
"favicon.ico"
]
}
],
"resource": [{
"files": [
"**/images/**",
"**/samples/**",
"langwordMapping.yml",
"marketing/logo/**.svg",
"marketing/logo/**.png",
"favicon.ico"
]
}],
"dest": "_site",
"template": [
"default",
@@ -47,17 +52,19 @@
"_template/last-modified",
"_template/description-generator"
],
"postProcessors": ["ExtractSearchIndex", "LastModifiedPostProcessor", "DescriptionPostProcessor"],
"postProcessors": [
"ExtractSearchIndex",
"LastModifiedPostProcessor",
"DescriptionPostProcessor"
],
"overwrite": "_overwrites/**/**.md",
"globalMetadata": {
"_appTitle": "Discord.Net Documentation",
"_appFooter": "Discord.Net (c) 2015-2020 2.2.0",
"_appFooter": "Discord.Net (c) 2015-2021 3.0.0",
"_enableSearch": true,
"_appLogoPath": "marketing/logo/SVG/Logomark Purple.svg",
"_appFaviconPath": "favicon.ico"
"_appFaviconPath": "favicon.ico"
},
"xrefService": [
"https://xref.docs.microsoft.com/query?uid={uid}"
]
"xrefService": ["https://xref.docs.microsoft.com/query?uid={uid}"]
}
}

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

@@ -13,7 +13,7 @@ language-specific tips when using this library.

> [!WARNING]
> Direct casting (e.g., `(Type)type`) is **the least recommended**
> way of casting, as it *can* throw an [InvalidCastException]
> 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.
@@ -26,7 +26,7 @@ A good and safe casting example:

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

[InvalidCastException]: https://docs.microsoft.com/en-us/dotnet/api/system.invalidcastexception
[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?
@@ -45,15 +45,15 @@ 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*
[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
[glossary]: xref:FAQ.Glossary#message-channels

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

@@ -86,9 +86,9 @@ implement [IEmote] and are valid options.

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

***
---

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

## What is a "preemptive rate limit?"

@@ -107,17 +107,17 @@ reactions.

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

Unfortunately, not at the moment. See [#401](https://github.com/RogueException/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
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

+ 5
- 3
docs/faq/basics/client-basics.md View File

@@ -28,8 +28,8 @@ There are few possible reasons why this may occur.
mind that a token is **different** from a *client secret*.

[TokenType]: xref:Discord.TokenType
[827]: https://github.com/RogueException/Discord.Net/issues/827
[958]: https://github.com/RogueException/Discord.Net/issues/958
[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?
@@ -73,7 +73,9 @@ 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 need to specify the total amount of shards, or shard ids, via [DiscordShardedClient]'s constructors.
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.


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

@@ -79,4 +79,4 @@ Several common ways to do this:
![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.
3. Inspect the roles collection within the guild via your debugger.

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

Before After
Width: 446  |  Height: 317  |  Size: 16 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.

+ 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);
}
}

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

@@ -23,7 +23,7 @@ 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.Commands.DI#usage-in-modules).
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.



+ 3
- 3
docs/faq/commands/general.md View File

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

# Command-related Questions
# Chat Command-related Questions

In the following section, you will find commonly asked questions and
answered regarding general command usage when using @Discord.Commands.
@@ -144,4 +144,4 @@ For #4, exceptions are caught in [CommandService.Log] event under
[LogMessage.Exception]: xref:Discord.LogMessage.Exception*
[ExecuteResult.Exception]: xref:Discord.Commands.ExecuteResult.Exception*
[CommandException]: xref:Discord.Commands.CommandException
[IResult]: xref:Discord.Commands.IResult
[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

+ 44
- 4
docs/faq/misc/glossary.md View File

@@ -26,11 +26,11 @@ channels, and are often referred to as "servers".
## Channel Types

### Message Channels
* A **Text Channel** ([ITextChannel]) is a message channel from a
Guild.
* 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.
* 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.
@@ -39,11 +39,15 @@ Group.
* 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
@@ -53,6 +57,33 @@ exist under a category.
[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

@@ -64,6 +95,15 @@ exist under a category.
[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.


+ 2
- 2
docs/faq/misc/legacy.md View File

@@ -18,7 +18,7 @@ their breaking nature.

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

[release tag]: https://github.com/RogueException/Discord.Net/releases
[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?

@@ -26,4 +26,4 @@ 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
[DependencyInjection]: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection

+ 5
- 1
docs/faq/toc.yml View File

@@ -6,10 +6,14 @@
topicUid: FAQ.Basics.BasicOp
- name: Client Basics
topicUid: FAQ.Basics.ClientBasics
- name: Interactions
topicUid: FAQ.Basics.InteractionBasics
- name: Commands
items:
- name: General
- name: String commands
topicUid: FAQ.Commands.General
- name: Interaction commands
topicUid: FAQ.Commands.Interactions
- name: Dependency Injection
topicUid: FAQ.Commands.DI
- name: Glossary


+ 2
- 3
docs/guides/concepts/entities.md View File

@@ -31,8 +31,7 @@ But that doesn't mean a message _can't_ come from a
retrieve information about a guild from a message entity, you will
need to cast its channel object to a `SocketTextChannel`.

You can find out various types of entities in the @FAQ.Misc.Glossary
page.
You can find out various types of entities in the [Glossary page.](xref:FAQ.Glossary)

## Navigation

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

## Sample

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

+ 49
- 0
docs/guides/concepts/ratelimits.md View File

@@ -0,0 +1,49 @@
# Ratelimits

Ratelimits are a core concept of any API - Discords API is no exception. each verified library must follow the ratelimit guidelines.

### Using the ratelimit callback

There is a new property within `RequestOptions` called RatelimitCallback. This callback is called when a request is made via the rest api. The callback is called with a `IRateLimitInfo` parameter:

| Name | Type | Description |
| ---------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| IsGlobal | bool | Whether or not this ratelimit info is global. |
| Limit | int? | The number of requests that can be made. |
| Remaining | int? | The number of remaining requests that can be made. |
| RetryAfter | int? | The total time (in seconds) of when the current rate limit bucket will reset. Can have decimals to match previous millisecond ratelimit precision. |
| Reset | DateTimeOffset? | The time at which the rate limit resets. |
| ResetAfter | TimeSpan? | The absolute time when this ratelimit resets. |
| Bucket | string | A unique string denoting the rate limit being encountered (non-inclusive of major parameters in the route path). |
| Lag | TimeSpan? | The amount of lag for the request. This is used to denote the precise time of when the ratelimit expires. |
| Endpoint | string | The endpoint that this ratelimit info came from. |

Let's set up a ratelimit callback that will print out the ratelimit info to the console.

```cs
public async Task MyRatelimitCallback(IRateLimitInfo info)
{
Console.WriteLine($"{info.IsGlobal} {info.Limit} {info.Remaining} {info.RetryAfter} {info.Reset} {info.ResetAfter} {info.Bucket} {info.Lag} {info.Endpoint}");
}
```

Let's use this callback in a send message function

```cs
[Command("ping")]
public async Task ping()
{
var options = new RequestOptions()
{
RatelimitCallback = MyRatelimitCallback
};

await Context.Channel.SendMessageAsync("Pong!", options: options);
}
```

Running this produces the following output:

```
False 5 4 2021-09-09 3:48:14 AM +00:00 00:00:05 a06de0de4a08126315431cc0c55ee3dc 00:00:00.9891364 channels/848511736872828929/messages
```

+ 5
- 3
docs/guides/emoji/emoji.md View File

@@ -46,14 +46,16 @@ form; this can be obtained in several different ways.
### Emoji Declaration

After obtaining the Unicode representation of the emoji, you may
create the @Discord.Emoji object by passing the string into its
create the @Discord.Emoji object by passing the string with unicode into its
constructor (e.g. `new Emoji("👌");` or `new Emoji("\uD83D\uDC4C");`).

Your method of declaring an @Discord.Emoji should look similar to
this:

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

Also you can use `Emoji.Parse()` or `Emoji.TryParse()` methods
for parsing emojis from strings like `:heart:`, `<3` or `❤`.

[FileFormat.Info]: https://www.fileformat.info/info/emoji/list.htm

## Emote
@@ -97,4 +99,4 @@ this:
## Additional Information

To learn more about emote and emojis and how they could be used,
see the documentation of @Discord.IEmote.
see the documentation of @Discord.IEmote.

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

+ 36
- 34
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 6.0] and [.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.

@@ -22,10 +22,12 @@ other limitations, you may also consider targeting [.NET Framework]
> notice. It is known to have issues with the library's WebSockets
> implementation and may crash the application upon startup.

[Mono]: https://www.mono-project.com/
[.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/
[mono]: https://www.mono-project.com/
[.net 6.0]: https://docs.microsoft.com/en-us/dotnet/core/whats-new/dotnet-6
[.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/
[additional steps]: #installing-on-net-standard-11

## Installing with NuGet
@@ -37,37 +39,37 @@ Development builds of Discord.Net, as well as add-ons, will be
published to our [MyGet feed]. See
@Guides.GettingStarted.Installation.Nightlies to learn more.

[official NuGet feed]: https://nuget.org
[MyGet feed]: https://www.myget.org/feed/Packages/discord-net
[official nuget feed]: https://nuget.org
[myget feed]: https://www.myget.org/feed/Packages/discord-net

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

1. Create a new solution for your bot
2. In the Solution Explorer, find the "Dependencies" element under your
bot's project
bot's project
3. Right click on "Dependencies", and select "Manage NuGet packages"

![Step 3](images/install-vs-deps.png)
![Step 3](images/install-vs-deps.png)

4. In the "Browse" tab, search for `Discord.Net`
5. Install the `Discord.Net` package

![Step 5](images/install-vs-nuget.png)
![Step 5](images/install-vs-nuget.png)

### [Using JetBrains Rider](#tab/rider-install)

1. Create a new solution for your bot
2. Open the NuGet window (Tools > NuGet > Manage NuGet packages for Solution)

![Step 2](images/install-rider-nuget-manager.png)
![Step 2](images/install-rider-nuget-manager.png)

3. In the "Packages" tab, search for `Discord.Net`

![Step 3](images/install-rider-search.png)
![Step 3](images/install-rider-search.png)

4. Install by adding the package to your project

![Step 4](images/install-rider-add.png)
![Step 4](images/install-rider-add.png)

### [Using Visual Studio Code](#tab/vs-code)

@@ -82,7 +84,7 @@ published to our [MyGet feed]. See
2. Navigate to where your `*.csproj` is located
3. Enter `dotnet add package Discord.Net`

***
---

## Compiling from Source

@@ -90,15 +92,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 workload is required during Visual Studio
installation.

### Using Command Line

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

## Additional Information

@@ -117,28 +119,28 @@ by installing one or more custom packages as listed below.
1. Download the latest [.NET Core SDK].
2. Create or move your existing project to use .NET Core.
3. Modify your `<TargetFramework>` tag to at least `netcoreapp2.1`, or
by adding the `--framework netcoreapp2.1` switch when building.
by adding the `--framework netcoreapp2.1` switch when building.

#### [Custom Packages](#tab/custom-pkg)

1. Install or compile the following packages:
1. Install or compile the following packages:

* `Discord.Net.Providers.WS4Net`
* `Discord.Net.Providers.UDPClient` (Optional)
* This is _only_ required if your bot will be utilizing voice chat.
- `Discord.Net.Providers.WS4Net`
- `Discord.Net.Providers.UDPClient` (Optional)
- This is _only_ required if your bot will be utilizing voice chat.

2. Configure your [DiscordSocketClient] to use these custom providers
over the default ones.
2. Configure your [DiscordSocketClient] to use these custom providers
over the default ones.

* To do this, set the `WebSocketProvider` and the optional
`UdpSocketProvider` properties on the [DiscordSocketConfig] that you
are passing into your client.
* To do this, set the `WebSocketProvider` and the optional
`UdpSocketProvider` properties on the [DiscordSocketConfig] that you
are passing into your client.

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

[DiscordSocketClient]: xref:Discord.WebSocket.DiscordSocketClient
[DiscordSocketConfig]: xref:Discord.WebSocket.DiscordSocketConfig
[discordsocketclient]: xref:Discord.WebSocket.DiscordSocketClient
[discordsocketconfig]: xref:Discord.WebSocket.DiscordSocketConfig

***
---

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

+ 31
- 0
docs/guides/guild_events/creating-guild-events.md View File

@@ -0,0 +1,31 @@
---
uid: Guides.GuildEvents.Creating
title: Creating Guild Events
---

# Creating guild events

You can create new guild events by using the `CreateEventAsync` function on a guild.

### Parameters

| Name | Type | Summary |
| ------------- | --------------------------------- | ---------------------------------------------------------------------------- |
| name | `string` | Sets the name of the event. |
| startTime | `DateTimeOffset` | Sets the start time of the event. |
| type | `GuildScheduledEventType` | Sets the type of the event. |
| privacyLevel? | `GuildScheduledEventPrivacyLevel` | Sets the privacy level of the event |
| description? | `string` | Sets the description of the event. |
| endTime? | `DateTimeOffset?` | Sets the end time of the event. |
| channelId? | `ulong?` | Sets the channel id of the event, only valid on stage or voice channel types |
| location? | `string` | Sets the location of the event, only valid on external types |

Lets create a basic test event.

```cs
var guild = client.GetGuild(guildId);

var guildEvent = await guild.CreateEventAsync("test event", DateTimeOffset.UtcNow.AddDays(1), GuildScheduledEventType.External, endTime: DateTimeOffset.UtcNow.AddDays(2), location: "Space");
```

This code will create an event that lasts a day and starts tomorrow. It will be an external event thats in space.

+ 16
- 0
docs/guides/guild_events/getting-event-users.md View File

@@ -0,0 +1,16 @@
---
uid: Guides.GuildEvents.GettingUsers
title: Getting Guild Event Users
---

# Getting Event Users

You can get a collection of users who are currently interested in the event by calling `GetUsersAsync`. This method works like any other get users method as in it returns an async enumerable. This method also supports pagination by user id.

```cs
// get all users and flatten the result into one collection.
var users = await event.GetUsersAsync().FlattenAsync();

// get users around the 613425648685547541 id.
var aroundUsers = await event.GetUsersAsync(613425648685547541, Direction.Around).FlattenAsync();
```

+ 41
- 0
docs/guides/guild_events/intro.md View File

@@ -0,0 +1,41 @@
---
uid: Guides.GuildEvents.Intro
title: Introduction to Guild Events
---

# Guild Events

Guild events are a way to host events within a guild. They offer alot of features and flexibility.

## Getting started with guild events

You can access any events within a guild by calling `GetEventsAsync` on a guild.

```cs
var guildEvents = await guild.GetEventsAsync();
```

If your working with socket guilds you can just use the `Events` property:

```cs
var guildEvents = guild.Events;
```

There are also new gateway events that you can hook to receive guild scheduled events on.

```cs
// Fired when a guild event is cancelled.
client.GuildScheduledEventCancelled += ...

// Fired when a guild event is completed.
client.GuildScheduledEventCompleted += ...

// Fired when a guild event is started.
client.GuildScheduledEventStarted += ...

// Fired when a guild event is created.
client.GuildScheduledEventCreated += ...

// Fired when a guild event is updated.
client.GuildScheduledEventUpdated += ...
```

+ 23
- 0
docs/guides/guild_events/modifying-events.md View File

@@ -0,0 +1,23 @@
---
uid: Guides.GuildEvents.Modifying
title: Modifying Guild Events
---

# Modifying Events

You can modify events using the `ModifyAsync` method to modify the event, heres the properties you can modify:

| Name | Type | Description |
| ------------ | --------------------------------- | -------------------------------------------- |
| ChannelId | `ulong?` | Gets or sets the channel id of the event. |
| string | `string` | Gets or sets the location of this event. |
| Name | `string` | Gets or sets the name of the event. |
| PrivacyLevel | `GuildScheduledEventPrivacyLevel` | Gets or sets the privacy level of the event. |
| StartTime | `DateTimeOffset` | Gets or sets the start time of the event. |
| EndTime | `DateTimeOffset` | Gets or sets the end time of the event. |
| Description | `string` | Gets or sets the description of the event. |
| Type | `GuildScheduledEventType` | Gets or sets the type of the event. |
| Status | `GuildScheduledEventStatus` | Gets or sets the status of the event. |

> [!NOTE]
> All of these properties are optional.

+ 110
- 0
docs/guides/int_basics/application-commands/context-menu-commands/creating-context-menu-commands.md View File

@@ -0,0 +1,110 @@
---
uid: Guides.ContextCommands.Creating
title: Creating Context Commands
---

# Creating context menu commands.

There are two kinds of Context Menu Commands: User Commands and Message Commands.
Each of these have a Global and Guild variant.
Global menu commands are available for every guild that adds your app. An individual app's global commands are also available in DMs if that app has a bot that shares a mutual guild with the user.

Guild commands are specific to the guild you specify when making them. Guild commands are not available in DMs. Command names are unique per application within each scope (global and guild). That means:

- Your app cannot have two global commands with the same name
- Your app cannot have two guild commands within the same name on the same guild
- Your app can have a global and guild command with the same name
- Multiple apps can have commands with the same names

[!IMPORTANT]
> Apps can have a maximum of 5 global context menu commands,
> and an additional 5 guild-specific context menu commands per guild.

## UserCommandBuilder

The context menu user command builder will help you create user commands. The builder has these available fields and methods:

| Name | Type | Description |
| -------- | -------- | ------------------------------------------------------------------------------------------------ |
| Name | string | The name of this context menu command. |
| WithName | Function | Sets the field name. |
| Build | Function | Builds the builder into the appropriate `UserCommandProperties` class used to make Menu commands |

## MessageCommandBuilder

The context menu message command builder will help you create message commands. The builder has these available fields and methods:

| Name | Type | Description |
| -------- | -------- | --------------------------------------------------------------------------------------------------- |
| Name | string | The name of this context menu command. |
| 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.
> They cannot be registered pre-ready.

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

```cs
// Let's hook the ready event for creating our commands in.
client.Ready += Client_Ready;

...

public async Task Client_Ready()
{
// Let's build a guild command! We're going to need a guild so lets just put that in a variable.
var guild = client.GetGuild(guildId);

// Next, lets create our user and message command builder. This is like the embed builder but for context menu commands.
var guildUserCommand = new UserCommandBuilder();
var guildMessageCommand = new MessageCommandBuilder();

// Note: Names have to be all lowercase and match the regular expression ^[\w -]{3,32}$
guildUserCommand.WithName("Guild User Command");
guildMessageCommand.WithName("Guild Message Command");

// Descriptions are not used with User and Message commands
//guildCommand.WithDescription("");

// Let's do our global commands
var globalUserCommand = new UserCommandBuilder();
globalCommand.WithName("Global User Command");
var globalMessageCommand = new MessageCommandBuilder();
globalMessageCommand.WithName("Global Message Command");


try
{
// Now that we have our builder, we can call the BulkOverwriteApplicationCommandAsync to make our context commands. Note: this will overwrite all your previous commands with this array.
await guild.BulkOverwriteApplicationCommandAsync(new ApplicationCommandProperties[]
{
guildUserCommand.Build(),
guildMessageCommand.Build()
});

// With global commands we dont need the guild.
await client.BulkOverwriteGlobalApplicationCommandsAsync(new ApplicationCommandProperties[]
{
globalUserCommand.Build(),
globalMessageCommand.Build()
})
}
catch(ApplicationCommandException exception)
{
// If our command was invalid, we should catch an ApplicationCommandException. This exception contains the path of the error as well as the error message. You can serialize the Error field in the exception to get a visual of where your error is.
var json = JsonConvert.SerializeObject(exception.Error, Formatting.Indented);

// You can send this error somewhere or just print it to the console, for this example we're just going to print it.
Console.WriteLine(json);
}
}

```

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

+ 33
- 0
docs/guides/int_basics/application-commands/context-menu-commands/receiving-context-menu-command-events.md View File

@@ -0,0 +1,33 @@
---
uid: Guides.ContextCommands.Reveiving
title: Receiving Context Commands
---

# Receiving Context Menu events

User commands and Message commands have their own unique event just like the other interaction types. For user commands the event is `UserCommandExecuted` and for message commands the event is `MessageCommandExecuted`.

```cs
// For message commands
client.MessageCommandExecuted += MessageCommandHandler;

// For user commands
client.UserCommandExecuted += UserCommandHandler;

...

public async Task MessageCommandHandler(SocketMessageCommand arg)
{
Console.Writeline("Message command received!");
}

public async Task UserCommandHandler(SocketUserCommand arg)
{
Console.Writeline("User command received!");
}
```

User commands contain a SocketUser object called `Member` in their data class, showing the user that was clicked to run the command.
Message commands contain a SocketMessage object called `Message` in their data class, showing the message that was clicked to run the command.

Both return the user who ran the command, the guild (if any), channel, etc.

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

+ 40
- 0
docs/guides/int_basics/application-commands/slash-commands/bulk-overwrite-of-global-slash-commands.md View File

@@ -0,0 +1,40 @@
---
uid: Guides.SlashCommands.BulkOverwrite
title: Slash Command Bulk Overwrites
---

If you have too many global commands then you might want to consider using the bulk overwrite function.

```cs
public async Task Client_Ready()
{
List<ApplicationCommandProperties> applicationCommandProperties = new();
try
{
// Simple help slash command.
SlashCommandBuilder globalCommandHelp = new SlashCommandBuilder();
globalCommandHelp.WithName("help");
globalCommandHelp.WithDescription("Shows information about the bot.");
applicationCommandProperties.Add(globalCommandHelp.Build());

// Slash command with name as its parameter.
SlashCommandOptionBuilder slashCommandOptionBuilder = new();
slashCommandOptionBuilder.WithName("name");
slashCommandOptionBuilder.WithType(ApplicationCommandOptionType.String);
slashCommandOptionBuilder.WithDescription("Add a family");
slashCommandOptionBuilder.WithRequired(true); // Only add this if you want it to be required

SlashCommandBuilder globalCommandAddFamily = new SlashCommandBuilder();
globalCommandAddFamily.WithName("add-family");
globalCommandAddFamily.WithDescription("Add a family");
applicationCommandProperties.Add(globalCommandAddFamily.Build());

await _client.BulkOverwriteGlobalApplicationCommandsAsync(applicationCommandProperties.ToArray());
}
catch (ApplicationCommandException exception)
{
var json = JsonConvert.SerializeObject(exception.Error, Formatting.Indented);
Console.WriteLine(json);
}
}
```

+ 85
- 0
docs/guides/int_basics/application-commands/slash-commands/choice-slash-command.md View File

@@ -0,0 +1,85 @@
---
uid: Guides.SlashCommands.Choices
title: Slash Command Choices
---

# Slash Command Choices.

With slash command options you can add choices, making the user select between some set values. Lets create a command that asks how much they like our bot!

Let's set up our slash command:

```cs
private async Task Client_Ready()
{
ulong guildId = 848176216011046962;

var guildCommand = new SlashCommandBuilder()
.WithName("feedback")
.WithDescription("Tell us how much you are enjoying this bot!")
.AddOption(new SlashCommandOptionBuilder()
.WithName("rating")
.WithDescription("The rating your willing to give our bot")
.WithRequired(true)
.AddChoice("Terrible", 1)
.AddChoice("Meh", 2)
.AddChoice("Good", 3)
.AddChoice("Lovely", 4)
.AddChoice("Excellent!", 5)
.WithType(ApplicationCommandOptionType.Integer)
).Build();

try
{
await client.Rest.CreateGuildCommand(guildCommand.Build(), guildId);
}
catch(ApplicationCommandException exception)
{
var json = JsonConvert.SerializeObject(exception.Error, Formatting.Indented);
Console.WriteLine(json);
}
}
```
> [!NOTE]
> Your `ApplicationCommandOptionType` specifies which type your choices are, you need to use `ApplicationCommandOptionType.Integer` for choices whos values are whole numbers, `ApplicationCommandOptionType.Number` for choices whos values are doubles, and `ApplicationCommandOptionType.String` for string values.

We have defined 5 choices for the user to pick from, each choice has a value assigned to it. The value can either be a string or an int. In our case we're going to use an int. This is what the command looks like:

![feedback style](images/feedback1.png)

Lets add our code for handling the interaction.

```cs
private async Task SlashCommandHandler(SocketSlashCommand command)
{
// Let's add a switch statement for the command name so we can handle multiple commands in one event.
switch(command.Data.Name)
{
case "list-roles":
await HandleListRoleCommand(command);
break;
case "settings":
await HandleSettingsCommand(command);
break;
case "feedback":
await HandleFeedbackCommand(command);
break;
}
}

private async Task HandleFeedbackCommand(SocketSlashCommand command)
{
var embedBuilder = new EmbedBuilder()
.WithAuthor(command.User)
.WithTitle("Feedback")
.WithDescription($"Thanks for your feedback! You rated us {command.Data.Options.First().Value}/5")
.WithColor(Color.Green)
.WithCurrentTimestamp();

await command.RespondAsync(embed: embedBuilder.Build());
}
```

And this is the result:

![feedback working](images/feedback2.png)

+ 98
- 0
docs/guides/int_basics/application-commands/slash-commands/creating-slash-commands.md View File

@@ -0,0 +1,98 @@
---
uid: Guides.SlashCommands.Creating
title: Creating Slash Commands
---

# Creating your first slash commands.

There are two kinds of Slash Commands: global commands and guild commands.
Global commands are available for every guild that adds your app. An individual app's global commands are also available in DMs if that app has a bot that shares a mutual guild with the user.

Guild commands are specific to the guild you specify when making them. Guild commands are not available in DMs. Command names are unique per application within each scope (global and guild). That means:

- Your app cannot have two global commands with the same name
- Your app cannot have two guild commands within the same name on the same guild
- Your app can have a global and guild command with the same name
- Multiple apps can have commands with the same names

**Note**: Apps can have a maximum of 100 global commands, and an additional 100 guild-specific commands per guild.

**Note**: Global commands will take up to 1 hour to create, delete or modify on guilds. If you need to update a command quickly for testing you can create it as a guild command.

If you don't have the code for a bot ready yet please follow [this guide](https://docs.stillu.cc/guides/getting_started/first-bot.html).

## SlashCommandBuilder

The slash command builder will help you create slash commands. The builder has these available fields and methods:

| Name | Type | Description |
| --------------------- | -------------------------------- | -------------------------------------------------------------------------------------------- |
| MaxNameLength | const int | The maximum length of a name for a slash command allowed by Discord. |
| MaxDescriptionLength | const int | The maximum length of a commands description allowed by Discord. |
| MaxOptionsCount | const int | The maximum count of command options allowed by Discord |
| Name | string | The name of this slash command. |
| Description | string | A 1-100 length description of this slash command |
| Options | List\<SlashCommandOptionBuilder> | The options for this command. |
| DefaultPermission | bool | Whether the command is enabled by default when the app is added to a guild. |
| WithName | Function | Sets the field name. |
| WithDescription | Function | Sets the description of the current command. |
| WithDefaultPermission | Function | Sets the default permission of the current command. |
| AddOption | Function | Adds an option to the current slash command. |
| Build | Function | Builds the builder into a `SlashCommandCreationProperties` class used to make slash commands |

> [!NOTE]
> Slash command names must be all lowercase!

## Creating a Slash Command

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

```cs
// Let's hook the ready event for creating our commands in.
client.Ready += Client_Ready;

...

public async Task Client_Ready()
{
// Let's build a guild command! We're going to need a guild so lets just put that in a variable.
var guild = client.GetGuild(guildId);

// Next, lets create our slash command builder. This is like the embed builder but for slash commands.
var guildCommand = new SlashCommandBuilder();

// Note: Names have to be all lowercase and match the regular expression ^[\w-]{3,32}$
guildCommand.WithName("first-command");

// Descriptions can have a max length of 100.
guildCommand.WithDescription("This is my first guild slash command!");

// Let's do our global command
var globalCommand = new SlashCommandBuilder();
globalCommand.WithName("first-global-command");
globalCommand.WithDescription("This is my frist global slash command");

try
{
// Now that we have our builder, we can call the CreateApplicationCommandAsync method to make our slash command.
await guild.CreateApplicationCommandAsync(guildCommand.Build());

// With global commands we dont need the guild.
await client.CreateGlobalApplicationCommandAsync(globalCommand.Build());
// Using the ready event is a simple implementation for the sake of the example. Suitable for testing and development.
// For a production bot, it is recommended to only run the CreateGlobalApplicationCommandAsync() once for each command.
}
catch(ApplicationCommandException exception)
{
// If our command was invalid, we should catch an ApplicationCommandException. This exception contains the path of the error as well as the error message. You can serialize the Error field in the exception to get a visual of where your error is.
var json = JsonConvert.SerializeObject(exception.Error, Formatting.Indented);

// You can send this error somewhere or just print it to the console, for this example we're just going to print it.
Console.WriteLine(json);
}
}

```

> [!NOTE]
> Slash commands only need to be created once. They do _not_ have to be 'created' on every startup or connection. The example simple shows creating them in the ready event as it's simpler than creating normal bot commands to register slash commands. The global commands take up to an hour to register every time the CreateGlobalApplicationCommandAsync() is called for a given command.

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

Before After
Width: 482  |  Height: 366  |  Size: 37 KiB

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

Before After
Width: 1670  |  Height: 412  |  Size: 31 KiB

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

Before After
Width: 499  |  Height: 265  |  Size: 28 KiB

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

Before After
Width: 1672  |  Height: 294  |  Size: 37 KiB

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

Before After
Width: 472  |  Height: 314  |  Size: 32 KiB

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

Before After
Width: 1715  |  Height: 751  |  Size: 111 KiB

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

Before After
Width: 1667  |  Height: 549  |  Size: 74 KiB

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

Before After
Width: 467  |  Height: 331  |  Size: 50 KiB

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

Before After
Width: 552  |  Height: 322  |  Size: 52 KiB

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

Before After
Width: 330  |  Height: 132  |  Size: 11 KiB

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

Before After
Width: 434  |  Height: 106  |  Size: 18 KiB

+ 102
- 0
docs/guides/int_basics/application-commands/slash-commands/parameters.md View File

@@ -0,0 +1,102 @@
---
uid: Guides.SlashCommands.Parameters
title: Slash Command Parameters
---

# Slash command parameters

Slash commands can have a bunch of parameters, each their own type. Let's first go over the types of parameters we can have.

| Name | Description |
| --------------- | -------------------------------------------------- |
| SubCommand | A subcommand inside of a subcommand group. |
| SubCommandGroup | The parent command group of subcommands. |
| String | A string of text. |
| Integer | A number. |
| Boolean | True or False. |
| User | A user |
| Channel | A channel, this includes voice text and categories |
| Role | A role. |
| Mentionable | A role or a user. |

Each one of the parameter types has its own DNET type in the `SocketSlashCommandDataOption`'s Value field:
| Name | C# Type |
| --------------- | ------------------------------------------------ |
| SubCommand | NA |
| SubCommandGroup | NA |
| String | `string` |
| Integer | `int` |
| Boolean | `bool` |
| User | `SocketGuildUser` or `SocketUser` |
| Role | `SocketRole` |
| Channel | `SocketChannel` |
| Mentionable | `SocketUser`, `SocketGuildUser`, or `SocketRole` |

Let's start by making a command that takes in a user and lists their roles.

```cs
client.Ready += Client_Ready;

...

public async Task Client_Ready()
{
ulong guildId = 848176216011046962;

var guildCommand = new SlashCommandBuilder()
.WithName("list-roles")
.WithDescription("Lists all roles of a user.")
.AddOption("user", ApplicationCommandOptionType.User, "The users whos roles you want to be listed", isRequired: true);

try
{
await client.Rest.CreateGuildCommand(guildCommand.Build(), guildId);
}
catch(ApplicationCommandException exception)
{
var json = JsonConvert.SerializeObject(exception.Error, Formatting.Indented);
Console.WriteLine(json);
}
}

```

![list roles command](images/listroles1.png)

That seems to be working, now Let's handle the interaction.

```cs
private async Task SlashCommandHandler(SocketSlashCommand command)
{
// Let's add a switch statement for the command name so we can handle multiple commands in one event.
switch(command.Data.Name)
{
case "list-roles":
await HandleListRoleCommand(command);
break;
}
}

private async Task HandleListRoleCommand(SocketSlashCommand command)
{
// We need to extract the user parameter from the command. since we only have one option and it's required, we can just use the first option.
var guildUser = (SocketGuildUser)command.Data.Options.First().Value;

// We remove the everyone role and select the mention of each role.
var roleList = string.Join(",\n", guildUser.Roles.Where(x => !x.IsEveryone).Select(x => x.Mention));

var embedBuiler = new EmbedBuilder()
.WithAuthor(guildUser.ToString(), guildUser.GetAvatarUrl() ?? guildUser.GetDefaultAvatarUrl())
.WithTitle("Roles")
.WithDescription(roleList)
.WithColor(Color.Green)
.WithCurrentTimestamp();

// Now, Let's respond with the embed.
await command.RespondAsync(embed: embedBuiler.Build());
}
```

![working list roles](images/listroles2.png)

That has worked! Next, we will go over responding ephemerally.

+ 23
- 0
docs/guides/int_basics/application-commands/slash-commands/responding-ephemerally.md View File

@@ -0,0 +1,23 @@
---
uid: Guides.SlashCommands.Ephemeral
title: Ephemeral Responses
---

# Responding ephemerally

What is an ephemeral response? Basically, only the user who executed the command can see the result of it, this is pretty simple to implement.

> [!NOTE]
> You don't have to run arg.DeferAsync() to capture the interaction, you can use arg.RespondAsync() with a message to capture it, this also follows the ephemeral rule.

When responding with either `FollowupAsync` or `RespondAsync` you can pass in an `ephemeral` property. When setting it to true it will respond ephemerally, false and it will respond non-ephemerally.

Let's use this in our list role command.

```cs
await command.RespondAsync(embed: embedBuiler.Build(), ephemeral: true);
```

Running the command now only shows the message to us!

![ephemeral command](images/ephemeral1.png)

+ 40
- 0
docs/guides/int_basics/application-commands/slash-commands/responding-to-slash-commands.md View File

@@ -0,0 +1,40 @@
---
uid: Guides.SlashCommands.Receiving
title: Receiving and Responding to Slash Commands
---

# Responding to interactions.

Interactions are the base thing sent over by Discord. Slash commands are one of the interaction types. We can listen to the `SlashCommandExecuted` event to respond to them. Lets add this to our code:

```cs
client.SlashCommandExecuted += SlashCommandHandler;

...

private async Task SlashCommandHandler(SocketSlashCommand command)
{

}
```

With every type of interaction there is a `Data` field. This is where the relevant information lives about our command that was executed. In our case, `Data` is a `SocketSlashCommandData` instance. In the data class, we can access the name of the command triggered as well as the options if there were any. For this example, we're just going to respond with the name of the command executed.

```cs
private async Task SlashCommandHandler(SocketSlashCommand command)
{
await command.RespondAsync($"You executed {command.Data.Name}");
}
```

Let's try this out!

![slash command picker](images/slashcommand1.png)

![slash command result](images/slashcommand2.png)

> [!NOTE]
> After receiving an interaction, you must respond to acknowledge it. You can choose to respond with a message immediately using `RespondAsync()` or you can choose to send a deferred response with `DeferAsync()`.
> If choosing a deferred response, the user will see a loading state for the interaction, and you'll have up to 15 minutes to edit the original deferred response using `ModifyOriginalResponseAsync()`. You can read more about response types [here](https://discord.com/developers/docs/interactions/slash-commands#interaction-response)

This seems to be working! Next, we will look at parameters for slash commands.

+ 219
- 0
docs/guides/int_basics/application-commands/slash-commands/subcommands.md View File

@@ -0,0 +1,219 @@
---
uid: Guides.SlashCommands.SubCommand
title: Sub Commands
---

# Subcommands

Subcommands allow you to have multiple commands available in a single command. They can be useful for representing sub options for a command. For example: A settings command. Let's first look at some limitations with subcommands set by discord.

- An app can have up to 25 subcommand groups on a top-level command
- An app can have up to 25 subcommands within a subcommand group
- commands can have up to 25 `options`
- options can have up to 25 `choices`

```
VALID

command
|
|__ subcommand
|
|__ subcommand

----

command
|
|__ subcommand-group
|
|__ subcommand
|
|__ subcommand-group
|
|__ subcommand


-------

INVALID


command
|
|__ subcommand-group
|
|__ subcommand-group
|
|__ subcommand-group
|
|__ subcommand-group

----

INVALID

command
|
|__ subcommand
|
|__ subcommand-group
|
|__ subcommand
|
|__ subcommand-group
```

Let's write a settings command that can change 3 fields in our bot.

```cs
public string FieldA { get; set; } = "test";
public int FieldB { get; set; } = 10;
public bool FieldC { get; set; } = true;

public async Task Client_Ready()
{
ulong guildId = 848176216011046962;

var guildCommand = new SlashCommandBuilder()
.WithName("settings")
.WithDescription("Changes some settings within the bot.")
.AddOption(new SlashCommandOptionBuilder()
.WithName("field-a")
.WithDescription("Gets or sets the field A")
.WithType(ApplicationCommandOptionType.SubCommandGroup)
.AddOption(new SlashCommandOptionBuilder()
.WithName("set")
.WithDescription("Sets the field A")
.WithType(ApplicationCommandOptionType.SubCommand)
.AddOption("value", ApplicationCommandOptionType.String, "the value to set the field", isRequired: true)
).AddOption(new SlashCommandOptionBuilder()
.WithName("get")
.WithDescription("Gets the value of field A.")
.WithType(ApplicationCommandOptionType.SubCommand)
)
).AddOption(new SlashCommandOptionBuilder()
.WithName("field-b")
.WithDescription("Gets or sets the field B")
.WithType(ApplicationCommandOptionType.SubCommandGroup)
.AddOption(new SlashCommandOptionBuilder()
.WithName("set")
.WithDescription("Sets the field B")
.WithType(ApplicationCommandOptionType.SubCommand)
.AddOption("value", ApplicationCommandOptionType.Integer, "the value to set the fie to.", isRequired: true)
).AddOption(new SlashCommandOptionBuilder()
.WithName("get")
.WithDescription("Gets the value of field B.")
.WithType(ApplicationCommandOptionType.SubCommand)
)
).AddOption(new SlashCommandOptionBuilder()
.WithName("field-c")
.WithDescription("Gets or sets the field C")
.WithType(ApplicationCommandOptionType.SubCommandGroup)
.AddOption(new SlashCommandOptionBuilder()
.WithName("set")
.WithDescription("Sets the field C")
.WithType(ApplicationCommandOptionType.SubCommand)
.AddOption("value", ApplicationCommandOptionType.Boolean, "the value to set the fie to.", isRequired: true)
).AddOption(new SlashCommandOptionBuilder()
.WithName("get")
.WithDescription("Gets the value of field C.")
.WithType(ApplicationCommandOptionType.SubCommand)
)
);

try
{
await client.Rest.CreateGuildCommand(guildCommand.Build(), guildId);
}
catch(ApplicationCommandException exception)
{
var json = JsonConvert.SerializeObject(exception.Error, Formatting.Indented);
Console.WriteLine(json);
}
}
```

All that code generates a command that looks like this:
![settings](images/settings1.png)

Now that we have our command made, we need to handle the multiple options with this command. So lets add this into our handler:

```cs
private async Task SlashCommandHandler(SocketSlashCommand command)
{
// Let's add a switch statement for the command name so we can handle multiple commands in one event.
switch(command.Data.Name)
{
case "list-roles":
await HandleListRoleCommand(command);
break;
case "settings":
await HandleSettingsCommand(command);
break;
}
}

private async Task HandleSettingsCommand(SocketSlashCommand command)
{
// First lets extract our variables
var fieldName = command.Data.Options.First().Name;
var getOrSet = command.Data.Options.First().Options.First().Name;
// Since there is no value on a get command, we use the ? operator because "Options" can be null.
var value = command.Data.Options.First().Options.First().Options?.FirstOrDefault().Value;

switch (fieldName)
{
case "field-a":
{
if(getOrSet == "get")
{
await command.RespondAsync($"The value of `field-a` is `{FieldA}`");
}
else if (getOrSet == "set")
{
this.FieldA = (string)value;
await command.RespondAsync($"`field-a` has been set to `{FieldA}`");
}
}
break;
case "field-b":
{
if (getOrSet == "get")
{
await command.RespondAsync($"The value of `field-b` is `{FieldB}`");
}
else if (getOrSet == "set")
{
this.FieldB = (int)value;
await command.RespondAsync($"`field-b` has been set to `{FieldB}`");
}
}
break;
case "field-c":
{
if (getOrSet == "get")
{
await command.RespondAsync($"The value of `field-c` is `{FieldC}`");
}
else if (getOrSet == "set")
{
this.FieldC = (bool)value;
await command.RespondAsync($"`field-c` has been set to `{FieldC}`");
}
}
break;
}
}

```

Now, let's try this out! Running the 3 get commands seems to get the default values we set.

![settings get](images/settings2.png)

Now let's try changing each to a different value.

![settings set](images/settings3.png)

That has worked! Next, let't look at choices in commands.

+ 10
- 0
docs/guides/int_basics/intro.md View File

@@ -0,0 +1,10 @@
---
uid: Guides.Interactions.Intro
title: Introduction to Interactions
---

# Interactions

Placeholder text does the brrr.

Links to different sections of guides: msg comp / slash commands.

+ 87
- 0
docs/guides/int_basics/message-components/advanced.md View File

@@ -0,0 +1,87 @@
---
uid: Guides.MessageComponents.Advanced
title: Advanced Concepts
---

# Advanced

Lets say you have some components on an ephemeral slash command, and you want to modify the message that the button is on. The issue with this is that ephemeral messages are not stored and can not be get via rest or other means.

Luckily, Discord thought of this and introduced a way to modify them with interactions.

### Using the UpdateAsync method

Components come with an `UpdateAsync` method that can update the message that the component was on. You can use it like a `ModifyAsync` method.

Lets use it with a command, we first create our command, in this example im just going to use a message command:

```cs
var command = new MessageCommandBuilder()
.WithName("testing").Build();

await client.GetGuild(guildId).BulkOverwriteApplicationCommandAsync(new [] { command, buttonCommand });
```

Next, we listen for this command, and respond with some components when its used:

```cs
var menu = new SelectMenuBuilder()
{
CustomId = "select-1",
Placeholder = "Select Somthing!",
MaxValues = 1,
MinValues = 1,
};

menu.AddOption("Meh", "1", "Its not gaming.")
.AddOption("Ish", "2", "Some would say that this is gaming.")
.AddOption("Moderate", "3", "It could pass as gaming")
.AddOption("Confirmed", "4", "We are gaming")
.AddOption("Excellent", "5", "It is renowned as gaming nation wide", new Emoji("🔥"));

var components = new ComponentBuilder()
.WithSelectMenu(menu);


await arg.RespondAsync("On a scale of one to five, how gaming is this?", component: componBuild(), ephemeral: true);
break;
```

Now, let's listen to the select menu executed event and add a case for `select-1`

```cs
client.SelectMenuExecuted += SelectMenuHandler;

...

public async Task SelectMenuHandler(SocketMessageComponent arg)
{
switch (arg.Data.CustomId)
{
case "select-1":
var value = arg.Data.Values.First();
var menu = new SelectMenuBuilder()
{
CustomId = "select-1",
Placeholder = $"{(arg.Message.Components.First().Components.First() as SelectMenu).Options.FirstOrDefault(x => x.Value == value).Label}",
MaxValues = 1,
MinValues = 1,
Disabled = true
};
menu.AddOption("Meh", "1", "Its not gaming.")
.AddOption("Ish", "2", "Some would say that this is gaming.")
.AddOption("Moderate", "3", "It could pass as gaming")
.AddOption("Confirmed", "4", "We are gaming")
.AddOption("Excellent", "5", "It is renowned as gaming nation wide", new Emoji("🔥"));
// We use UpdateAsync to update the message and its original content and components.
await arg.UpdateAsync(x =>
{
x.Content = $"Thank you {arg.User.Mention} for rating us {value}/5 on the gaming scale";
x.Components = new ComponentBuilder().WithSelectMenu(menu).Build();
});
break;
}
}
```

+ 45
- 0
docs/guides/int_basics/message-components/buttons-in-depth.md View File

@@ -0,0 +1,45 @@
---
uid: Guides.MessageComponents.Buttons
title: Buttons in Depth
---

# Buttons in depth

There are many changes you can make to buttons, lets take a look at the parameters in the `WithButton` function"
| Name | Type | Description |
|----------|---------------|----------------------------------------------------------------|
| label | `string` | The label text for the button. |
| customId | `string` | The custom id of the button. |
| style | `ButtonStyle` | The style of the button. |
| emote | `IEmote` | A IEmote to be used with this button. |
| url | `string` | A URL to be used only if the `ButtonStyle` is a Link. |
| disabled | `bool` | Whether or not the button is disabled. |
| row | `int` | The row to place the button if it has enough room, otherwise 0 |

### Label

This is the front facing text that the user sees. The maximum length is 80 characters.

### CustomId

This is the property sent to you by discord when a button is clicked. It is not required for link buttons as they do not emit an event. The maximum length is 100 characters.

### Style

Styling your buttons are important for indicating different actions:

![](Images/image3.png)

You can do this by using the `ButtonStyle` which has all the styles defined.

### Emote

You can specify an `IEmote` when creating buttons to add them to your button. They have the same restrictions as putting guild based emotes in messages.

### Url

If you use the link style with your button you can specify a url. When this button is clicked the user is taken to that url.

### Disabled

You can specify if your button is disabled, meaning users won't be able to click on it.

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

Before After
Width: 390  |  Height: 154  |  Size: 17 KiB

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

Before After
Width: 413  |  Height: 100  |  Size: 19 KiB

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

Before After
Width: 849  |  Height: 508  |  Size: 40 KiB

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

Before After
Width: 584  |  Height: 161  |  Size: 20 KiB

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

Before After
Width: 587  |  Height: 201  |  Size: 17 KiB

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

Before After
Width: 620  |  Height: 288  |  Size: 38 KiB

+ 66
- 0
docs/guides/int_basics/message-components/intro.md View File

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

# Message Components

Message components are a framework for adding interactive elements to a message your app or bot sends. They're accessible, customizable, and easy to use.

## What is a Component

Components are a new parameter you can use when sending messages with your bot. There are currently 2 different types of components you can use: Buttons and Select Menus.

## Creating components

Lets create a simple component that has a button. First thing we need is a way to trigger the message, this can be done via commands or simply a ready event. Lets make a command that triggers our button message.

```cs
[Command("spawner")]
public async Task Spawn()
{
// Reply with some components
}
```

We now have our command, but we need to actually send the buttons with the command. To do that, lets look at the `ComponentBuilder` class:

| Name | Description |
| ---------------- | --------------------------------------------------------------------------- |
| `FromMessage` | Creates a new builder from a message. |
| `FromComponents` | Creates a new builder from the provided list of components. |
| `WithSelectMenu` | Adds a `SelectMenuBuilder` to the `ComponentBuilder` at the specific row. |
| `WithButton` | Adds a `ButtonBuilder` to the `ComponentBuilder` at the specific row. |
| `Build` | Builds this builder into a `MessageComponent` used to send your components. |

We see that we can use the `WithButton` function so lets do that. looking at its parameters it takes:

- `label` - The display text of the button.
- `customId` - The custom id of the button, this is whats sent by discord when your button is clicked.
- `style` - The discord defined style of the button.
- `emote` - An emote to be displayed with the button.
- `url` - The url of the button if its a link button.
- `disabled` - Whether or not the button is disabled.
- `row` - The row the button will occupy.

Since were just making a busic button, we dont have to specify anything else besides the label and custom id.

```cs
var builder = new ComponentBuilder()
.WithButton("label", "custom-id");
```

Lets add this to our command:

```cs
[Command("spawner")]
public async Task Spawn()
{
var builder = new ComponentBuilder()
.WithButton("label", "custom-id");

await ReplyAsync("Here is a button!", components: builder.Build());
}
```

![](images\image1.png)

+ 37
- 0
docs/guides/int_basics/message-components/responding-to-buttons.md View File

@@ -0,0 +1,37 @@
---
uid: Guides.MessageComponents.Responding
title: Responding to Components
---

# Responding to button clicks

Responding to buttons is pretty simple, there are a couple ways of doing it and we can cover both.

### Method 1: Hooking the InteractionCreated Event

We can hook the `ButtonExecuted` event for button type interactions:

```cs
client.ButtonExecuted += MyButtonHandler;
```

Now, lets write our handler.

```cs
public async Task MyButtonHandler(SocketMessageComponent component)
{
// We can now check for our custom id
switch(component.Data.CustomId)
{
// Since we set our buttons custom id as 'custom-id', we can check for it like this:
case "custom-id":
// Lets respond by sending a message saying they clicked the button
await component.RespondAsync($"{component.User.Mention} has clicked the button!");
break;
}
}
```

Running it and clicking the button:

![](Images/image2.png)

+ 76
- 0
docs/guides/int_basics/message-components/select-menus.md View File

@@ -0,0 +1,76 @@
---
uid: Guides.MessageComponents.SelectMenus
title: Select Menus
---

# Select menus

Select menus allow users to select from a range of options, this can be quite useful with configuration commands etc.

## Creating a select menu

We can use a `SelectMenuBuilder` to create our menu.

```cs
var menuBuilder = new SelectMenuBuilder()
.WithPlaceholder("Select an option")
.WithCustomId("menu-1")
.WithMinValues(1)
.WithMaxValues(1)
.AddOption("Option A", "opt-a", "Option B is lying!")
.AddOption("Option B", "opt-b", "Option A is telling the truth!");

var builder = new ComponentBuilder()
.WithSelectMenu(menuBuilder);
```

Lets add this to a command:

```cs
[Command("spawner")]
public async Task Spawn()
{
var menuBuilder = new SelectMenuBuilder()
.WithPlaceholder("Select an option")
.WithCustomId("menu-1")
.WithMinValues(1)
.WithMaxValues(1)
.AddOption("Option A", "opt-a", "Option B is lying!")
.AddOption("Option B", "opt-b", "Option A is telling the truth!");

var builder = new ComponentBuilder()
.WithSelectMenu(menuBuilder);

await ReplyAsync("Whos really lying?", components: builder.Build());
}
```

Running this produces this result:

![](Images/image4.png)

And opening the menu we see:

![](Images/image5.png)

Lets handle the selection of an option, We can hook the `SelectMenuExecuted` event to handle our select menu:

```cs
client.SelectMenuExecuted += MyMenuHandler;
```

The `SelectMenuExecuted` also supplies a `SocketMessageComponent` argument, we can confirm that its a select menu by checking the `ComponentType` inside of the data field if we need, but the library will do that for us and only execute our handler if its a select menu.

The values that the user has selected will be inside of the `Values` collection in the Data field. we can list all of them back to the user for this example.

```cs
public async Task MyMenuHandler(SocketMessageComponent arg)
{
var text = string.Join(", ", arg.Data.Values);
await arg.RespondAsync($"You have selected {text}");
}
```

Running this produces this result:

![](Images/image6.png)

+ 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`1
[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!");

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

Loading…
Cancel
Save