* 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 suggestionstags/3.2.1
| @@ -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} | ||||
| @@ -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. | |||||
| @@ -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? | ||||
| @@ -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 | ||||
| @@ -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 | ||||
| @@ -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. | |||||
| @@ -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 | |||||
|  | |||||
| ### 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 | |||||
|  | |||||
| * 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 | |||||
|  | |||||
| * 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 | |||||
|  | |||||
| * 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 | ||||
| @@ -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)] | |||||
| @@ -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(); | |||||
| @@ -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. | |||||
| } | |||||
| @@ -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); | |||||
| } | |||||
| @@ -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. | |||||
| @@ -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. | |||||
| @@ -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; | |||||
| @@ -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 | ||||
| @@ -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!"); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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 | |||||
| } | |||||
| } | |||||
| @@ -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!"); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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.")); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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 | ||||
| { | { | ||||
| @@ -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 | |||||
| } | } | ||||
| } | } | ||||
| @@ -0,0 +1,10 @@ | |||||
| namespace InteractionFramework | |||||
| { | |||||
| public enum ExampleEnum | |||||
| { | |||||
| First, | |||||
| Second, | |||||
| Third, | |||||
| Fourth | |||||
| } | |||||
| } | |||||
| @@ -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!"); | |||||
| } | |||||
| } | |||||
| @@ -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(); | ||||
| @@ -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!"); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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}"); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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}>!"); | |||||
| } | |||||
| } | |||||
| @@ -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 ( ) | ||||
| { | { | ||||
| @@ -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> | ||||
| @@ -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); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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> | ||||
| @@ -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) | ||||
| @@ -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) | ||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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> | ||||
| @@ -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> | ||||
| @@ -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 | ||||
| @@ -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, | ||||
| } | } | ||||
| @@ -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 | ||||
| { | { | ||||
| @@ -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> | ||||
| @@ -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 | ||||
| @@ -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> | ||||
| @@ -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(); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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; } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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> | |||||
| @@ -0,0 +1 @@ | |||||
| Get-Content .\bin\Debug\netcoreapp3.1\idn.log -Tail 3 -Wait | |||||
| @@ -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 | ||||
| { | { | ||||
| @@ -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); | ||||
| @@ -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,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 | ||||
| { | { | ||||
| @@ -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; | ||||