Browse Source

Adding Entity guides, flowcharts, better sample system. (#2054)

* initial

* Interaction glossary entry

* Sharded Interaction sample

* Renames into solution

* Debugging samples

* Modify target location for webhookclient

* Finalizing docs work, resolving docfx errors.

* Adding threaduser to user chart

* Add branch info to readme.

* Edits to user chart

* Resolve format for glossary entries

* Patch sln target

* Issue with file naming fixed

* Patch 1/x for builds

* Appending suggestions
tags/3.2.1
Armano den Boef GitHub 3 years ago
parent
commit
b14af1c008
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
57 changed files with 1056 additions and 341 deletions
  1. +121
    -106
      Discord.Net.sln
  2. +19
    -0
      README.md
  3. +1
    -1
      docs/faq/basics/basic-operations.md
  4. +1
    -1
      docs/faq/misc/legacy.md
  5. +0
    -2
      docs/faq/toc.yml
  6. +68
    -0
      docs/guides/entities/casting.md
  7. +48
    -30
      docs/guides/entities/glossary.md
  8. BIN
      docs/guides/entities/images/IChannel.png
  9. BIN
      docs/guides/entities/images/IInteraction.png
  10. BIN
      docs/guides/entities/images/IMessage.png
  11. BIN
      docs/guides/entities/images/IUser.png
  12. +41
    -19
      docs/guides/entities/introduction.md
  13. +7
    -0
      docs/guides/entities/samples/casting.cs
  14. +8
    -0
      docs/guides/entities/samples/restentities.cs
  15. +10
    -0
      docs/guides/entities/samples/safety-cast-pass.cs
  16. +9
    -0
      docs/guides/entities/samples/safety-cast-var.cs
  17. +8
    -0
      docs/guides/entities/samples/safety-cast.cs
  18. +0
    -0
      docs/guides/entities/samples/socketentities.cs
  19. +9
    -0
      docs/guides/entities/samples/unboxing.cs
  20. +8
    -2
      docs/guides/toc.yml
  21. +0
    -77
      samples/01_basic_ping_bot/Program.cs
  22. +0
    -16
      samples/04_interactions_framework/ExampleEnum.cs
  23. +112
    -0
      samples/BasicBot/Program.cs
  24. +0
    -0
      samples/BasicBot/_BasicBot.csproj
  25. +37
    -0
      samples/InteractionFramework/Attributes/DoUserCheckAttribute.cs
  26. +1
    -1
      samples/InteractionFramework/Attributes/RequireOwnerAttribute.cs
  27. +10
    -4
      samples/InteractionFramework/CommandHandler.cs
  28. +10
    -0
      samples/InteractionFramework/ExampleEnum.cs
  29. +18
    -0
      samples/InteractionFramework/Modules/ComponentModule.cs
  30. +4
    -9
      samples/InteractionFramework/Modules/GeneralModule.cs
  31. +30
    -0
      samples/InteractionFramework/Modules/MessageCommandModule.cs
  32. +51
    -0
      samples/InteractionFramework/Modules/SlashCommandModule.cs
  33. +17
    -0
      samples/InteractionFramework/Modules/UserCommandModule.cs
  34. +4
    -6
      samples/InteractionFramework/Program.cs
  35. +1
    -1
      samples/InteractionFramework/_InteractionFramework.csproj
  36. +18
    -0
      samples/ShardedClient/Modules/InteractionModule.cs
  37. +2
    -2
      samples/ShardedClient/Modules/PublicModule.cs
  38. +15
    -9
      samples/ShardedClient/Program.cs
  39. +7
    -7
      samples/ShardedClient/Services/CommandHandlingService.cs
  40. +57
    -0
      samples/ShardedClient/Services/InteractionHandlingService.cs
  41. +2
    -1
      samples/ShardedClient/_ShardedClient.csproj
  42. +4
    -4
      samples/TextCommandFramework/Modules/PublicModule.cs
  43. +6
    -6
      samples/TextCommandFramework/Program.cs
  44. +12
    -9
      samples/TextCommandFramework/Services/CommandHandlingService.cs
  45. +1
    -1
      samples/TextCommandFramework/Services/PictureService.cs
  46. +1
    -0
      samples/TextCommandFramework/_TextCommandFramework.csproj
  47. +1
    -1
      samples/WebhookClient/Program.cs
  48. +2
    -2
      samples/WebhookClient/_WebhookClient.csproj
  49. +74
    -0
      samples/_idn/Inspector.cs
  50. +152
    -0
      samples/_idn/Program.cs
  51. +16
    -0
      samples/_idn/idn.csproj
  52. +1
    -0
      samples/_idn/logview.ps1
  53. +8
    -8
      samples/idn/Program.cs
  54. +9
    -5
      src/Discord.Net.Examples/Core/Entities/Channels/IGuildChannel.Examples.cs
  55. +5
    -4
      src/Discord.Net.Examples/Core/Entities/Channels/IMessageChannel.Examples.cs
  56. +1
    -1
      src/Discord.Net.Examples/Core/Entities/Users/IUser.Examples.cs
  57. +9
    -6
      src/Discord.Net.Examples/WebSocket/BaseSocketClient.Events.Examples.cs

+ 121
- 106
Discord.Net.sln View File

@@ -4,43 +4,45 @@ VisualStudioVersion = 17.1.31903.286
MinimumVisualStudioVersion = 10.0.40219.1 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}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Core", "src\Discord.Net.Core\Discord.Net.Core.csproj", "{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Impls", "Impls", "{288C363D-A636-4EAE-9AC1-4698B641B26E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Rest", "src\Discord.Net.Rest\Discord.Net.Rest.csproj", "{BFC6DC28-0351-4573-926A-D4124244C04F}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Rest", "src\Discord.Net.Rest\Discord.Net.Rest.csproj", "{BFC6DC28-0351-4573-926A-D4124244C04F}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Commands", "src\Discord.Net.Commands\Discord.Net.Commands.csproj", "{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Commands", "src\Discord.Net.Commands\Discord.Net.Commands.csproj", "{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.WebSocket", "src\Discord.Net.WebSocket\Discord.Net.WebSocket.csproj", "{688FD1D8-7F01-4539-B2E9-F473C5D699C7}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.WebSocket", "src\Discord.Net.WebSocket\Discord.Net.WebSocket.csproj", "{688FD1D8-7F01-4539-B2E9-F473C5D699C7}"
EndProject 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}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Webhook", "src\Discord.Net.Webhook\Discord.Net.Webhook.csproj", "{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{BB59D5B5-E7B0-4BF4-8F82-D14431B2799B}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Examples", "src\Discord.Net.Examples\Discord.Net.Examples.csproj", "{47820065-3CFB-401C-ACEA-862BD564A404}"
EndProject 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}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Interactions", "src\Discord.Net.Interactions\Discord.Net.Interactions.csproj", "{137DB209-B357-4EE8-A6EE-4B6127F6DEE9}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "02_commands_framework", "samples\02_commands_framework\02_commands_framework.csproj", "{4E1F1F40-B1DD-40C9-A4B1-A2046A4C9C76}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Analyzers", "src\Discord.Net.Analyzers\Discord.Net.Analyzers.csproj", "{24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "03_sharded_client", "samples\03_sharded_client\03_sharded_client.csproj", "{9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Analyzers.Tests", "test\Discord.Net.Analyzers.Tests\Discord.Net.Analyzers.Tests.csproj", "{FC67057C-E92F-4E1C-98BE-46F839C8AD71}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Tests.Unit", "test\Discord.Net.Tests.Unit\Discord.Net.Tests.Unit.csproj", "{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Tests.Unit", "test\Discord.Net.Tests.Unit\Discord.Net.Tests.Unit.csproj", "{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Tests.Integration", "test\Discord.Net.Tests.Integration\Discord.Net.Tests.Integration.csproj", "{E169E15A-E82C-45BF-8C24-C2CADB7093AA}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Tests.Integration", "test\Discord.Net.Tests.Integration\Discord.Net.Tests.Integration.csproj", "{E169E15A-E82C-45BF-8C24-C2CADB7093AA}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{C7CF5621-7D36-433B-B337-5A2E3C101A71}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_BasicBot", "samples\BasicBot\_BasicBot.csproj", "{F2FF84FB-F6AD-47E5-9EE5-18206CAE136E}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Analyzers.Tests", "test\Discord.Net.Analyzers.Tests\Discord.Net.Analyzers.Tests.csproj", "{FC67057C-E92F-4E1C-98BE-46F839C8AD71}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_TextCommandFramework", "samples\TextCommandFramework\_TextCommandFramework.csproj", "{4E1F1F40-B1DD-40C9-A4B1-A2046A4C9C76}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Examples", "src\Discord.Net.Examples\Discord.Net.Examples.csproj", "{47820065-3CFB-401C-ACEA-862BD564A404}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_ShardedClient", "samples\ShardedClient\_ShardedClient.csproj", "{9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "idn", "samples\idn\idn.csproj", "{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_InteractionFramework", "samples\InteractionFramework\_InteractionFramework.csproj", "{A23E46D2-1610-4AE5-820F-422D34810887}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Interactions", "src\Discord.Net.Interactions\Discord.Net.Interactions.csproj", "{137DB209-B357-4EE8-A6EE-4B6127F6DEE9}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_WebhookClient", "samples\WebhookClient\_WebhookClient.csproj", "{B61AAE66-15CC-40E4-873A-C23E697C3411}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "04_interactions_framework", "samples\04_interactions_framework\04_interactions_framework.csproj", "{A23E46D2-1610-4AE5-820F-422D34810887}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IDN", "samples\idn\idn.csproj", "{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Analyzers", "src\Discord.Net.Analyzers\Discord.Net.Analyzers.csproj", "{24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{C7CF5621-7D36-433B-B337-5A2E3C101A71}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Impls", "Impls", "{288C363D-A636-4EAE-9AC1-4698B641B26E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions", "Extensions", "{CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{BB59D5B5-E7B0-4BF4-8F82-D14431B2799B}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -112,6 +114,78 @@ Global
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Release|x64.Build.0 = Release|Any CPU {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.ActiveCfg = Release|Any CPU
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Release|x86.Build.0 = Release|Any CPU {9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Release|x86.Build.0 = Release|Any CPU
{47820065-3CFB-401C-ACEA-862BD564A404}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{47820065-3CFB-401C-ACEA-862BD564A404}.Debug|Any CPU.Build.0 = Debug|Any CPU
{47820065-3CFB-401C-ACEA-862BD564A404}.Debug|x64.ActiveCfg = Debug|Any CPU
{47820065-3CFB-401C-ACEA-862BD564A404}.Debug|x64.Build.0 = Debug|Any CPU
{47820065-3CFB-401C-ACEA-862BD564A404}.Debug|x86.ActiveCfg = Debug|Any CPU
{47820065-3CFB-401C-ACEA-862BD564A404}.Debug|x86.Build.0 = Debug|Any CPU
{47820065-3CFB-401C-ACEA-862BD564A404}.Release|Any CPU.ActiveCfg = Release|Any CPU
{47820065-3CFB-401C-ACEA-862BD564A404}.Release|Any CPU.Build.0 = Release|Any CPU
{47820065-3CFB-401C-ACEA-862BD564A404}.Release|x64.ActiveCfg = Release|Any CPU
{47820065-3CFB-401C-ACEA-862BD564A404}.Release|x64.Build.0 = Release|Any CPU
{47820065-3CFB-401C-ACEA-862BD564A404}.Release|x86.ActiveCfg = Release|Any CPU
{47820065-3CFB-401C-ACEA-862BD564A404}.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
{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
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Debug|x64.ActiveCfg = Debug|Any CPU
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Debug|x64.Build.0 = Debug|Any CPU
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Debug|x86.ActiveCfg = Debug|Any CPU
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Debug|x86.Build.0 = Debug|Any CPU
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Release|Any CPU.Build.0 = Release|Any CPU
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Release|x64.ActiveCfg = Release|Any CPU
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Release|x64.Build.0 = Release|Any CPU
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Release|x86.ActiveCfg = Release|Any CPU
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Release|x86.Build.0 = Release|Any CPU
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Debug|x64.ActiveCfg = Debug|Any CPU
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Debug|x64.Build.0 = Debug|Any CPU
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Debug|x86.ActiveCfg = Debug|Any CPU
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Debug|x86.Build.0 = Debug|Any CPU
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Release|Any CPU.Build.0 = Release|Any CPU
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Release|x64.ActiveCfg = Release|Any CPU
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Release|x64.Build.0 = Release|Any CPU
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Release|x86.ActiveCfg = Release|Any CPU
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Release|x86.Build.0 = Release|Any CPU
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Debug|x64.ActiveCfg = Debug|Any CPU
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Debug|x64.Build.0 = Debug|Any CPU
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Debug|x86.ActiveCfg = Debug|Any CPU
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Debug|x86.Build.0 = Debug|Any CPU
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Release|Any CPU.Build.0 = Release|Any CPU
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Release|x64.ActiveCfg = Release|Any CPU
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Release|x64.Build.0 = Release|Any CPU
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Release|x86.ActiveCfg = Release|Any CPU
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.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.ActiveCfg = Debug|Any CPU
{F2FF84FB-F6AD-47E5-9EE5-18206CAE136E}.Debug|Any CPU.Build.0 = 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 {F2FF84FB-F6AD-47E5-9EE5-18206CAE136E}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -148,78 +222,6 @@ Global
{9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}.Release|x64.Build.0 = Release|Any CPU {9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}.Release|x64.Build.0 = Release|Any CPU
{9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}.Release|x86.ActiveCfg = Release|Any CPU {9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}.Release|x86.ActiveCfg = Release|Any CPU
{9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}.Release|x86.Build.0 = Release|Any CPU {9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}.Release|x86.Build.0 = Release|Any CPU
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Debug|x64.ActiveCfg = Debug|Any CPU
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Debug|x64.Build.0 = Debug|Any CPU
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Debug|x86.ActiveCfg = Debug|Any CPU
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Debug|x86.Build.0 = Debug|Any CPU
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Release|Any CPU.Build.0 = Release|Any CPU
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Release|x64.ActiveCfg = Release|Any CPU
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Release|x64.Build.0 = Release|Any CPU
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Release|x86.ActiveCfg = Release|Any CPU
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Release|x86.Build.0 = Release|Any CPU
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Debug|x64.ActiveCfg = Debug|Any CPU
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Debug|x64.Build.0 = Debug|Any CPU
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Debug|x86.ActiveCfg = Debug|Any CPU
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Debug|x86.Build.0 = Debug|Any CPU
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Release|Any CPU.Build.0 = Release|Any CPU
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Release|x64.ActiveCfg = Release|Any CPU
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Release|x64.Build.0 = Release|Any CPU
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Release|x86.ActiveCfg = Release|Any CPU
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Release|x86.Build.0 = Release|Any CPU
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Debug|x64.ActiveCfg = Debug|Any CPU
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Debug|x64.Build.0 = Debug|Any CPU
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Debug|x86.ActiveCfg = Debug|Any CPU
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Debug|x86.Build.0 = Debug|Any CPU
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Release|Any CPU.Build.0 = Release|Any CPU
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Release|x64.ActiveCfg = Release|Any CPU
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Release|x64.Build.0 = Release|Any CPU
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Release|x86.ActiveCfg = Release|Any CPU
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Release|x86.Build.0 = Release|Any CPU
{47820065-3CFB-401C-ACEA-862BD564A404}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{47820065-3CFB-401C-ACEA-862BD564A404}.Debug|Any CPU.Build.0 = Debug|Any CPU
{47820065-3CFB-401C-ACEA-862BD564A404}.Debug|x64.ActiveCfg = Debug|Any CPU
{47820065-3CFB-401C-ACEA-862BD564A404}.Debug|x64.Build.0 = Debug|Any CPU
{47820065-3CFB-401C-ACEA-862BD564A404}.Debug|x86.ActiveCfg = Debug|Any CPU
{47820065-3CFB-401C-ACEA-862BD564A404}.Debug|x86.Build.0 = Debug|Any CPU
{47820065-3CFB-401C-ACEA-862BD564A404}.Release|Any CPU.ActiveCfg = Release|Any CPU
{47820065-3CFB-401C-ACEA-862BD564A404}.Release|Any CPU.Build.0 = Release|Any CPU
{47820065-3CFB-401C-ACEA-862BD564A404}.Release|x64.ActiveCfg = Release|Any CPU
{47820065-3CFB-401C-ACEA-862BD564A404}.Release|x64.Build.0 = Release|Any CPU
{47820065-3CFB-401C-ACEA-862BD564A404}.Release|x86.ActiveCfg = Release|Any CPU
{47820065-3CFB-401C-ACEA-862BD564A404}.Release|x86.Build.0 = Release|Any CPU
{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}.Debug|x64.ActiveCfg = Debug|Any CPU
{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}.Debug|x64.Build.0 = Debug|Any CPU
{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}.Debug|x86.ActiveCfg = Debug|Any CPU
{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}.Debug|x86.Build.0 = Debug|Any CPU
{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}.Release|Any CPU.Build.0 = Release|Any CPU
{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}.Release|x64.ActiveCfg = Release|Any CPU
{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.ActiveCfg = Debug|Any CPU
{A23E46D2-1610-4AE5-820F-422D34810887}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Debug|Any CPU
@@ -232,18 +234,30 @@ Global
{A23E46D2-1610-4AE5-820F-422D34810887}.Release|x64.Build.0 = 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.ActiveCfg = Release|Any CPU
{A23E46D2-1610-4AE5-820F-422D34810887}.Release|x86.Build.0 = 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
{B61AAE66-15CC-40E4-873A-C23E697C3411}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B61AAE66-15CC-40E4-873A-C23E697C3411}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B61AAE66-15CC-40E4-873A-C23E697C3411}.Debug|x64.ActiveCfg = Debug|Any CPU
{B61AAE66-15CC-40E4-873A-C23E697C3411}.Debug|x64.Build.0 = Debug|Any CPU
{B61AAE66-15CC-40E4-873A-C23E697C3411}.Debug|x86.ActiveCfg = Debug|Any CPU
{B61AAE66-15CC-40E4-873A-C23E697C3411}.Debug|x86.Build.0 = Debug|Any CPU
{B61AAE66-15CC-40E4-873A-C23E697C3411}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B61AAE66-15CC-40E4-873A-C23E697C3411}.Release|Any CPU.Build.0 = Release|Any CPU
{B61AAE66-15CC-40E4-873A-C23E697C3411}.Release|x64.ActiveCfg = Release|Any CPU
{B61AAE66-15CC-40E4-873A-C23E697C3411}.Release|x64.Build.0 = Release|Any CPU
{B61AAE66-15CC-40E4-873A-C23E697C3411}.Release|x86.ActiveCfg = Release|Any CPU
{B61AAE66-15CC-40E4-873A-C23E697C3411}.Release|x86.Build.0 = Release|Any CPU
{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}.Debug|x64.ActiveCfg = Debug|Any CPU
{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}.Debug|x64.Build.0 = Debug|Any CPU
{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}.Debug|x86.ActiveCfg = Debug|Any CPU
{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}.Debug|x86.Build.0 = Debug|Any CPU
{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}.Release|Any CPU.Build.0 = Release|Any CPU
{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}.Release|x64.ActiveCfg = Release|Any CPU
{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
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -253,17 +267,18 @@ Global
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A} {078DD7E6-943D-4D09-AFC2-D2BA58B76C9C} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}
{688FD1D8-7F01-4539-B2E9-F473C5D699C7} = {288C363D-A636-4EAE-9AC1-4698B641B26E} {688FD1D8-7F01-4539-B2E9-F473C5D699C7} = {288C363D-A636-4EAE-9AC1-4698B641B26E}
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A} {9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}
{47820065-3CFB-401C-ACEA-862BD564A404} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B}
{137DB209-B357-4EE8-A6EE-4B6127F6DEE9} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}
{24C231FD-8CF3-444A-9E7C-45C18BAD4A0D} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}
{FC67057C-E92F-4E1C-98BE-46F839C8AD71} = {C7CF5621-7D36-433B-B337-5A2E3C101A71}
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4} = {C7CF5621-7D36-433B-B337-5A2E3C101A71}
{E169E15A-E82C-45BF-8C24-C2CADB7093AA} = {C7CF5621-7D36-433B-B337-5A2E3C101A71}
{F2FF84FB-F6AD-47E5-9EE5-18206CAE136E} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B} {F2FF84FB-F6AD-47E5-9EE5-18206CAE136E} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B}
{4E1F1F40-B1DD-40C9-A4B1-A2046A4C9C76} = {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} {9B4C4AFB-3D15-44C6-9E36-12ED625AAA26} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B}
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4} = {C7CF5621-7D36-433B-B337-5A2E3C101A71}
{E169E15A-E82C-45BF-8C24-C2CADB7093AA} = {C7CF5621-7D36-433B-B337-5A2E3C101A71}
{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} {A23E46D2-1610-4AE5-820F-422D34810887} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B}
{24C231FD-8CF3-444A-9E7C-45C18BAD4A0D} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}
{B61AAE66-15CC-40E4-873A-C23E697C3411} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B}
{4A03840B-9EBE-47E3-89AB-E0914DF21AFB} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D2404771-EEC8-45F2-9D71-F3373F6C1495} SolutionGuid = {D2404771-EEC8-45F2-9D71-F3373F6C1495}


+ 19
- 0
README.md View File

@@ -81,3 +81,22 @@ Due to the nature of the Discord API, we will oftentimes need to add a property
Furthermore, while we will never break the API (outside of interface changes) on minor builds, we will occasionally need to break the ABI, by introducing parameters to a method to match changes upstream with Discord. As such, a minor version increment may require you to recompile your code, and dependencies, such as addons, may also need to be recompiled and republished on the newer version. When a binary breaking change is made, the change will be noted in the release notes. Furthermore, while we will never break the API (outside of interface changes) on minor builds, we will occasionally need to break the ABI, by introducing parameters to a method to match changes upstream with Discord. As such, a minor version increment may require you to recompile your code, and dependencies, such as addons, may also need to be recompiled and republished on the newer version. When a binary breaking change is made, the change will be noted in the release notes.


An increment of the MAJOR component indicates that breaking changes have been made to the library; consumers should check the release notes to determine what changes need to be made. An increment of the MAJOR component indicates that breaking changes have been made to the library; consumers should check the release notes to determine what changes need to be made.

## Branches

### Release/X.X

Release branch following Major.Minor. Upon release, patches will be pushed to these branches.
New NuGet releases will be tagged on these branches.

### Dev

Development branch, available on MyGet. This branch is what pull requests are targetted to.

### Feature/X

Branches that target Dev, adding new features. Feel free to explore these branches and give feedback where necessary.

### Docs/X

Usually targets Dev. These branches are used to update documentation with either new features or existing feature rework.

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

@@ -53,7 +53,7 @@ able to message.
You may check the message channel type. Visit [Glossary] to see the You may check the message channel type. Visit [Glossary] to see the
various types of channels. various types of channels.


[glossary]: xref:FAQ.Glossary#message-channels
[Glossary]: xref:Guides.Entities.Glossary#channels


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




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

@@ -24,6 +24,6 @@ Visit the repo's [release tag] to see the latest public pre-release.


The `DependencyMap` has been replaced with Microsoft's The `DependencyMap` has been replaced with Microsoft's
[DependencyInjection] Abstractions. An example usage can be seen [DependencyInjection] Abstractions. An example usage can be seen
[here](https://github.com/foxbot/DiscordBotBase/blob/csharp/src/DiscordBot/Program.cs#L36).
[here](https://github.com/Discord-Net-Labs/Discord.Net-Labs/blob/release/3.x/samples/InteractionFramework/Program.cs#L66).


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

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

@@ -16,7 +16,5 @@
topicUid: FAQ.Commands.Interactions topicUid: FAQ.Commands.Interactions
- name: Dependency Injection - name: Dependency Injection
topicUid: FAQ.Commands.DI topicUid: FAQ.Commands.DI
- name: Glossary
topicUid: FAQ.Glossary
- name: Legacy or Upgrade - name: Legacy or Upgrade
topicUid: FAQ.Legacy topicUid: FAQ.Legacy

+ 68
- 0
docs/guides/entities/casting.md View File

@@ -0,0 +1,68 @@
---
uid: Guides.Entities.Casting
title: Casting & Unboxing
---

# Casting

Casting can be done in many ways, and is the only method to box and unbox types to/from their base definition.
Casting only works for types that inherit the base type that you want to unbox from.
`IUser` cannot be cast to `IMessage`.

> [!NOTE]
> Interfaces **can** be cast to other interfaces, as long as they inherit each other.
> The same goes for reverse casting. As long as some entity can be simplified into what it inherits, your cast will pass.

## Boxing

A boxed object is the definition of an object that was simplified (or trimmed) by incoming traffic,
but still owns the data of the originally constructed type. Boxing is an implicit operation.

Through casting, we can **unbox** this type, and access the properties that were unaccessible before.

## Unboxing

Unboxing is the most direct way to access the real definition of an object.
If we want to return a type from its interface, we can unbox it directly.

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

## Regular casting

In 'regular' casting, we use the `as` keyword to assign the given type to the object.
If the boxed type can indeed be cast into given type,
it will become said type, and its properties can be accessed.
[!code-csharp[Casting](samples/casting.cs)]

> [!WARNING]
> If the type you're casting to is null, a `NullReferenceException` will be thrown when it's called.
> This makes safety casting much more interesting to use, as it prevents this exception from being thrown.

## Safety casting

Safety casting makes sure that the type you're trying to cast to can never be null, as it passes checks upon calling them.

There are 3 different ways to safety cast an object:

### Basic safety casting:

To safety cast an object, all we need to do is check if it is of the member type in a statement.
If this check fails, it will continue below, making sure we don't try to access null.
[!code-csharp[Base](samples/safety-cast.cs)]

### Object declaration:

Here we declare the object we are casting to,
making it so that you can immediately work with its properties without reassigning through regular casting.
[!code-csharp[Declare](samples/safety-cast-var.cs)]

### Reverse passage:

In previous examples, we want to let code continue running after the check, or if the check fails.
In this example, the cast will return the entire method (ignoring the latter) upon failure,
and declare the variable for further use into the method:
[!code-csharp[Pass](samples/safety-cast-pass.cs)]

> [!NOTE]
> Usage of `is`, `not` and `as` is required in cast assignment and/or type checks. `==`, `!=` and `=` are invalid assignment,
> as these operators only apply to initialized objects and not their types.

docs/faq/misc/glossary.md → docs/guides/entities/glossary.md View File

@@ -1,29 +1,19 @@
--- ---
uid: FAQ.Glossary
title: Common Terminologies / Glossary
uid: Guides.Entities.Glossary
title: Glossary & Flowcharts
--- ---


# Glossary
# Entity Types


This is an additional chapter for quick references to various common
types that you may see within Discord.Net. To see more information
regarding each type of object, click on the object to navigate
to our API documentation page where you might find more explanation
about it.
A list of all Discord.Net entities, what they can be cast to and what their properties are.


## Common Types

* A **Guild** ([IGuild]) is an isolated collection of users and
channels, and are often referred to as "servers".
- Example: [Discord API](https://discord.gg/jkrBmQR)
* A **Channel** ([IChannel]) represents a generic channel.
- Example: #dotnet_discord-net
- See [Channel Types](#channel-types)
> [!NOTE]
> All interfaces have the same inheritance tree for both `Socket` and `Rest` entities.
> Entities with that have been marked red are exclusive to the project they source from.


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


## Channel Types
![IChannelChart](images/IChannel.png)


### Message Channels ### Message Channels
* A **Text Channel** ([ITextChannel]) is a message channel from a Guild. * A **Text Channel** ([ITextChannel]) is a message channel from a Guild.
@@ -40,14 +30,11 @@ channels, and are often referred to as "servers".
- This can be any channels that may exist 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 **Voice Channel** ([IVoiceChannel]) is a voice channel in a guild.
* A **Stage Channel** ([IStageChannel]) is a stage 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
* A **Category Channel** ([ICategoryChannel]) is a category that
holds one or more sub-channels. holds one or more sub-channels.
* A **Nested Channel** ([INestedChannel]) (2.0+) is a channel that can
* A **Nested Channel** ([INestedChannel]) is a channel that can
exist under a category. exist under a category.


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

[INestedChannel]: xref:Discord.INestedChannel [INestedChannel]: xref:Discord.INestedChannel
[IGuildChannel]: xref:Discord.IGuildChannel [IGuildChannel]: xref:Discord.IGuildChannel
[IMessageChannel]: xref:Discord.IMessageChannel [IMessageChannel]: xref:Discord.IMessageChannel
@@ -62,17 +49,27 @@ exist under a category.
[IStageChannel]: xref:Discord.IStageChannel [IStageChannel]: xref:Discord.IStageChannel
[INewsChannel]: xref:Discord.INewsChannel [INewsChannel]: xref:Discord.INewsChannel


## Message Types
## Messages

![IMessageChart](images/IMessage.png)


* A **Rest Followup Message** ([RestFollowupMessage]) is a message returned by followup on on an interaction.
* A **Rest Interaction Message** ([RestInteractionMessage]) is a message returned by the interaction's original response.
* A **Rest User Message** ([RestUserMessage]) is a message sent over rest; it can be any of the above.
* An **User Message** ([IUserMessage]) is a message sent by a user. * An **User Message** ([IUserMessage]) is a message sent by a user.
* A **System Message** ([ISystemMessage]) is a message sent by Discord itself. * A **System Message** ([ISystemMessage]) is a message sent by Discord itself.
* A **Message** ([IMessage]) can be any of the above. * A **Message** ([IMessage]) can be any of the above.


[RestFollowupMessage]: xref:Discord.Rest.RestFollowupMessage
[RestInteractionMessage]: xref:Discord.Rest.RestInteractionMessage
[RestUserMEssage]: xref:Discord.Rest.RestUserMessage
[IUserMessage]: xref:Discord.IUserMessage [IUserMessage]: xref:Discord.IUserMessage
[ISystemMessage]: xref:Discord.ISystemMessage [ISystemMessage]: xref:Discord.ISystemMessage
[IMessage]: xref:Discord.IMessage [IMessage]: xref:Discord.IMessage


## User Types
## Users

![IUserChart](images/IUser.png)


* A **Guild User** ([IGuildUser]) is a user available inside a guild. * A **Guild User** ([IGuildUser]) is a user available inside a guild.
* A **Group User** ([IGroupUser]) is a user available inside a group. * A **Group User** ([IGroupUser]) is a user available inside a group.
@@ -85,7 +82,29 @@ exist under a category.
[ISelfUser]: xref:Discord.ISelfUser [ISelfUser]: xref:Discord.ISelfUser
[IUser]: xref:Discord.IUser [IUser]: xref:Discord.IUser


## Emoji Types
## Interactions

![IInteractionChart](images/IInteraction.png)

* A **Slash command** ([ISlashCommandInteraction]) is an application command executed in the text box, with provided parameters.
* A **Message Command** ([IMessageCommandInteraction]) is an application command targetting a message.
* An **User Command** ([IUserCommandInteraction]) is an application command targetting a user.
* An **Application Command** ([IApplicationCommandInteraction]) is any of the above.
* A **Message component** ([IMessageComponent]) is the interaction of a button being clicked/dropdown option(s) entered.
* An **Autocomplete Interaction** ([IAutocompleteinteraction]) is an interaction that has been automatically completed.
* An **Interaction** ([IDiscordInteraction]) is any of the above.

[ISlashCommandInteraction]: xref:Discord.ISlashCommandInteraction
[IMessageCommandInteraction]: xref:Discord.IMessageCommandInteraction
[IUserCommandInteraction]: xref:Discord.IUserCommandInteraction
[IApplicationCommandInteraction]: xref:Discord.IApplicationCommandInteraction
[IMessageComponent]: xref:Discord.IMessageComponent
[IAutocompleteinteraction]: xref:Discord.IAutocompleteInteraction
[IDiscordInteraction]: xref:Discord.IDiscordInteraction

## Other types:

### Emoji


* An **Emote** ([Emote]) is a custom emote from a guild. * An **Emote** ([Emote]) is a custom emote from a guild.
- Example: `<:dotnet:232902710280716288>` - Example: `<:dotnet:232902710280716288>`
@@ -95,8 +114,7 @@ exist under a category.
[Emote]: xref:Discord.Emote [Emote]: xref:Discord.Emote
[Emoji]: xref:Discord.Emoji [Emoji]: xref:Discord.Emoji



## Sticker Types
### Stickers


* A **Sticker** ([ISticker]) is a standard Discord sticker. * A **Sticker** ([ISticker]) is a standard Discord sticker.
* A **Custom Sticker ([ICustomSticker]) is a Guild-unique sticker. * A **Custom Sticker ([ICustomSticker]) is a Guild-unique sticker.
@@ -104,7 +122,7 @@ exist under a category.
[ISticker]: xref:Discord.ISticker [ISticker]: xref:Discord.ISticker
[ICustomSticker]: xref:Discord.ICustomSticker [ICustomSticker]: xref:Discord.ICustomSticker


## Activity Types
### Activity


* A **Game** ([Game]) refers to a user's game activity. * A **Game** ([Game]) refers to a user's game activity.
* A **Rich Presence** ([RichGame]) refers to a user's detailed * A **Rich Presence** ([RichGame]) refers to a user's detailed

BIN
docs/guides/entities/images/IChannel.png View File

Before After
Width: 682  |  Height: 882  |  Size: 58 KiB

BIN
docs/guides/entities/images/IInteraction.png View File

Before After
Width: 682  |  Height: 602  |  Size: 37 KiB

BIN
docs/guides/entities/images/IMessage.png View File

Before After
Width: 682  |  Height: 522  |  Size: 36 KiB

BIN
docs/guides/entities/images/IUser.png View File

Before After
Width: 682  |  Height: 722  |  Size: 62 KiB

docs/guides/concepts/entities.md → docs/guides/entities/introduction.md View File

@@ -1,26 +1,41 @@
--- ---
uid: Guides.Concepts.Entities
title: Entities
uid: Guides.Entities.Intro
title: Introduction
--- ---


# Entities in Discord.Net # Entities in Discord.Net


> [!NOTE]
> This article is written with the Socket variants of entities in mind,
> not the general interfaces or Rest entities.

Discord.Net provides a versatile entity system for navigating the Discord.Net provides a versatile entity system for navigating the
Discord API. Discord API.


> [!TIP]
> It is **vital** that you use the proper IDs for an entity when using
> a `GetXXX` method. It is recommended that you enable Discord's
> _developer mode_ to allow easy access to entity IDs, found in
> Settings > Appearance > Advanced. Read more about it in the
> [FAQ](xref:FAQ.Basics.GetStarted) page.

## Inheritance ## Inheritance


Due to the nature of the Discord API, some entities are designed with Due to the nature of the Discord API, some entities are designed with
multiple variants; for example, `SocketUser` and `SocketGuildUser`.
multiple variants; for example, `IUser` and `IGuildUser`.


All models will contain the most detailed version of an entity All models will contain the most detailed version of an entity
possible, even if the type is less detailed. possible, even if the type is less detailed.


For example, in the case of the `MessageReceived` event, a
## Socket & REST

REST entities are retrieved over REST, and will be disposed after use.
It is suggested to limit the amount of REST calls as much as possible,
as calls over REST interact with the API, and are thus prone to rate-limits.

- [Learn more about REST](https://restfulapi.net/)

Socket entities are created through the gateway,
most commonly through `DiscordSocketClient` events.
These entities will enter the clients' global cache for later use.

In the case of the `MessageReceived` event, a
`SocketMessage` is passed in with a channel property of type `SocketMessage` is passed in with a channel property of type
`SocketMessageChannel`. All messages come from channels capable of `SocketMessageChannel`. All messages come from channels capable of
messaging, so this is the only variant of a channel that can cover messaging, so this is the only variant of a channel that can cover
@@ -31,7 +46,9 @@ But that doesn't mean a message _can't_ come from a
retrieve information about a guild from a message entity, you will retrieve information about a guild from a message entity, you will
need to cast its channel object to a `SocketTextChannel`. need to cast its channel object to a `SocketTextChannel`.


You can find out various types of entities in the [Glossary page.](xref:FAQ.Glossary)
> [!NOTE]
> You can find out the inheritance tree & definitions of various entities
> [here](xref:Guides.Entities.Glossary)


## Navigation ## Navigation


@@ -40,26 +57,31 @@ you to easily navigate to an entity's parent or children. As explained
above, you will sometimes need to cast to a more detailed version of above, you will sometimes need to cast to a more detailed version of
an entity to navigate to its parent. an entity to navigate to its parent.


## Accessing Entities
## Accessing Socket Entities


The most basic forms of entities, `SocketGuild`, `SocketUser`, and The most basic forms of entities, `SocketGuild`, `SocketUser`, and
`SocketChannel` can be pulled from the DiscordSocketClient's global `SocketChannel` can be pulled from the DiscordSocketClient's global
cache, and can be retrieved using the respective `GetXXX` method on cache, and can be retrieved using the respective `GetXXX` method on
DiscordSocketClient. DiscordSocketClient.


> [!TIP]
> It is **vital** that you use the proper IDs for an entity when using
> a `GetXXX` method. It is recommended that you enable Discord's
> _developer mode_ to allow easy access to entity IDs, found in
> Settings > Appearance > Advanced. Read more about it in the
> [FAQ](xref:FAQ.Basics.GetStarted) page.

More detailed versions of entities can be pulled from the basic More detailed versions of entities can be pulled from the basic
entities, e.g., `SocketGuild.GetUser`, which returns a entities, e.g., `SocketGuild.GetUser`, which returns a
`SocketGuildUser`, or `SocketGuild.GetChannel`, which returns a `SocketGuildUser`, or `SocketGuild.GetChannel`, which returns a
`SocketGuildChannel`. Again, you may need to cast these objects to get `SocketGuildChannel`. Again, you may need to cast these objects to get
a variant of the type that you need. a variant of the type that you need.


## Sample
### Sample

[!code-csharp[Socket Sample](samples/socketentities.cs)]

## Accessing REST Entities

REST entities work almost the same as Socket entities, but are much less frequently used.
To access REST entities, the `DiscordSocketClient`'s `Rest` property is required.
Another option here is to create your own [DiscordRestClient], independent of the Socket gateway.

[DiscordRestClient]: xref:Discord.Rest.DiscordRestClient

### Sample


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

+ 7
- 0
docs/guides/entities/samples/casting.cs View File

@@ -0,0 +1,7 @@
// Say we have an entity; for the simplicity of this example, it will appear from thin air.
IChannel channel;

// If we want this to be an ITextChannel so we can access the properties of a text channel inside of a guild, an approach would be:
ITextChannel textChannel = channel as ITextChannel;

await textChannel.DoSomethingICantWithIChannelAsync();

+ 8
- 0
docs/guides/entities/samples/restentities.cs View File

@@ -0,0 +1,8 @@
// RestUser entities expose the accent color and banner of a user.
// This being one of the few use-cases for requesting a RestUser instead of depending on the Socket counterpart.
public static EmbedBuilder WithUserColor(this EmbedBuilder builder, IUser user)
{
var restUser = await _client.Rest.GetUserAsync(user.Id);
return builder.WithColor(restUser.AccentColor ?? Color.Blue);
// The accent color can still be null, so a check for this needs to be done to prevent an exception to be thrown.
}

+ 10
- 0
docs/guides/entities/samples/safety-cast-pass.cs View File

@@ -0,0 +1,10 @@
private void MyFunction(IMessage message)
{
// Here we do the reverse as in the previous examples, and let it continue the code below if it IS an IUserMessage
if (message is not IUserMessage userMessage)
return;

// Because we do the above check inline (don't give the statement a body),
// the code will still declare `userMessage` as available outside of the above statement.
Console.WriteLine(userMessage.Author);
}

+ 9
- 0
docs/guides/entities/samples/safety-cast-var.cs View File

@@ -0,0 +1,9 @@
IUser user;

// Here we can pre-define the actual declaration of said IGuildUser object,
// so we don't need to cast additionally inside of the statement.
if (user is IGuildUser guildUser)
{
Console.WriteLine(guildUser.JoinedAt);
}
// Check failed.

+ 8
- 0
docs/guides/entities/samples/safety-cast.cs View File

@@ -0,0 +1,8 @@
IUser user;

// Here we check if the user is an IGuildUser, if not, let it pass. This ensures its not null.
if (user is IGuildUser)
{
Console.WriteLine("This user is in a guild!");
}
// Check failed.

docs/guides/concepts/samples/entities.cs → docs/guides/entities/samples/socketentities.cs View File


+ 9
- 0
docs/guides/entities/samples/unboxing.cs View File

@@ -0,0 +1,9 @@
IUser user;

// Here we use inline unboxing to make a call to its member (if available) only once.

// Note that if the entity we're trying to cast to is null, this will throw a NullReferenceException.
Console.WriteLine(((IGuildUser)user).Nickname);

// In case you are certain the entity IS said member, you can also use unboxing to declare variables.
IGuildUser guildUser = (IGuildUser)user;

+ 8
- 2
docs/guides/toc.yml View File

@@ -21,8 +21,14 @@
topicUid: Guides.Concepts.Events topicUid: Guides.Concepts.Events
- name: Managing Connections - name: Managing Connections
topicUid: Guides.Concepts.ManageConnections topicUid: Guides.Concepts.ManageConnections
- name: Entities
topicUid: Guides.Concepts.Entities
- name: Entities
items:
- name: Introduction
topicUid: Guides.Entities.Intro
- name: Casting
topicUid: Guides.Entities.Casting
- name: Glossary & Flowcharts
topicUid: Guides.Entities.Glossary
- name: Working with Text-based Commands - name: Working with Text-based Commands
items: items:
- name: Introduction - name: Introduction


+ 0
- 77
samples/01_basic_ping_bot/Program.cs View File

@@ -1,77 +0,0 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Discord;
using Discord.WebSocket;

namespace _01_basic_ping_bot
{
// This is a minimal, bare-bones example of using Discord.Net
//
// If writing a bot with commands, we recommend using the Discord.Net.Commands
// framework, rather than handling commands yourself, like we do in this sample.
//
// You can find samples of using the command framework:
// - Here, under the 02_commands_framework sample
// - https://github.com/foxbot/DiscordBotBase - a bare-bones bot template
// - https://github.com/foxbot/patek - a more feature-filled bot, utilizing more aspects of the library
class Program
{
private readonly DiscordSocketClient _client;

// Discord.Net heavily utilizes TAP for async, so we create
// an asynchronous context from the beginning.
static void Main(string[] args)
{
new Program().MainAsync().GetAwaiter().GetResult();
}

public Program()
{
// It is recommended to Dispose of a client when you are finished
// using it, at the end of your app's lifetime.
_client = new DiscordSocketClient();

_client.Log += LogAsync;
_client.Ready += ReadyAsync;
_client.MessageReceived += MessageReceivedAsync;
}

public async Task MainAsync()
{
// Tokens should be considered secret data, and never hard-coded.
await _client.LoginAsync(TokenType.Bot, Environment.GetEnvironmentVariable("token"));
await _client.StartAsync();

// Block the program until it is closed.
await Task.Delay(Timeout.Infinite);
}

private Task LogAsync(LogMessage log)
{
Console.WriteLine(log.ToString());
return Task.CompletedTask;
}

// The Ready event indicates that the client has opened a
// connection and it is now safe to access the cache.
private Task ReadyAsync()
{
Console.WriteLine($"{_client.CurrentUser} is connected!");

return Task.CompletedTask;
}

// This is not the recommended way to write a bot - consider
// reading over the Commands Framework sample.
private async Task MessageReceivedAsync(SocketMessage message)
{
// The bot should never respond to itself.
if (message.Author.Id == _client.CurrentUser.Id)
return;

if (message.Content == "!ping")
await message.Channel.SendMessageAsync("pong!");
}
}
}

+ 0
- 16
samples/04_interactions_framework/ExampleEnum.cs View File

@@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _04_interactions_framework
{
public enum ExampleEnum
{
First,
Second,
Third,
Fourth
}
}

+ 112
- 0
samples/BasicBot/Program.cs View File

@@ -0,0 +1,112 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Discord;
using Discord.WebSocket;

namespace BasicBot
{
// This is a minimal, bare-bones example of using Discord.Net.
//
// If writing a bot with commands/interactions, we recommend using the Discord.Net.Commands/Discord.Net.Interactions
// framework, rather than handling them yourself, like we do in this sample.
//
// You can find samples of using the command framework:
// - Here, under the TextCommandFramework sample
// - At the guides: https://discordnet.dev/guides/text_commands/intro.html
//
// You can find samples of using the interaction framework:
// - Here, under the InteractionFramework sample
// - At the guides: https://discordnet.dev/guides/int_framework/intro.html
class Program
{
// Non-static readonly fields can only be assigned in a constructor.
// If you want to assign it elsewhere, consider removing the readonly keyword.
private readonly DiscordSocketClient _client;

// Discord.Net heavily utilizes TAP for async, so we create
// an asynchronous context from the beginning.
static void Main(string[] args)
=> new Program()
.MainAsync()
.GetAwaiter()
.GetResult();

public Program()
{
// It is recommended to Dispose of a client when you are finished
// using it, at the end of your app's lifetime.
_client = new DiscordSocketClient();

// Subscribing to client events, so that we may receive them whenever they're invoked.
_client.Log += LogAsync;
_client.Ready += ReadyAsync;
_client.MessageReceived += MessageReceivedAsync;
_client.InteractionCreated += InteractionCreatedAsync;
}

public async Task MainAsync()
{
// Tokens should be considered secret data, and never hard-coded.
await _client.LoginAsync(TokenType.Bot, Environment.GetEnvironmentVariable("token"));
// Different approaches to making your token a secret is by putting them in local .json, .yaml, .xml or .txt files, then reading them on startup.

await _client.StartAsync();

// Block the program until it is closed.
await Task.Delay(Timeout.Infinite);
}

private Task LogAsync(LogMessage log)
{
Console.WriteLine(log.ToString());
return Task.CompletedTask;
}

// The Ready event indicates that the client has opened a
// connection and it is now safe to access the cache.
private Task ReadyAsync()
{
Console.WriteLine($"{_client.CurrentUser} is connected!");

return Task.CompletedTask;
}

// This is not the recommended way to write a bot - consider
// reading over the Commands Framework sample.
private async Task MessageReceivedAsync(SocketMessage message)
{
// The bot should never respond to itself.
if (message.Author.Id == _client.CurrentUser.Id)
return;


if (message.Content == "!ping")
{
// Create a new componentbuilder, in which dropdowns & buttons can be created.
var cb = new ComponentBuilder()
.WithButton("Click me!", "unique-id", ButtonStyle.Primary);

// Send a message with content 'pong', including a button.
// This button needs to be build by calling .Build() before being passed into the call.
await message.Channel.SendMessageAsync("pong!", components: cb.Build());
}
}

// For better functionality & a more developer-friendly approach to handling any kind of interaction, refer to:
// https://discordnet.dev/guides/int_framework/intro.html
private async Task InteractionCreatedAsync(SocketInteraction interaction)
{
// safety-casting is the best way to prevent something being cast from being null.
// If this check does not pass, it could not be cast to said type.
if (interaction is SocketMessageComponent component)
{
// Check for the ID created in the button mentioned above.
if (component.Data.CustomId == "unique-id")
await interaction.RespondAsync("Thank you for clicking my button!");

else Console.WriteLine("An ID has been received that has no handler!");
}
}
}
}

samples/01_basic_ping_bot/01_basic_ping_bot.csproj → samples/BasicBot/_BasicBot.csproj View File


+ 37
- 0
samples/InteractionFramework/Attributes/DoUserCheckAttribute.cs View File

@@ -0,0 +1,37 @@
using Discord;
using Discord.Interactions;
using Discord.WebSocket;
using System;
using System.Threading.Tasks;

namespace InteractionFramework.Attributes
{
internal class DoUserCheck : PreconditionAttribute
{
public override Task<PreconditionResult> CheckRequirementsAsync(IInteractionContext context, ICommandInfo commandInfo, IServiceProvider services)
{
// Check if the component matches the target properly.
if (context.Interaction is not SocketMessageComponent componentContext)
return Task.FromResult(PreconditionResult.FromError("Context unrecognized as component context."));

else
{
// The approach here entirely depends on how you construct your custom ID. In this case, the format is:
// unique-name:*,*

// here the name and wildcards are split by ':'
var param = componentContext.Data.CustomId.Split(':');

// here we determine that we should always check for the first ',' present.
// This will deal with additional wildcards by always selecting the first wildcard present.
if (param.Length > 1 && ulong.TryParse(param[1].Split(',')[0], out ulong id))
return (context.User.Id == id)
// If the user ID
? Task.FromResult(PreconditionResult.FromSuccess())
: Task.FromResult(PreconditionResult.FromError("User ID does not match component ID!"));

else return Task.FromResult(PreconditionResult.FromError("Parse cannot be done if no userID exists."));
}
}
}
}

samples/04_interactions_framework/RequireOwnerAttribute.cs → samples/InteractionFramework/Attributes/RequireOwnerAttribute.cs View File

@@ -6,7 +6,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;


namespace _04_interactions_framework
namespace InteractionFramework.Attributes
{ {
public class RequireOwnerAttribute : PreconditionAttribute public class RequireOwnerAttribute : PreconditionAttribute
{ {

samples/04_interactions_framework/CommandHandler.cs → samples/InteractionFramework/CommandHandler.cs View File

@@ -2,13 +2,10 @@ using Discord;
using Discord.Interactions; using Discord.Interactions;
using Discord.WebSocket; using Discord.WebSocket;
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;


namespace _04_interactions_framework
namespace InteractionFramework
{ {
public class CommandHandler public class CommandHandler
{ {
@@ -27,6 +24,9 @@ namespace _04_interactions_framework
{ {
// Add the public modules that inherit InteractionModuleBase<T> to the InteractionService // Add the public modules that inherit InteractionModuleBase<T> to the InteractionService
await _commands.AddModulesAsync(Assembly.GetEntryAssembly(), _services); await _commands.AddModulesAsync(Assembly.GetEntryAssembly(), _services);
// Another approach to get the assembly of a specific type is:
// typeof(CommandHandler).Assembly



// Process the InteractionCreated payloads to execute Interactions commands // Process the InteractionCreated payloads to execute Interactions commands
_client.InteractionCreated += HandleInteraction; _client.InteractionCreated += HandleInteraction;
@@ -37,6 +37,8 @@ namespace _04_interactions_framework
_commands.ComponentCommandExecuted += ComponentCommandExecuted; _commands.ComponentCommandExecuted += ComponentCommandExecuted;
} }


# region Error Handling

private Task ComponentCommandExecuted (ComponentCommandInfo arg1, Discord.IInteractionContext arg2, IResult arg3) private Task ComponentCommandExecuted (ComponentCommandInfo arg1, Discord.IInteractionContext arg2, IResult arg3)
{ {
if (!arg3.IsSuccess) if (!arg3.IsSuccess)
@@ -123,6 +125,9 @@ namespace _04_interactions_framework


return Task.CompletedTask; return Task.CompletedTask;
} }
# endregion

# region Execution


private async Task HandleInteraction (SocketInteraction arg) private async Task HandleInteraction (SocketInteraction arg)
{ {
@@ -142,5 +147,6 @@ namespace _04_interactions_framework
await arg.GetOriginalResponseAsync().ContinueWith(async (msg) => await msg.Result.DeleteAsync()); await arg.GetOriginalResponseAsync().ContinueWith(async (msg) => await msg.Result.DeleteAsync());
} }
} }
# endregion
} }
} }

+ 10
- 0
samples/InteractionFramework/ExampleEnum.cs View File

@@ -0,0 +1,10 @@
namespace InteractionFramework
{
public enum ExampleEnum
{
First,
Second,
Third,
Fourth
}
}

+ 18
- 0
samples/InteractionFramework/Modules/ComponentModule.cs View File

@@ -0,0 +1,18 @@
using Discord.Interactions;
using Discord.WebSocket;
using InteractionFramework.Attributes;
using System.Threading.Tasks;

namespace InteractionFramework
{
// As with all other modules, we create the context by defining what type of interaction this module is supposed to target.
internal class ComponentModule : InteractionModuleBase<SocketInteractionContext<SocketMessageComponent>>
{
// With the Attribute DoUserCheck you can make sure that only the user this button targets can click it. This is defined by the first wildcard: *.
// See Attributes/DoUserCheckAttribute.cs for elaboration.
[DoUserCheck]
[ComponentInteraction("myButton:*")]
public async Task ClickButtonAsync(string userId)
=> await RespondAsync(text: ":thumbsup: Clicked!");
}
}

samples/04_interactions_framework/Modules/UtilityModule.cs → samples/InteractionFramework/Modules/GeneralModule.cs View File

@@ -1,16 +1,11 @@
using Discord; using Discord;
using Discord.Interactions; using Discord.Interactions;
using Discord.WebSocket;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;


namespace _04_interactions_framework.Modules
namespace InteractionFramework.Modules
{ {
// Interation modules must be public and inherit from an IInterationModuleBase // Interation modules must be public and inherit from an IInterationModuleBase
public class UtilityModule : InteractionModuleBase<SocketInteractionContext>
public class GeneralModule : InteractionModuleBase<SocketInteractionContext>
{ {
// Dependencies can be accessed through Property injection, public properties with public setters will be set by the service provider // Dependencies can be accessed through Property injection, public properties with public setters will be set by the service provider
public InteractionService Commands { get; set; } public InteractionService Commands { get; set; }
@@ -18,7 +13,7 @@ namespace _04_interactions_framework.Modules
private CommandHandler _handler; private CommandHandler _handler;


// Constructor injection is also a valid way to access the dependecies // Constructor injection is also a valid way to access the dependecies
public UtilityModule ( CommandHandler handler )
public GeneralModule(CommandHandler handler)
{ {
_handler = handler; _handler = handler;
} }
@@ -65,7 +60,7 @@ namespace _04_interactions_framework.Modules


// Message Commands can only have one parameter, which must be a type of SocketMessage // Message Commands can only have one parameter, which must be a type of SocketMessage
[MessageCommand("Delete")] [MessageCommand("Delete")]
[RequireOwner]
[Attributes.RequireOwner]
public async Task DeleteMesage(IMessage message) public async Task DeleteMesage(IMessage message)
{ {
await message.DeleteAsync(); await message.DeleteAsync();

+ 30
- 0
samples/InteractionFramework/Modules/MessageCommandModule.cs View File

@@ -0,0 +1,30 @@
using Discord;
using Discord.Interactions;
using Discord.WebSocket;
using System.Threading.Tasks;

namespace InteractionFramework.Modules
{
// A transient module for executing commands. This module will NOT keep any information after the command is executed.
internal class MessageCommandModule : InteractionModuleBase<SocketInteractionContext<SocketMessageCommand>>
{
// Pins a message in the channel it is in.
[MessageCommand("pin")]
public async Task PinMessageAsync(IMessage message)
{
// make a safety cast to check if the message is ISystem- or IUserMessage
if (message is not IUserMessage userMessage)
await RespondAsync(text: ":x: You cant pin system messages!");

// if the pins in this channel are equal to or above 50, no more messages can be pinned.
else if ((await Context.Channel.GetPinnedMessagesAsync()).Count >= 50)
await RespondAsync(text: ":x: You cant pin any more messages, the max has already been reached in this channel!");

else
{
await userMessage.PinAsync();
await RespondAsync(":white_check_mark: Successfully pinned message!");
}
}
}
}

+ 51
- 0
samples/InteractionFramework/Modules/SlashCommandModule.cs View File

@@ -0,0 +1,51 @@
using Discord;
using Discord.Interactions;
using Discord.WebSocket;
using System;
using System.Threading.Tasks;

namespace InteractionFramework.Modules
{
public enum Hobby
{
Gaming,

Art,

Reading
}

// A transient module for executing commands. This module will NOT keep any information after the command is executed.
class SlashCommandModule : InteractionModuleBase<SocketInteractionContext<SocketSlashCommand>>
{
// Will be called before execution. Here you can populate several entities you may want to retrieve before executing a command.
// I.E. database objects
public override void BeforeExecute(ICommandInfo command)
{
// Anything
throw new NotImplementedException();
}

// Will be called after execution
public override void AfterExecute(ICommandInfo command)
{
// Anything
throw new NotImplementedException();
}

[SlashCommand("ping", "Pings the bot and returns its latency.")]
public async Task GreetUserAsync()
=> await RespondAsync(text: $":ping_pong: It took me {Context.Client.Latency}ms to respond to you!", ephemeral: true);

[SlashCommand("hobby", "Choose your hobby from the list!")]
public async Task ChooseAsync(Hobby hobby)
=> await RespondAsync(text: $":thumbsup: Your hobby is: {hobby}.");

[SlashCommand("bitrate", "Gets the bitrate of a specific voice channel.")]
public async Task GetBitrateAsync([ChannelTypes(ChannelType.Voice, ChannelType.Stage)] IChannel channel)
{
var voiceChannel = channel as IVoiceChannel;
await RespondAsync(text: $"This voice channel has a bitrate of {voiceChannel.Bitrate}");
}
}
}

+ 17
- 0
samples/InteractionFramework/Modules/UserCommandModule.cs View File

@@ -0,0 +1,17 @@
using Discord;
using Discord.Interactions;
using Discord.WebSocket;
using System.Threading.Tasks;

namespace InteractionFramework.Modules
{
// A transient module for executing commands. This module will NOT keep any information after the command is executed.
class UserCommandModule : InteractionModuleBase<SocketInteractionContext<SocketUserCommand>>
{
// This command will greet target user in the channel this was executed in.
[UserCommand("greet")]
public async Task GreetUserAsync(IUser user)
=> await RespondAsync(text: $":wave: {Context.User} said hi to you, <@{user.Id}>!");
}
}


samples/04_interactions_framework/Program.cs → samples/InteractionFramework/Program.cs View File

@@ -4,14 +4,14 @@ using Discord.WebSocket;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using System; using System;
using System.Reflection;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;


namespace _04_interactions_framework
namespace InteractionFramework
{ {
class Program class Program
{ {
// Entry point of the program.
static void Main ( string[] args ) static void Main ( string[] args )
{ {
// One of the more flexable ways to access the configuration data is to use the Microsoft's Configuration model, // One of the more flexable ways to access the configuration data is to use the Microsoft's Configuration model,
@@ -24,7 +24,7 @@ namespace _04_interactions_framework
RunAsync(config).GetAwaiter().GetResult(); RunAsync(config).GetAwaiter().GetResult();
} }


static async Task RunAsync (IConfiguration configuration )
static async Task RunAsync (IConfiguration configuration)
{ {
// Dependency injection is a key part of the Interactions framework but it needs to be disposed at the end of the app's lifetime. // Dependency injection is a key part of the Interactions framework but it needs to be disposed at the end of the app's lifetime.
using var services = ConfigureServices(configuration); using var services = ConfigureServices(configuration);
@@ -64,14 +64,12 @@ namespace _04_interactions_framework
} }


static ServiceProvider ConfigureServices ( IConfiguration configuration ) static ServiceProvider ConfigureServices ( IConfiguration configuration )
{
return new ServiceCollection()
=> new ServiceCollection()
.AddSingleton(configuration) .AddSingleton(configuration)
.AddSingleton<DiscordSocketClient>() .AddSingleton<DiscordSocketClient>()
.AddSingleton(x => new InteractionService(x.GetRequiredService<DiscordSocketClient>())) .AddSingleton(x => new InteractionService(x.GetRequiredService<DiscordSocketClient>()))
.AddSingleton<CommandHandler>() .AddSingleton<CommandHandler>()
.BuildServiceProvider(); .BuildServiceProvider();
}


static bool IsDebug ( ) static bool IsDebug ( )
{ {

samples/04_interactions_framework/04_interactions_framework.csproj → samples/InteractionFramework/_InteractionFramework.csproj View File

@@ -3,7 +3,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<RootNamespace>_04_interactions_framework</RootNamespace>
<RootNamespace>InteractionFramework</RootNamespace>
<StartupObject></StartupObject> <StartupObject></StartupObject>
</PropertyGroup> </PropertyGroup>



+ 18
- 0
samples/ShardedClient/Modules/InteractionModule.cs View File

@@ -0,0 +1,18 @@
using Discord.Interactions;
using Discord.WebSocket;
using System.Threading.Tasks;

namespace ShardedClient.Modules
{
// A display of portability, which shows how minimal the difference between the 2 frameworks is.
public class InteractionModule : InteractionModuleBase<ShardedInteractionContext<SocketSlashCommand>>
{
[SlashCommand("info", "Information about this shard.")]
public async Task InfoAsync()
{
var msg = $@"Hi {Context.User}! There are currently {Context.Client.Shards.Count} shards!
This guild is being served by shard number {Context.Client.GetShardFor(Context.Guild).ShardId}";
await RespondAsync(msg);
}
}
}

samples/03_sharded_client/Modules/PublicModule.cs → samples/ShardedClient/Modules/PublicModule.cs View File

@@ -1,7 +1,7 @@
using System.Threading.Tasks;
using Discord.Commands; using Discord.Commands;
using System.Threading.Tasks;


namespace _03_sharded_client.Modules
namespace ShardedClient.Modules
{ {
// Remember to make your module reference the ShardedCommandContext // Remember to make your module reference the ShardedCommandContext
public class PublicModule : ModuleBase<ShardedCommandContext> public class PublicModule : ModuleBase<ShardedCommandContext>

samples/03_sharded_client/Program.cs → samples/ShardedClient/Program.cs View File

@@ -1,13 +1,14 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using _03_sharded_client.Services;
using Discord; using Discord;
using Discord.Commands; using Discord.Commands;
using Discord.Interactions;
using Discord.WebSocket; using Discord.WebSocket;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using ShardedClient.Services;
using System;
using System.Threading;
using System.Threading.Tasks;


namespace _03_sharded_client
namespace ShardedClient
{ {
// This is a minimal example of using Discord.Net's Sharded Client // This is a minimal example of using Discord.Net's Sharded Client
// The provided DiscordShardedClient class simplifies having multiple // The provided DiscordShardedClient class simplifies having multiple
@@ -15,7 +16,11 @@ namespace _03_sharded_client
class Program class Program
{ {
static void Main(string[] args) static void Main(string[] args)
=> new Program().MainAsync().GetAwaiter().GetResult();
=> new Program()
.MainAsync()
.GetAwaiter()
.GetResult();

public async Task MainAsync() public async Task MainAsync()
{ {
// You specify the amount of shards you'd like to have with the // You specify the amount of shards you'd like to have with the
@@ -40,6 +45,7 @@ namespace _03_sharded_client
client.ShardReady += ReadyAsync; client.ShardReady += ReadyAsync;
client.Log += LogAsync; client.Log += LogAsync;


await services.GetRequiredService<InteractionHandlingService>().InitializeAsync();
await services.GetRequiredService<CommandHandlingService>().InitializeAsync(); await services.GetRequiredService<CommandHandlingService>().InitializeAsync();


// Tokens should be considered secret data, and never hard-coded. // Tokens should be considered secret data, and never hard-coded.
@@ -51,13 +57,13 @@ namespace _03_sharded_client
} }


private ServiceProvider ConfigureServices(DiscordSocketConfig config) private ServiceProvider ConfigureServices(DiscordSocketConfig config)
{
return new ServiceCollection()
=> new ServiceCollection()
.AddSingleton(new DiscordShardedClient(config)) .AddSingleton(new DiscordShardedClient(config))
.AddSingleton<CommandService>() .AddSingleton<CommandService>()
.AddSingleton(x => new InteractionService(x.GetRequiredService<DiscordShardedClient>()))
.AddSingleton<CommandHandlingService>() .AddSingleton<CommandHandlingService>()
.AddSingleton<InteractionHandlingService>()
.BuildServiceProvider(); .BuildServiceProvider();
}




private Task ReadyAsync(DiscordSocketClient shard) private Task ReadyAsync(DiscordSocketClient shard)

samples/03_sharded_client/Services/CommandHandlingService.cs → samples/ShardedClient/Services/CommandHandlingService.cs View File

@@ -1,12 +1,12 @@
using System;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Discord; using Discord;
using Discord.Commands; using Discord.Commands;
using Discord.WebSocket; using Discord.WebSocket;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Reflection;
using System.Threading.Tasks;


namespace _03_sharded_client.Services
namespace ShardedClient.Services
{ {
public class CommandHandlingService public class CommandHandlingService
{ {
@@ -33,7 +33,7 @@ namespace _03_sharded_client.Services
public async Task MessageReceivedAsync(SocketMessage rawMessage) public async Task MessageReceivedAsync(SocketMessage rawMessage)
{ {
// Ignore system messages, or messages from other bots // Ignore system messages, or messages from other bots
if (!(rawMessage is SocketUserMessage message))
if (rawMessage is not SocketUserMessage message)
return; return;
if (message.Source != MessageSource.User) if (message.Source != MessageSource.User)
return; return;
@@ -59,7 +59,7 @@ namespace _03_sharded_client.Services
return; return;


// the command failed, let's notify the user that something happened. // the command failed, let's notify the user that something happened.
await context.Channel.SendMessageAsync($"error: {result.ToString()}");
await context.Channel.SendMessageAsync($"error: {result}");
} }


private Task LogAsync(LogMessage log) private Task LogAsync(LogMessage log)

+ 57
- 0
samples/ShardedClient/Services/InteractionHandlingService.cs View File

@@ -0,0 +1,57 @@
using Discord;
using Discord.Interactions;
using Discord.WebSocket;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Linq;
using System.Threading.Tasks;

namespace ShardedClient.Services
{
public class InteractionHandlingService
{
private readonly InteractionService _service;
private readonly DiscordShardedClient _client;
private readonly IServiceProvider _provider;

public InteractionHandlingService(IServiceProvider services)
{
_service = services.GetRequiredService<InteractionService>();
_client = services.GetRequiredService<DiscordShardedClient>();
_provider = services;

_service.Log += LogAsync;
_client.InteractionCreated += OnInteractionAsync;
// For examples on how to handle post execution,
// see the InteractionFramework samples.
}

// Register all modules, and add the commands from these modules to either guild or globally depending on the build state.
public async Task InitializeAsync()
{
await _service.AddModulesAsync(typeof(InteractionHandlingService).Assembly, _provider);
#if DEBUG
await _service.AddCommandsToGuildAsync(_client.Guilds.First(x => x.Id == 1));
#else
await _service.AddCommandsGloballyAsync();
#endif
}

private async Task OnInteractionAsync(SocketInteraction interaction)
{
_ = Task.Run(async () =>
{
var context = new ShardedInteractionContext(_client, interaction);
await _service.ExecuteCommandAsync(context, _provider);
});
await Task.CompletedTask;
}

private Task LogAsync(LogMessage log)
{
Console.WriteLine(log.ToString());

return Task.CompletedTask;
}
}
}

samples/03_sharded_client/03_sharded_client.csproj → samples/ShardedClient/_ShardedClient.csproj View File

@@ -3,7 +3,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<RootNamespace>_03_sharded_client</RootNamespace>
<RootNamespace>ShardedClient</RootNamespace>
</PropertyGroup> </PropertyGroup>


<ItemGroup> <ItemGroup>
@@ -12,6 +12,7 @@


<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Discord.Net.Commands\Discord.Net.Commands.csproj" /> <ProjectReference Include="..\..\src\Discord.Net.Commands\Discord.Net.Commands.csproj" />
<ProjectReference Include="..\..\src\Discord.Net.Interactions\Discord.Net.Interactions.csproj" />
<ProjectReference Include="..\..\src\Discord.Net.WebSocket\Discord.Net.WebSocket.csproj" /> <ProjectReference Include="..\..\src\Discord.Net.WebSocket\Discord.Net.WebSocket.csproj" />
</ItemGroup> </ItemGroup>



samples/02_commands_framework/Modules/PublicModule.cs → samples/TextCommandFramework/Modules/PublicModule.cs View File

@@ -1,10 +1,10 @@
using System.IO;
using System.Threading.Tasks;
using Discord; using Discord;
using Discord.Commands; using Discord.Commands;
using _02_commands_framework.Services;
using System.IO;
using System.Threading.Tasks;
using TextCommandFramework.Services;


namespace _02_commands_framework.Modules
namespace TextCommandFramework.Modules
{ {
// Modules must be public and inherit from an IModuleBase // Modules must be public and inherit from an IModuleBase
public class PublicModule : ModuleBase<SocketCommandContext> public class PublicModule : ModuleBase<SocketCommandContext>

samples/02_commands_framework/Program.cs → samples/TextCommandFramework/Program.cs View File

@@ -1,14 +1,14 @@
using Discord;
using Discord.Commands;
using Discord.WebSocket;
using Microsoft.Extensions.DependencyInjection;
using System; using System;
using System.Net.Http; using System.Net.Http;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Discord;
using Discord.WebSocket;
using Discord.Commands;
using _02_commands_framework.Services;
using TextCommandFramework.Services;


namespace _02_commands_framework
namespace TextCommandFramework
{ {
// This is a minimal example of using Discord.Net's command // This is a minimal example of using Discord.Net's command
// framework - by no means does it show everything the framework // framework - by no means does it show everything the framework

samples/02_commands_framework/Services/CommandHandlingService.cs → samples/TextCommandFramework/Services/CommandHandlingService.cs View File

@@ -1,12 +1,12 @@
using System;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Discord; using Discord;
using Discord.Commands; using Discord.Commands;
using Discord.WebSocket; using Discord.WebSocket;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Reflection;
using System.Threading.Tasks;


namespace _02_commands_framework.Services
namespace TextCommandFramework.Services
{ {
public class CommandHandlingService public class CommandHandlingService
{ {
@@ -36,21 +36,24 @@ namespace _02_commands_framework.Services
public async Task MessageReceivedAsync(SocketMessage rawMessage) public async Task MessageReceivedAsync(SocketMessage rawMessage)
{ {
// Ignore system messages, or messages from other bots // Ignore system messages, or messages from other bots
if (!(rawMessage is SocketUserMessage message)) return;
if (message.Source != MessageSource.User) return;
if (!(rawMessage is SocketUserMessage message))
return;
if (message.Source != MessageSource.User)
return;


// This value holds the offset where the prefix ends // This value holds the offset where the prefix ends
var argPos = 0; var argPos = 0;
// Perform prefix check. You may want to replace this with // Perform prefix check. You may want to replace this with
// (!message.HasCharPrefix('!', ref argPos)) // (!message.HasCharPrefix('!', ref argPos))
// for a more traditional command format like !help. // for a more traditional command format like !help.
if (!message.HasMentionPrefix(_discord.CurrentUser, ref argPos)) return;
if (!message.HasMentionPrefix(_discord.CurrentUser, ref argPos))
return;


var context = new SocketCommandContext(_discord, message); var context = new SocketCommandContext(_discord, message);
// Perform the execution of the command. In this method, // Perform the execution of the command. In this method,
// the command service will perform precondition and parsing check // the command service will perform precondition and parsing check
// then execute the command if one is matched. // then execute the command if one is matched.
await _commands.ExecuteAsync(context, argPos, _services);
await _commands.ExecuteAsync(context, argPos, _services);
// Note that normally a result will be returned by this format, but here // Note that normally a result will be returned by this format, but here
// we will handle the result in CommandExecutedAsync, // we will handle the result in CommandExecutedAsync,
} }

samples/02_commands_framework/Services/PictureService.cs → samples/TextCommandFramework/Services/PictureService.cs View File

@@ -2,7 +2,7 @@ using System.IO;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;


namespace _02_commands_framework.Services
namespace TextCommandFramework.Services
{ {
public class PictureService public class PictureService
{ {

samples/02_commands_framework/02_commands_framework.csproj → samples/TextCommandFramework/_TextCommandFramework.csproj View File

@@ -3,6 +3,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<RootNamespace>TextCommandFramework</RootNamespace>
</PropertyGroup> </PropertyGroup>


<ItemGroup> <ItemGroup>

samples/04_webhook_client/Program.cs → samples/WebhookClient/Program.cs View File

@@ -2,7 +2,7 @@ using Discord;
using Discord.Webhook; using Discord.Webhook;
using System.Threading.Tasks; using System.Threading.Tasks;


namespace _04_webhook_client
namespace WebHookClient
{ {
// This is a minimal example of using Discord.Net's Webhook Client // This is a minimal example of using Discord.Net's Webhook Client
// Webhooks are send-only components of Discord that allow you to make a POST request // Webhooks are send-only components of Discord that allow you to make a POST request

samples/04_webhook_client/04_webhook_client.csproj → samples/WebhookClient/_WebhookClient.csproj View File

@@ -2,8 +2,8 @@


<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
<RootNamespace>_04_webhook_client</RootNamespace>
<TargetFramework>net5.0</TargetFramework>
<RootNamespace>WebHookClient</RootNamespace>
</PropertyGroup> </PropertyGroup>


<ItemGroup> <ItemGroup>

+ 74
- 0
samples/_idn/Inspector.cs View File

@@ -0,0 +1,74 @@
using System.Collections;
using System.Linq;
using System.Reflection;
using System.Text;

namespace Idn
{
public static class Inspector
{
public static string Inspect(object value)
{
var builder = new StringBuilder();
if (value != null)
{
var type = value.GetType().GetTypeInfo();
builder.AppendLine($"[{type.Namespace}.{type.Name}]");
builder.AppendLine($"{InspectProperty(value)}");

if (value is IEnumerable)
{
var items = (value as IEnumerable).Cast<object>().ToArray();
if (items.Length > 0)
{
builder.AppendLine();
foreach (var item in items)
builder.AppendLine($"- {InspectProperty(item)}");
}
}
else
{
var groups = type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(x => x.GetIndexParameters().Length == 0)
.GroupBy(x => x.Name)
.OrderBy(x => x.Key)
.ToArray();
if (groups.Length > 0)
{
builder.AppendLine();
int pad = groups.Max(x => x.Key.Length) + 1;
foreach (var group in groups)
builder.AppendLine($"{group.Key.PadRight(pad, ' ')}{InspectProperty(group.First().GetValue(value))}");
}
}
}
else
builder.AppendLine("null");
return builder.ToString();
}

private static string InspectProperty(object obj)
{
if (obj == null)
return "null";

var type = obj.GetType();

var debuggerDisplay = type.GetProperty("DebuggerDisplay", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (debuggerDisplay != null)
return debuggerDisplay.GetValue(obj).ToString();

var toString = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where(x => x.Name == "ToString" && x.DeclaringType != typeof(object))
.FirstOrDefault();
if (toString != null)
return obj.ToString();

var count = type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (count != null)
return $"[{count.GetValue(obj)} Items]";

return obj.ToString();
}
}
}

+ 152
- 0
samples/_idn/Program.cs View File

@@ -0,0 +1,152 @@
using Discord;
using Discord.WebSocket;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Idn
{
public class Program
{
public static readonly string[] Imports =
{
"System",
"System.Collections.Generic",
"System.Linq",
"System.Threading.Tasks",
"System.Diagnostics",
"System.IO",
"Discord",
"Discord.Rest",
"Discord.WebSocket",
"idn"
};

static async Task Main(string[] args)
{
var token = File.ReadAllText("token.ignore");
var client = new DiscordSocketClient(new DiscordSocketConfig { LogLevel = LogSeverity.Debug });
var logQueue = new ConcurrentQueue<LogMessage>();
var logCancelToken = new CancellationTokenSource();
int presenceUpdates = 0;

client.Log += msg =>
{
logQueue.Enqueue(msg);
return Task.CompletedTask;
};
Console.CancelKeyPress += (_ev, _s) =>
{
logCancelToken.Cancel();
};

var logTask = Task.Run(async () =>
{
var fs = new FileStream("idn.log", FileMode.Append);
var logStringBuilder = new StringBuilder(200);
string logString = "";

byte[] helloBytes = Encoding.UTF8.GetBytes($"### new log session: {DateTime.Now} ###\n\n");
await fs.WriteAsync(helloBytes);

while (!logCancelToken.IsCancellationRequested)
{
if (logQueue.TryDequeue(out var msg))
{
if (msg.Message?.IndexOf("PRESENCE_UPDATE)") > 0)
{
presenceUpdates++;
continue;
}

_ = msg.ToString(builder: logStringBuilder);
logStringBuilder.AppendLine();
logString = logStringBuilder.ToString();

Debug.Write(logString, "DNET");
await fs.WriteAsync(Encoding.UTF8.GetBytes(logString));
}
await fs.FlushAsync();
try
{
await Task.Delay(100, logCancelToken.Token);
}
finally { }
}

byte[] goodbyeBytes = Encoding.UTF8.GetBytes($"#!! end log session: {DateTime.Now} !!#\n\n\n");
await fs.WriteAsync(goodbyeBytes);
await fs.DisposeAsync();
});

await client.LoginAsync(TokenType.Bot, token);
await client.StartAsync();

var options = ScriptOptions.Default
.AddReferences(GetAssemblies().ToArray())
.AddImports(Imports);

var globals = new ScriptGlobals
{
Client = client,
PUCount = -1,
};

while (true)
{
Console.Write("> ");
string input = Console.ReadLine();

if (input == "quit!")
{
break;
}

object eval;
try
{
globals.PUCount = presenceUpdates;
eval = await CSharpScript.EvaluateAsync(input, options, globals);
}
catch (Exception e)
{
eval = e;
}
Console.WriteLine(Inspector.Inspect(eval));
}

await client.StopAsync();
client.Dispose();
logCancelToken.Cancel();
try
{ await logTask; }
finally { Console.WriteLine("goodbye!"); }
}

static IEnumerable<Assembly> GetAssemblies()
{
var Assemblies = Assembly.GetEntryAssembly().GetReferencedAssemblies();
foreach (var a in Assemblies)
{
var asm = Assembly.Load(a);
yield return asm;
}
yield return Assembly.GetEntryAssembly();
}

public class ScriptGlobals
{
public DiscordSocketClient Client { get; set; }
public int PUCount { get; set; }
}
}
}

+ 16
- 0
samples/_idn/idn.csproj View File

@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="3.11.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Discord.Net.WebSocket\Discord.Net.WebSocket.csproj" />
</ItemGroup>

</Project>

+ 1
- 0
samples/_idn/logview.ps1 View File

@@ -0,0 +1 @@
Get-Content .\bin\Debug\netcoreapp3.1\idn.log -Tail 3 -Wait

+ 8
- 8
samples/idn/Program.cs View File

@@ -1,17 +1,17 @@
using Discord;
using Discord.WebSocket;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
using Discord;
using Discord.WebSocket;
using System.Collections.Concurrent;
using System.Threading;
using System.Text; using System.Text;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;


namespace Idn namespace Idn
{ {


+ 9
- 5
src/Discord.Net.Examples/Core/Entities/Channels/IGuildChannel.Examples.cs View File

@@ -1,6 +1,6 @@
using JetBrains.Annotations;
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations;


namespace Discord.Net.Examples.Core.Entities.Channels namespace Discord.Net.Examples.Core.Entities.Channels
{ {
@@ -11,8 +11,10 @@ namespace Discord.Net.Examples.Core.Entities.Channels


public async Task MuteRoleAsync(IRole role, IGuildChannel channel) public async Task MuteRoleAsync(IRole role, IGuildChannel channel)
{ {
if (role == null) throw new ArgumentNullException(nameof(role));
if (channel == null) throw new ArgumentNullException(nameof(channel));
if (role == null)
throw new ArgumentNullException(nameof(role));
if (channel == null)
throw new ArgumentNullException(nameof(channel));


// Fetches the previous overwrite and bail if one is found // Fetches the previous overwrite and bail if one is found
var previousOverwrite = channel.GetPermissionOverwrite(role); var previousOverwrite = channel.GetPermissionOverwrite(role);
@@ -29,8 +31,10 @@ namespace Discord.Net.Examples.Core.Entities.Channels


public async Task MuteUserAsync(IGuildUser user, IGuildChannel channel) public async Task MuteUserAsync(IGuildUser user, IGuildChannel channel)
{ {
if (user == null) throw new ArgumentNullException(nameof(user));
if (channel == null) throw new ArgumentNullException(nameof(channel));
if (user == null)
throw new ArgumentNullException(nameof(user));
if (channel == null)
throw new ArgumentNullException(nameof(channel));


// Fetches the previous overwrite and bail if one is found // Fetches the previous overwrite and bail if one is found
var previousOverwrite = channel.GetPermissionOverwrite(user); var previousOverwrite = channel.GetPermissionOverwrite(user);


+ 5
- 4
src/Discord.Net.Examples/Core/Entities/Channels/IMessageChannel.Examples.cs View File

@@ -1,8 +1,8 @@
using JetBrains.Annotations;
using System; using System;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations;


namespace Discord.Net.Examples.Core.Entities.Channels namespace Discord.Net.Examples.Core.Entities.Channels
{ {
@@ -90,7 +90,7 @@ namespace Discord.Net.Examples.Core.Entities.Channels
#region SendFileAsync.FilePath.EmbeddedImage #region SendFileAsync.FilePath.EmbeddedImage


await channel.SendFileAsync("b1nzy.jpg", await channel.SendFileAsync("b1nzy.jpg",
embed: new EmbedBuilder {ImageUrl = "attachment://b1nzy.jpg"}.Build());
embed: new EmbedBuilder { ImageUrl = "attachment://b1nzy.jpg" }.Build());


#endregion #endregion


@@ -99,13 +99,14 @@ namespace Discord.Net.Examples.Core.Entities.Channels


using (var b1nzyStream = await httpClient.GetStreamAsync("https://example.com/b1nzy")) using (var b1nzyStream = await httpClient.GetStreamAsync("https://example.com/b1nzy"))
await channel.SendFileAsync(b1nzyStream, "b1nzy.jpg", await channel.SendFileAsync(b1nzyStream, "b1nzy.jpg",
embed: new EmbedBuilder {ImageUrl = "attachment://b1nzy.jpg"}.Build());
embed: new EmbedBuilder { ImageUrl = "attachment://b1nzy.jpg" }.Build());


#endregion #endregion


#region EnterTypingState #region EnterTypingState


using (channel.EnterTypingState()) await LongRunningAsync();
using (channel.EnterTypingState())
await LongRunningAsync();


#endregion #endregion
} }


+ 1
- 1
src/Discord.Net.Examples/Core/Entities/Users/IUser.Examples.cs View File

@@ -1,7 +1,7 @@
using JetBrains.Annotations;
using System; using System;
using System.Net; using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations;


namespace Discord.Net.Examples.Core.Entities.Users namespace Discord.Net.Examples.Core.Entities.Users
{ {


+ 9
- 6
src/Discord.Net.Examples/WebSocket/BaseSocketClient.Events.Examples.cs View File

@@ -1,8 +1,8 @@
using Discord.WebSocket;
using JetBrains.Annotations;
using System; using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Discord.WebSocket;
using JetBrains.Annotations;


namespace Discord.Net.Examples.WebSocket namespace Discord.Net.Examples.WebSocket
{ {
@@ -74,7 +74,7 @@ namespace Discord.Net.Examples.WebSocket


#region MessageReceived #region MessageReceived


private readonly ulong[] _targetUserIds = {168693960628371456, 53905483156684800};
private readonly ulong[] _targetUserIds = { 168693960628371456, 53905483156684800 };


public void HookMessageReceived(BaseSocketClient client) public void HookMessageReceived(BaseSocketClient client)
=> client.MessageReceived += HandleMessageReceived; => client.MessageReceived += HandleMessageReceived;
@@ -82,9 +82,11 @@ namespace Discord.Net.Examples.WebSocket
public Task HandleMessageReceived(SocketMessage message) public Task HandleMessageReceived(SocketMessage message)
{ {
// check if the message is a user message as opposed to a system message (e.g. Clyde, pins, etc.) // check if the message is a user message as opposed to a system message (e.g. Clyde, pins, etc.)
if (!(message is SocketUserMessage userMessage)) return Task.CompletedTask;
if (!(message is SocketUserMessage userMessage))
return Task.CompletedTask;
// check if the message origin is a guild message channel // check if the message origin is a guild message channel
if (!(userMessage.Channel is SocketTextChannel textChannel)) return Task.CompletedTask;
if (!(userMessage.Channel is SocketTextChannel textChannel))
return Task.CompletedTask;
// check if the target user was mentioned // check if the target user was mentioned
var targetUsers = userMessage.MentionedUsers.Where(x => _targetUserIds.Contains(x.Id)); var targetUsers = userMessage.MentionedUsers.Where(x => _targetUserIds.Contains(x.Id));
foreach (var targetUser in targetUsers) foreach (var targetUser in targetUsers)
@@ -103,7 +105,8 @@ namespace Discord.Net.Examples.WebSocket
public async Task HandleMessageDelete(Cacheable<IMessage, ulong> cachedMessage, Cacheable<IMessageChannel, ulong> cachedChannel) public async Task HandleMessageDelete(Cacheable<IMessage, ulong> cachedMessage, Cacheable<IMessageChannel, ulong> cachedChannel)
{ {
// check if the message exists in cache; if not, we cannot report what was removed // check if the message exists in cache; if not, we cannot report what was removed
if (!cachedMessage.HasValue) return;
if (!cachedMessage.HasValue)
return;
// gets or downloads the channel if it's not in the cache // gets or downloads the channel if it's not in the cache
IMessageChannel channel = await cachedChannel.GetOrDownloadAsync(); IMessageChannel channel = await cachedChannel.GetOrDownloadAsync();
var message = cachedMessage.Value; var message = cachedMessage.Value;


Loading…
Cancel
Save