Browse Source

Merge branch 'dev' into dev

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

+ 1
- 0
.github/FUNDING.yml View File

@@ -0,0 +1 @@
open_collective: discordnet

+ 2
- 3
.gitignore View File

@@ -127,7 +127,7 @@ publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
@@ -151,7 +151,6 @@ AppPackages/
# Others
*.[Cc]ache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
@@ -206,4 +205,4 @@ docs/api/\.manifest
\.idea/

# Codealike UID
codealike.json
codealike.json

+ 264
- 2
CHANGELOG.md View File

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

## [3.1.0] - 2021-12-24

### Added

- #1996 Add nullable type converter to Interaction service (ccc365e)
- #1998 Add before and after execute async (9f124b2)
- #2001 Add MaxUploadLimit to guilds (7745558)
- #2002 Add RTCRegion to voice channels (2a416a3)
- #2003 Add Guilduser timeouts and MODERATE_MEMBERS permission (144741e)

### Fixed

- #1976 fix guild scheduled events update (8daa0b6)
- #1977 fix thread member nre (5d43fe6)
- #1980 fix requireRole attribute of interaction service (a2f57f8)
- #1990 Fix images path for select menu section (a8b5506)
- #1992 fix images; fix closing brace on cs ref (fb52525)
- #1993 Fix CommandExecuted not invoked on failed parse (82bb3e4)
- #1995 Fixed file being disposed on upload (ad20e03)
- #1999 Fix SocketGuildUser being changed to SocketGlobalUser in UserLeft (5446bfe)
- Fix voice codes namespace (768a0a9)

### Misc

- #1994 Make HasResponded public and add it to IDiscordInteraction (1fbcbb8)
- #1997 Make module service scopes optional (cb1aad3)

## [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)
- #1781 Add GetEmotesAsync to IGuild (df23d57)
- #1801 Add missing property to MESSAGE_REACTION_ADD event (0715d7d)
- #1828 Add methods to interact with reactions without a message object (5b244f2)
- #1830 Add ModifyMessageAsync to IMessageChannel (365a848)
- #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)
- #1786 Add ChannelType property to ChannelInfo audit log (6ac5ea1)
- #1791 Update Webhook ChannelId from model change (d2518db)
- #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)
- #1526 Add Direction.Around to GetMessagesAsync (f2130f8)
- #1537 Implement gateway ratelimit (ec673e1)
- #1544 Add MESSAGE_REACTION_REMOVE_EMOJI and RemoveAllReactionsForEmoteAsync (a89f076)
- #1549 Add GetUsersAsync to SocketGuild (30b5a83)
- #1566 Support Gateway Intents (d5d10d3)
- #1573 Add missing properties to Guild and deprecate GuildEmbed (ec212b1)
- #1581 Add includeRoleIds to PruneUsersAsync (a80e5ff)
- #1588 Add GetStreams to AudioClient (1e012ac)
- #1596 Add missing channel properties (2d80037)
- #1604 Add missing application properties (including Teams) (10fcde0)
- #1619 Add "View Guild Insights" to GuildPermission (2592264)
- #1637 Added CultureInvariant RegexOption to WebhookUrlRegex (e3925a7)
- #1659 Add inline replies (e3850e1)
- #1688 Send presence on Identify payload (25d5d36)
- #1721 Add role tags (6a62c47)
- #1722 Add user public flags (c683b29)
- #1724 Add MessageFlags and AllowedMentions to message modify (225550d)
- #1731 Add GuildUser IsPending property (8b25c9b)
- #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)
- #1531 Add AllowedMentions to SendFileAsync (ab32607)
- #1532 GuildEmbed.ChannelId as nullable per API documentation (971d519)
- #1546 Different ratelimits for the same route (implement discord buckets) (2f6c017)
- #1548 Incomplete Ready, DownloadUsersAsync, and optimize AlwaysDownloadUsers (dc8c959)
- #1555 InvalidOperationException at MESSAGE_CREATE (bd4672a)
- #1557 Sending 2 requests instead of 1 to create a Guild role. (5430cc8)
- #1571 Not using the new domain name. (df8a0f7)
- #1578 Trim token before passing it to the authorization header (42ba372)
- #1580 Stop TaskCanceledException from bubbling up (b8fa464)
- #1599 Invite audit log without inviter (b95b95b)
- #1602 Add AllowedMentions to webhooks (bd4516b)
- #1603 Cancel reconnection when 4014 (f396cd9)
- #1608 Voice overwrites and CategoryId remarks (43c8fc0)
- #1614 Check error 404 and return null for GetBanAsync (ae9fff6)
- #1621 Parse mentions from message payload (366ca9a)
- #1622 Do not update overwrite cache locally (3860da0)
- #1623 Invoke UserUpdated from GuildMemberUpdated if needed (3085e88)
- #1624 Handle null PreferredLocale in rare cases (c1d04b4)
- #1639 Invite and InviteMetadata properties (dd2e524)
- #1642 Add missing permissions (4b389f3)
- #1647 handicap member downloading for verified bots (fa5ef5e)
- #1652 Update README.MD to reflect new discord domain (03b831e)
- #1667 Audio stream dispose (a2af985)
- #1671 Crosspost throwing InvalidOperationException (9134443)
- #1672 Team is nullable, not optional (be60d81)
- #1681 Emoji url encode (04389a4)
- #1683 SocketGuild.HasAllMembers is false if a user left a guild (47f571e)
- #1686 Revert PremiumSubscriptionCount type (97e71cd)
- #1695 Possible NullReferenceException when receiving InvalidSession (5213916)
- #1702 Rollback Activities to Game (9d7cb39)
- #1727 Move and fix internal AllowedMentions object (4a7f8fe)
- limit request members batch size (084db25)
- UserMentions throwing NullRef (5ed01a3)
- Wrong author for SocketUserMessage.ReferencedMessage (1e9b252)
- Discord sends null when there's no team (05a1f0a)
- IMessage.Embeds docs remarks (a4d32d3)
- Missing MessageReference when sending files (2095701)

### Misc

- #1545 MutualGuilds optimization (323a677)
- #1551 Update webhook regex to support discord.com (7585789)
- #1556 Add SearchUsersAsync (57880de)
- #1561 Minor refactor to switch expression (42826df)
- #1576 Updating comments for privileged intents (c42bfa6)
- #1678 Change ratelimit messages (47ed806)
- #1714 Update summary of SocketVoiceChannel.Users (e385c40)
- #1720 VoiceRegions and related changes (5934c79)
- Add updated libraries for LastModified (d761846)
- Add alternative documentation link (accd351)
- Temporarily disable StyleCops until all the fixes are impl'd (36de7b2)
- Remove redundant CreateGuildRoleParams (3df0539)
- Add minor tweaks to DiscordSocketConfig docs strings (2cd1880)
- Fix MaxWaitBetweenGuildAvailablesBeforeReady docs string (e31cdc7)
- Missing summary tag for GatewayIntents (3a10018)
- Add new method of role ID copy (857ef77)
- Resolve inheritdocs for IAttachment (9ea3291)
- Mark null as a specific langword in summary (13a41f8)
- Cleanup GatewayReconnectException docs (833ee42)
- Update Docfx.Plugins.LastModified to v1.2.4 (28a6f97)
- Update framework version for tests to Core 3.1 to comply with LTS (4988a07)
- 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)
@@ -24,6 +263,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)
@@ -39,11 +279,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)
@@ -68,14 +310,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)
@@ -84,16 +328,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)
@@ -105,9 +353,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)
@@ -116,9 +366,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)
@@ -129,16 +381,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)
@@ -194,6 +450,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)
@@ -241,6 +498,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)
@@ -275,14 +533,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)
@@ -303,11 +562,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)
@@ -316,4 +577,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}


+ 4
- 5
Discord.Net.targets View File

@@ -1,15 +1,14 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VersionPrefix>2.3.0</VersionPrefix>
<VersionSuffix>dev</VersionSuffix>
<VersionPrefix>3.1.0</VersionPrefix>
<LangVersion>latest</LangVersion>
<Authors>Discord.Net Contributors</Authors>
<PackageTags>discord;discordapp</PackageTags>
<PackageProjectUrl>https://github.com/RogueException/Discord.Net</PackageProjectUrl>
<PackageProjectUrl>https://github.com/Discord-Net/Discord.Net</PackageProjectUrl>
<PackageLicenseUrl>http://opensource.org/licenses/MIT</PackageLicenseUrl>
<PackageIconUrl>https://github.com/RogueException/Discord.Net/raw/dev/docs/marketing/logo/PackageLogo.png</PackageIconUrl>
<PackageIconUrl>https://github.com/Discord-Net/Discord.Net/raw/dev/docs/marketing/logo/PackageLogo.png</PackageIconUrl>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>git://github.com/RogueException/Discord.Net</RepositoryUrl>
<RepositoryUrl>git://github.com/Discord-Net/Discord.Net</RepositoryUrl>
</PropertyGroup>
<PropertyGroup Condition=" '$(BuildNumber)' == '' ">
<VersionSuffix Condition=" '$(VersionSuffix)' != ''">$(VersionSuffix)-dev</VersionSuffix>


+ 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


+ 37
- 8
README.md View File

@@ -1,42 +1,71 @@
# 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://discordapp.com/api/guilds/81384788765712384/widget.png)](https://discord.gg/jkrBmQR)

An unofficial .NET API Wrapper for the Discord client (http://discordapp.com).

Check out the [documentation](https://discord.foxbot.me/) or join the [Discord API Chat](https://discord.gg/jkrBmQR).
<p align="center">
<a href="https://discordnet.dev/" title="Click to visit the documentation!">
<img src="https://raw.githubusercontent.com/discord-net/Discord.Net/dev/docs/marketing/logo/SVG/Combinationmark%20White%20Border.svg" alt="Logo">
</a>
<br />
<br />
<a href="https://www.nuget.org/packages/Discord.Net/">
<img src="https://img.shields.io/nuget/vpre/Discord.Net.svg?maxAge=2592000?style=plastic" alt="NuGet">
</a>
<a href="https://www.myget.org/feed/Packages/discord-net">
<img src="https://img.shields.io/myget/discord-net/vpre/Discord.Net.svg" alt="MyGet">
</a>
<a href="https://dev.azure.com/discord-net/Discord.Net/_build/latest?definitionId=1&branchName=dev">
<img src="https://dev.azure.com/discord-net/Discord.Net/_apis/build/status/discord-net.Discord.Net?branchName=dev" alt="Build Status">
</a>
<a href="https://discord.gg/dnet">
<img src="https://discord.com/api/guilds/848176216011046962/widget.png" alt="Discord">
</a>
</p>
Discord NET is an unofficial .NET API Wrapper for the Discord client (https://discord.com).

## Documentation

- [Nightly](https://discordnet.dev)

## 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 available on nuget (`https://www.nuget.org/packages/Discord.Net.Labs/`) and myget (`https://www.myget.org/F/discord-net-labs/api/v3/index.json`).

## Compiling

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

### Using Visual Studio

- [Visual Studio 2017](https://www.microsoft.com/net/core#windowsvs2017)
- [.NET Core 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


+ 9
- 0
StyleAnalyzer.targets View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- <ItemGroup>
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.205" PrivateAssets="all" />
</ItemGroup>
<PropertyGroup>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
</PropertyGroup> -->
</Project>

+ 3
- 9
azure-pipelines.yml View File

@@ -14,25 +14,20 @@ trigger:
jobs:
- job: Linux
pool:
vmImage: 'ubuntu-16.04'
vmImage: 'ubuntu-latest'
steps:
- task: UseDotNet@2
displayName: 'Use .NET Core sdk'
inputs:
packageType: 'sdk'
version: '3.x'
- template: azure/build.yml

- job: Windows_build
pool:
vmImage: 'windows-2019'
vmImage: 'windows-latest'
condition: ne(variables['Build.SourceBranch'], 'refs/heads/dev')
steps:
- template: azure/build.yml

- job: Windows_deploy
pool:
vmImage: 'windows-2019'
vmImage: 'windows-latest'
condition: |
and (
succeeded(),
@@ -44,4 +39,3 @@ jobs:
steps:
- template: azure/build.yml
- template: azure/deploy.yml
- template: azure/docs.yml

+ 13
- 1
azure/build.yml View File

@@ -1,5 +1,17 @@
steps:
- script: dotnet restore -v minimal Discord.Net.sln
- task: UseDotNet@2
displayName: 'Use .NET Core sdk'
inputs:
packageType: 'sdk'
version: '6.0.x'
includePreviewVersions: true
- task: DotNetCoreCLI@2
inputs:
command: 'restore'
projects: 'Discord.Net.sln'
feedsToUse: 'select'
verbosityRestore: 'Minimal'
displayName: Restore packages

- script: dotnet build "Discord.Net.sln" --no-restore -v minimal -c $(buildConfiguration) /p:BuildNumber=$(buildNumber) /p:IsTagBuild=$(buildTag)


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

+ 1
- 1
docs/_overwrites/Common/EmbedBuilder.Overwrites.md View File

@@ -28,7 +28,7 @@ public async Task SendRichEmbedAsync()
var embed = new EmbedBuilder
{
// Embed property can be set within object initializer
Title = "Hello world!"
Title = "Hello world!",
Description = "I am a description set by initializer."
};
// Or with methods


+ 3
- 3
docs/_overwrites/Common/EmbedObjectBuilder.Inclusion.md View File

@@ -4,10 +4,10 @@ field, and 2 normal fields using an @Discord.EmbedBuilder:
```cs
var exampleAuthor = new EmbedAuthorBuilder()
.WithName("I am a bot")
.WithIconUrl("https://discordapp.com/assets/e05ead6e6ebc08df9291738d0aa6986d.png");
.WithIconUrl("https://discord.com/assets/e05ead6e6ebc08df9291738d0aa6986d.png");
var exampleFooter = new EmbedFooterBuilder()
.WithText("I am a nice footer")
.WithIconUrl("https://discordapp.com/assets/28174a34e77bb5e5310ced9f95cb480b.png");
.WithIconUrl("https://discord.com/assets/28174a34e77bb5e5310ced9f95cb480b.png");
var exampleField = new EmbedFieldBuilder()
.WithName("Title of Another Field")
.WithValue("I am an [example](https://example.com).")
@@ -22,4 +22,4 @@ var embed = new EmbedBuilder()
.WithAuthor(exampleAuthor)
.WithFooter(exampleFooter)
.Build();
```
```

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


+ 3
- 3
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-a904fc6" target="lib/linux-x64/libgit2-a904fc6.so" />
<dllmap os="osx" cpu="x86,x86-64" dll="git2-a904fc6" target="lib/osx/libgit2-a904fc6.dylib" />
<configuration>
<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/alpine-x64/libgit2-ef5a385.so View File


BIN
docs/_template/last-modified/plugins/lib/alpine.3.9-x64/libgit2-ef5a385.so View File


BIN
docs/_template/last-modified/plugins/lib/debian-arm64/libgit2-ef5a385.so View File


BIN
docs/_template/last-modified/plugins/lib/debian.9-x64/libgit2-ef5a385.so View File


BIN
docs/_template/last-modified/plugins/lib/fedora-x64/libgit2-ef5a385.so View File


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/linux-x64/libgit2-ef5a385.so View File


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


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


BIN
docs/_template/last-modified/plugins/lib/rhel-x64/libgit2-ef5a385.so View File


BIN
docs/_template/last-modified/plugins/lib/ubuntu.16.04-arm64/libgit2-ef5a385.so View File


BIN
docs/_template/last-modified/plugins/lib/ubuntu.18.04-x64/libgit2-ef5a385.so View File


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


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


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


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


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

@@ -27,7 +27,8 @@
</div>
{{/_disableContribution}}
<nav class="bs-docs-sidebar hidden-print hidden-xs hidden-sm affix" id="affix">
<!-- <p><a class="back-to-top" href="#top">Back to top</a><p> -->
<h5>{{__global.inThisArticle}}</h5>
<div></div>
</nav>
</div>
</div>

+ 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.1.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}"]
}
}

+ 9
- 9
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,7 +107,7 @@ reactions.

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

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

[IChannel]: xref:Discord.IChannel
[ICategoryChannel]: xref:Discord.ICategoryChannel
@@ -120,4 +120,4 @@ Unfortunately, not at the moment. See [#401](https://github.com/RogueException/D
[IUserMessage]: xref:Discord.IUserMessage
[IEmote]: xref:Discord.IEmote
[Emote]: xref:Discord.Emote
[Emoji]: xref:Discord.Emoji
[Emoji]: xref:Discord.Emoji

+ 58
- 4
docs/faq/basics/client-basics.md View File

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

## I keep having trouble with intents!

As Discord.NET has upgraded from Discord API v6 to API v9,
`GatewayIntents` must now be specified in the socket config, as well as on the [developer portal].

```cs

// Where ever you declared your websocket client.
DiscordSocketClient _client;

...

var config = new DiscordSocketConfig()
{
.. // Other config options can be presented here.
GatewayIntents = GatewayIntents.All
}

_client = new DiscordSocketClient(config);

```
### Common intents:

- AllUnprivileged: This is a group of most common intents, that do NOT require any [developer portal] intents to be enabled.
This includes intents that receive messages such as: `GatewayIntents.GuildMessages, GatewayIntents.DirectMessages`
- GuildMembers: An intent disabled by default, as you need to enable it in the [developer portal].
- GuildPresences: Also disabled by default, this intent together with `GuildMembers` are the only intents not included in `AllUnprivileged`.
- All: All intents, it is ill adviced to use this without care, as it *can* cause a memory leak from presence.
The library will give responsive warnings if you specify unnecessary intents.


> [!NOTE]
> All gateway intents, their Discord API counterpart and their enum value are listed
> [HERE](xref:Discord.GatewayIntents)

### Stacking intents:

It is common that you require several intents together.
The example below shows how this can be done.

```cs

GatewayIntents = GatewayIntents.AllUnprivileged | GatewayIntents.GuildMembers | ..

```

> [!NOTE]
> Further documentation on the ` | ` operator can be found
> [HERE](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators)

[developer portal]: https://discord.com/developers/

## My client keeps returning 401 upon logging in!

> [!WARNING]
@@ -28,9 +80,9 @@ 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
[Discord API Terms of Service]: https://discordapp.com/developers/docs/legal
[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 +125,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.


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

@@ -74,6 +74,9 @@ it will return the user ID of the aforementioned user.

Several common ways to do this:

1. Make the role mentionable and mention the role, and escape it
1. (Easiest) Right click on the role either in the Server Settings
or in the user's role list.
![Roles](images/role-copy.png)
2. Make the role mentionable and mention the role, and escape it
using the `\` character in front.
2. 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/role-copy.png View File

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

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

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

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

@@ -0,0 +1,88 @@
---
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

## Im getting System.TimeoutException: 'Cannot respond to an interaction after 3 seconds!'

This happens because your computers clock is out of sync or your trying to respond after 3 seconds. If your clock is out of sync and you cant fix it, you can set the `UseInteractionSnowflakeDate` to false in the config.

## Bad form Exception when I try to create my commands, why do I get this?

Bad form exceptions are thrown if the slash, user or message command builder has invalid values.
The following options could resolve your error.

#### Is your command name lowercase?

If your command name is not lowercase, it is not seen as a valid command entry.
`Avatar` is invalid; `avatar` is valid.

#### Are your values below or above the required amount? (This also applies to message components)

Discord expects all values to be below maximum allowed.
Going over this maximum amount of characters causes an exception.

> [!NOTE]
> All maximum and minimum value requirements can be found in the [Discord Developer Docs].
> For components, structure documentation is found [here].

[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

+ 46
- 6
docs/faq/misc/glossary.md View File

@@ -19,18 +19,18 @@ channels, and are often referred to as "servers".
* A **Channel** ([IChannel]) represents a generic channel.
- Example: #dotnet_discord-net
- See [Channel Types](#channel-types)
[IGuild]: xref:Discord.IGuild
[IChannel]: xref:Discord.IChannel

## Channel Types

### Message Channels
* A **Text Channel** ([ITextChannel]) is a message channel from a
Guild.
* A **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.
@@ -79,4 +119,4 @@ activity for listening to a song on Spotify.
[RichGame]: xref:Discord.RichGame
[StreamingGame]: xref:Discord.StreamingGame
[SpotifyGame]: xref:Discord.SpotifyGame
[Rich Presence Intro]: https://discordapp.com/developers/docs/rich-presence/best-practices
[Rich Presence Intro]: https://discord.com/developers/docs/rich-presence/best-practices

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

+ 7
- 11
docs/guides/getting_started/first-bot.md View File

@@ -31,7 +31,7 @@ the Discord Applications Portal first.

![Step 7](images/intro-public-bot.png)

[Discord Applications Portal]: https://discordapp.com/developers/applications/
[Discord Applications Portal]: https://discord.com/developers/applications/

## Adding your bot to a server

@@ -80,15 +80,11 @@ recommended for these operations to be awaited in a
properly established async context whenever possible.

To establish an async context, we will be creating an async main method
in your console application, and rewriting the static main method to
invoke the new async main.
in your console application.

[!code-csharp[Async Context](samples/first-bot/async-context.cs)]

As a result of this, your program will now start and immediately
jump into an async context. This allows us to create a connection
to Discord later on without having to worry about setting up the
correct async implementation.
As a result of this, your program will now start into an async context.

> [!WARNING]
> If your application throws any exceptions within an async context,
@@ -165,11 +161,11 @@ or any other blocking method, such as reading from the console.
> the source code for your bot.
>
> In the following example, we retrieve the token from a pre-defined
> variable, which is **NOT** secure, especially if you plan on
> variable, which is **NOT** secure, especially if you plan on
> distributing the application in any shape or form.
>
> We recommend alternative storage such as
> [Environment Variables], an external configuration file, or a
> We recommend alternative storage such as
> [Environment Variables], an external configuration file, or a
> secrets manager for safe-handling of secrets.
>
> [Environment Variables]: https://en.wikipedia.org/wiki/Environment_variable
@@ -221,4 +217,4 @@ should be to separate...
2. the modules (handle commands)
3. the services (persistent storage, pure functions, data manipulation)

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

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)

+ 1
- 2
docs/guides/getting_started/samples/first-bot/async-context.cs View File

@@ -1,7 +1,6 @@
public class Program
{
public static void Main(string[] args)
=> new Program().MainAsync().GetAwaiter().GetResult();
public static Task Main(string[] args) => new Program().MainAsync();

public async Task MainAsync()
{


+ 1
- 2
docs/guides/getting_started/samples/first-bot/complete.cs View File

@@ -2,8 +2,7 @@ public class Program
{
private DiscordSocketClient _client;
public static void Main(string[] args)
=> new Program().MainAsync().GetAwaiter().GetResult();
public static Task Main(string[] args) => new Program().MainAsync();

public async Task MainAsync()
{


+ 2
- 2
docs/guides/getting_started/samples/first-bot/structure.cs View File

@@ -10,11 +10,11 @@ using Discord.WebSocket;
class Program
{
// Program entry point
static void Main(string[] args)
static Task Main(string[] args)
{
// Call the Program constructor, followed by the
// MainAsync method and wait until it finishes (which should be never).
new Program().MainAsync().GetAwaiter().GetResult();
return new Program().MainAsync();
}

private readonly DiscordSocketClient _client;


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

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

@@ -0,0 +1,41 @@
---
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");
globalCommandAddFamily.AddOptions(slashCommandOptionBuilder);
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

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

Loading…
Cancel
Save