diff --git a/Discord.Net.sln b/Discord.Net.sln index c22d91e27..fc68eb71c 100644 --- a/Discord.Net.sln +++ b/Discord.Net.sln @@ -4,43 +4,45 @@ VisualStudioVersion = 17.1.31903.286 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Core", "src\Discord.Net.Core\Discord.Net.Core.csproj", "{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}" EndProject -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}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Commands", "src\Discord.Net.Commands\Discord.Net.Commands.csproj", "{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.WebSocket", "src\Discord.Net.WebSocket\Discord.Net.WebSocket.csproj", "{688FD1D8-7F01-4539-B2E9-F473C5D699C7}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions", "Extensions", "{CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Webhook", "src\Discord.Net.Webhook\Discord.Net.Webhook.csproj", "{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}" EndProject -Project("{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 -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 -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 -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 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 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 -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 -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 -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 -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 -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 -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 -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 Global 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|x86.ActiveCfg = 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.Build.0 = 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|x86.ActiveCfg = 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.Build.0 = 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|x86.ActiveCfg = Release|Any CPU {A23E46D2-1610-4AE5-820F-422D34810887}.Release|x86.Build.0 = Release|Any CPU - {24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}.Debug|x64.ActiveCfg = Debug|Any CPU - {24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}.Debug|x64.Build.0 = Debug|Any CPU - {24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}.Debug|x86.ActiveCfg = Debug|Any CPU - {24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}.Debug|x86.Build.0 = Debug|Any CPU - {24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}.Release|Any CPU.Build.0 = Release|Any CPU - {24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}.Release|x64.ActiveCfg = Release|Any CPU - {24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}.Release|x64.Build.0 = Release|Any CPU - {24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}.Release|x86.ActiveCfg = Release|Any CPU - {24C231FD-8CF3-444A-9E7C-45C18BAD4A0D}.Release|x86.Build.0 = Release|Any CPU + {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 GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -253,17 +267,18 @@ Global {078DD7E6-943D-4D09-AFC2-D2BA58B76C9C} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A} {688FD1D8-7F01-4539-B2E9-F473C5D699C7} = {288C363D-A636-4EAE-9AC1-4698B641B26E} {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} {4E1F1F40-B1DD-40C9-A4B1-A2046A4C9C76} = {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} - {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 GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {D2404771-EEC8-45F2-9D71-F3373F6C1495} diff --git a/README.md b/README.md index cf0293359..541948f4b 100644 --- a/README.md +++ b/README.md @@ -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. 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. diff --git a/docs/faq/basics/basic-operations.md b/docs/faq/basics/basic-operations.md index d6121dbb0..6adfa1f1f 100644 --- a/docs/faq/basics/basic-operations.md +++ b/docs/faq/basics/basic-operations.md @@ -53,7 +53,7 @@ able to message. You may check the message channel type. Visit [Glossary] to see the 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? diff --git a/docs/faq/misc/legacy.md b/docs/faq/misc/legacy.md index ddb2d03c6..fbfb41ac2 100644 --- a/docs/faq/misc/legacy.md +++ b/docs/faq/misc/legacy.md @@ -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 [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 diff --git a/docs/faq/toc.yml b/docs/faq/toc.yml index 5a7e7e7f2..2f04dc98c 100644 --- a/docs/faq/toc.yml +++ b/docs/faq/toc.yml @@ -16,7 +16,5 @@ topicUid: FAQ.Commands.Interactions - name: Dependency Injection topicUid: FAQ.Commands.DI -- name: Glossary - topicUid: FAQ.Glossary - name: Legacy or Upgrade topicUid: FAQ.Legacy diff --git a/docs/guides/entities/casting.md b/docs/guides/entities/casting.md new file mode 100644 index 000000000..3a314c67f --- /dev/null +++ b/docs/guides/entities/casting.md @@ -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. diff --git a/docs/faq/misc/glossary.md b/docs/guides/entities/glossary.md similarity index 58% rename from docs/faq/misc/glossary.md rename to docs/guides/entities/glossary.md index 232690917..4ac6dd593 100644 --- a/docs/faq/misc/glossary.md +++ b/docs/guides/entities/glossary.md @@ -1,29 +1,19 @@ --- -uid: FAQ.Glossary -title: Common Terminologies / Glossary +uid: Guides.Entities.Glossary +title: Glossary & Flowcharts --- -# Glossary +# Entity Types -This is an additional chapter for quick references to various common -types that you may see within Discord.Net. To see more information -regarding each type of object, click on the object to navigate -to our API documentation page where you might find more explanation -about it. +A list of all Discord.Net entities, what they can be cast to and what their properties are. -## Common Types - -* A **Guild** ([IGuild]) is an isolated collection of users and -channels, and are often referred to as "servers". - - Example: [Discord API](https://discord.gg/jkrBmQR) -* A **Channel** ([IChannel]) represents a generic channel. - - Example: #dotnet_discord-net - - See [Channel Types](#channel-types) +> [!NOTE] +> All interfaces have the same inheritance tree for both `Socket` and `Rest` entities. +> Entities with that have been marked red are exclusive to the project they source from. -[IGuild]: xref:Discord.IGuild -[IChannel]: xref:Discord.IChannel +## Channels -## Channel Types +![IChannelChart](images/IChannel.png) ### Message Channels * 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. * A **Voice Channel** ([IVoiceChannel]) is a voice channel in a guild. * A **Stage Channel** ([IStageChannel]) is a stage channel in a guild. -* A **Category Channel** ([ICategoryChannel]) (2.0+) is a category that +* A **Category Channel** ([ICategoryChannel]) is a category that 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. -> [!NOTE] -> A Channel ([IChannel]) can be all types of channels. - [INestedChannel]: xref:Discord.INestedChannel [IGuildChannel]: xref:Discord.IGuildChannel [IMessageChannel]: xref:Discord.IMessageChannel @@ -62,17 +49,27 @@ exist under a category. [IStageChannel]: xref:Discord.IStageChannel [INewsChannel]: xref:Discord.INewsChannel -## Message Types +## Messages + +![IMessageChart](images/IMessage.png) +* A **Rest Followup Message** ([RestFollowupMessage]) is a message returned by followup on on an interaction. +* A **Rest Interaction Message** ([RestInteractionMessage]) is a message returned by the interaction's original response. +* A **Rest User Message** ([RestUserMessage]) is a message sent over rest; it can be any of the above. * An **User Message** ([IUserMessage]) is a message sent by a user. * A **System Message** ([ISystemMessage]) is a message sent by Discord itself. * 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 [ISystemMessage]: xref:Discord.ISystemMessage [IMessage]: xref:Discord.IMessage -## User Types +## Users + +![IUserChart](images/IUser.png) * A **Guild User** ([IGuildUser]) is a user available inside a guild. * A **Group User** ([IGroupUser]) is a user available inside a group. @@ -85,7 +82,29 @@ exist under a category. [ISelfUser]: xref:Discord.ISelfUser [IUser]: xref:Discord.IUser -## Emoji Types +## Interactions + +![IInteractionChart](images/IInteraction.png) + +* A **Slash command** ([ISlashCommandInteraction]) is an application command executed in the text box, with provided parameters. +* A **Message Command** ([IMessageCommandInteraction]) is an application command targetting a message. +* An **User Command** ([IUserCommandInteraction]) is an application command targetting a user. +* An **Application Command** ([IApplicationCommandInteraction]) is any of the above. +* A **Message component** ([IMessageComponent]) is the interaction of a button being clicked/dropdown option(s) entered. +* An **Autocomplete Interaction** ([IAutocompleteinteraction]) is an interaction that has been automatically completed. +* An **Interaction** ([IDiscordInteraction]) is any of the above. + +[ISlashCommandInteraction]: xref:Discord.ISlashCommandInteraction +[IMessageCommandInteraction]: xref:Discord.IMessageCommandInteraction +[IUserCommandInteraction]: xref:Discord.IUserCommandInteraction +[IApplicationCommandInteraction]: xref:Discord.IApplicationCommandInteraction +[IMessageComponent]: xref:Discord.IMessageComponent +[IAutocompleteinteraction]: xref:Discord.IAutocompleteInteraction +[IDiscordInteraction]: xref:Discord.IDiscordInteraction + +## Other types: + +### Emoji * An **Emote** ([Emote]) is a custom emote from a guild. - Example: `<:dotnet:232902710280716288>` @@ -95,8 +114,7 @@ exist under a category. [Emote]: xref:Discord.Emote [Emoji]: xref:Discord.Emoji - -## Sticker Types +### Stickers * A **Sticker** ([ISticker]) is a standard Discord sticker. * A **Custom Sticker ([ICustomSticker]) is a Guild-unique sticker. @@ -104,7 +122,7 @@ exist under a category. [ISticker]: xref:Discord.ISticker [ICustomSticker]: xref:Discord.ICustomSticker -## Activity Types +### Activity * A **Game** ([Game]) refers to a user's game activity. * A **Rich Presence** ([RichGame]) refers to a user's detailed diff --git a/docs/guides/entities/images/IChannel.png b/docs/guides/entities/images/IChannel.png new file mode 100644 index 000000000..e2cda78f3 Binary files /dev/null and b/docs/guides/entities/images/IChannel.png differ diff --git a/docs/guides/entities/images/IInteraction.png b/docs/guides/entities/images/IInteraction.png new file mode 100644 index 000000000..93ca7895d Binary files /dev/null and b/docs/guides/entities/images/IInteraction.png differ diff --git a/docs/guides/entities/images/IMessage.png b/docs/guides/entities/images/IMessage.png new file mode 100644 index 000000000..eff4b1dbe Binary files /dev/null and b/docs/guides/entities/images/IMessage.png differ diff --git a/docs/guides/entities/images/IUser.png b/docs/guides/entities/images/IUser.png new file mode 100644 index 000000000..ae4a969c8 Binary files /dev/null and b/docs/guides/entities/images/IUser.png differ diff --git a/docs/guides/concepts/entities.md b/docs/guides/entities/introduction.md similarity index 60% rename from docs/guides/concepts/entities.md rename to docs/guides/entities/introduction.md index e3ca7db32..46e220bc8 100644 --- a/docs/guides/concepts/entities.md +++ b/docs/guides/entities/introduction.md @@ -1,26 +1,41 @@ --- -uid: Guides.Concepts.Entities -title: Entities +uid: Guides.Entities.Intro +title: Introduction --- # 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 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 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 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 `SocketMessageChannel`. All messages come from channels capable of 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 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 @@ -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 an entity to navigate to its parent. -## Accessing Entities +## Accessing Socket Entities The most basic forms of entities, `SocketGuild`, `SocketUser`, and `SocketChannel` can be pulled from the DiscordSocketClient's global cache, and can be retrieved using the respective `GetXXX` method on 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 entities, e.g., `SocketGuild.GetUser`, which returns a `SocketGuildUser`, or `SocketGuild.GetChannel`, which returns a `SocketGuildChannel`. Again, you may need to cast these objects to get 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)] diff --git a/docs/guides/entities/samples/casting.cs b/docs/guides/entities/samples/casting.cs new file mode 100644 index 000000000..0a7b9d16e --- /dev/null +++ b/docs/guides/entities/samples/casting.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(); diff --git a/docs/guides/entities/samples/restentities.cs b/docs/guides/entities/samples/restentities.cs new file mode 100644 index 000000000..36a817780 --- /dev/null +++ b/docs/guides/entities/samples/restentities.cs @@ -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. +} diff --git a/docs/guides/entities/samples/safety-cast-pass.cs b/docs/guides/entities/samples/safety-cast-pass.cs new file mode 100644 index 000000000..03407746f --- /dev/null +++ b/docs/guides/entities/samples/safety-cast-pass.cs @@ -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); +} diff --git a/docs/guides/entities/samples/safety-cast-var.cs b/docs/guides/entities/samples/safety-cast-var.cs new file mode 100644 index 000000000..bf62a2095 --- /dev/null +++ b/docs/guides/entities/samples/safety-cast-var.cs @@ -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. diff --git a/docs/guides/entities/samples/safety-cast.cs b/docs/guides/entities/samples/safety-cast.cs new file mode 100644 index 000000000..684cff845 --- /dev/null +++ b/docs/guides/entities/samples/safety-cast.cs @@ -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. diff --git a/docs/guides/concepts/samples/entities.cs b/docs/guides/entities/samples/socketentities.cs similarity index 100% rename from docs/guides/concepts/samples/entities.cs rename to docs/guides/entities/samples/socketentities.cs diff --git a/docs/guides/entities/samples/unboxing.cs b/docs/guides/entities/samples/unboxing.cs new file mode 100644 index 000000000..78dd7ea02 --- /dev/null +++ b/docs/guides/entities/samples/unboxing.cs @@ -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; diff --git a/docs/guides/toc.yml b/docs/guides/toc.yml index cf4ea5516..d4f2984f8 100644 --- a/docs/guides/toc.yml +++ b/docs/guides/toc.yml @@ -21,8 +21,14 @@ topicUid: Guides.Concepts.Events - name: Managing Connections 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 items: - name: Introduction diff --git a/samples/01_basic_ping_bot/Program.cs b/samples/01_basic_ping_bot/Program.cs deleted file mode 100644 index 7fbe04993..000000000 --- a/samples/01_basic_ping_bot/Program.cs +++ /dev/null @@ -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!"); - } - } -} diff --git a/samples/04_interactions_framework/ExampleEnum.cs b/samples/04_interactions_framework/ExampleEnum.cs deleted file mode 100644 index 2ea5733c0..000000000 --- a/samples/04_interactions_framework/ExampleEnum.cs +++ /dev/null @@ -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 - } -} diff --git a/samples/BasicBot/Program.cs b/samples/BasicBot/Program.cs new file mode 100644 index 000000000..179dfce05 --- /dev/null +++ b/samples/BasicBot/Program.cs @@ -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!"); + } + } + } +} diff --git a/samples/01_basic_ping_bot/01_basic_ping_bot.csproj b/samples/BasicBot/_BasicBot.csproj similarity index 100% rename from samples/01_basic_ping_bot/01_basic_ping_bot.csproj rename to samples/BasicBot/_BasicBot.csproj diff --git a/samples/InteractionFramework/Attributes/DoUserCheckAttribute.cs b/samples/InteractionFramework/Attributes/DoUserCheckAttribute.cs new file mode 100644 index 000000000..96266cdff --- /dev/null +++ b/samples/InteractionFramework/Attributes/DoUserCheckAttribute.cs @@ -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 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.")); + } + } + } +} diff --git a/samples/04_interactions_framework/RequireOwnerAttribute.cs b/samples/InteractionFramework/Attributes/RequireOwnerAttribute.cs similarity index 96% rename from samples/04_interactions_framework/RequireOwnerAttribute.cs rename to samples/InteractionFramework/Attributes/RequireOwnerAttribute.cs index 2f2493838..7b0e57a46 100644 --- a/samples/04_interactions_framework/RequireOwnerAttribute.cs +++ b/samples/InteractionFramework/Attributes/RequireOwnerAttribute.cs @@ -6,7 +6,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace _04_interactions_framework +namespace InteractionFramework.Attributes { public class RequireOwnerAttribute : PreconditionAttribute { diff --git a/samples/04_interactions_framework/CommandHandler.cs b/samples/InteractionFramework/CommandHandler.cs similarity index 95% rename from samples/04_interactions_framework/CommandHandler.cs rename to samples/InteractionFramework/CommandHandler.cs index 735557da5..9a505246f 100644 --- a/samples/04_interactions_framework/CommandHandler.cs +++ b/samples/InteractionFramework/CommandHandler.cs @@ -2,13 +2,10 @@ using Discord; using Discord.Interactions; using Discord.WebSocket; using System; -using System.Collections.Generic; -using System.Linq; using System.Reflection; -using System.Text; using System.Threading.Tasks; -namespace _04_interactions_framework +namespace InteractionFramework { public class CommandHandler { @@ -27,6 +24,9 @@ namespace _04_interactions_framework { // Add the public modules that inherit InteractionModuleBase to the InteractionService 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 _client.InteractionCreated += HandleInteraction; @@ -37,6 +37,8 @@ namespace _04_interactions_framework _commands.ComponentCommandExecuted += ComponentCommandExecuted; } + # region Error Handling + private Task ComponentCommandExecuted (ComponentCommandInfo arg1, Discord.IInteractionContext arg2, IResult arg3) { if (!arg3.IsSuccess) @@ -123,6 +125,9 @@ namespace _04_interactions_framework return Task.CompletedTask; } + # endregion + + # region Execution private async Task HandleInteraction (SocketInteraction arg) { @@ -142,5 +147,6 @@ namespace _04_interactions_framework await arg.GetOriginalResponseAsync().ContinueWith(async (msg) => await msg.Result.DeleteAsync()); } } + # endregion } } diff --git a/samples/InteractionFramework/ExampleEnum.cs b/samples/InteractionFramework/ExampleEnum.cs new file mode 100644 index 000000000..755f33d17 --- /dev/null +++ b/samples/InteractionFramework/ExampleEnum.cs @@ -0,0 +1,10 @@ +namespace InteractionFramework +{ + public enum ExampleEnum + { + First, + Second, + Third, + Fourth + } +} diff --git a/samples/InteractionFramework/Modules/ComponentModule.cs b/samples/InteractionFramework/Modules/ComponentModule.cs new file mode 100644 index 000000000..643004ded --- /dev/null +++ b/samples/InteractionFramework/Modules/ComponentModule.cs @@ -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> + { + // 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!"); + } +} diff --git a/samples/04_interactions_framework/Modules/UtilityModule.cs b/samples/InteractionFramework/Modules/GeneralModule.cs similarity index 93% rename from samples/04_interactions_framework/Modules/UtilityModule.cs rename to samples/InteractionFramework/Modules/GeneralModule.cs index d6cbb1a9f..78740a960 100644 --- a/samples/04_interactions_framework/Modules/UtilityModule.cs +++ b/samples/InteractionFramework/Modules/GeneralModule.cs @@ -1,16 +1,11 @@ using Discord; using Discord.Interactions; -using Discord.WebSocket; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading.Tasks; -namespace _04_interactions_framework.Modules +namespace InteractionFramework.Modules { // Interation modules must be public and inherit from an IInterationModuleBase - public class UtilityModule : InteractionModuleBase + public class GeneralModule : InteractionModuleBase { // Dependencies can be accessed through Property injection, public properties with public setters will be set by the service provider public InteractionService Commands { get; set; } @@ -18,7 +13,7 @@ namespace _04_interactions_framework.Modules private CommandHandler _handler; // Constructor injection is also a valid way to access the dependecies - public UtilityModule ( CommandHandler handler ) + public GeneralModule(CommandHandler 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 [MessageCommand("Delete")] - [RequireOwner] + [Attributes.RequireOwner] public async Task DeleteMesage(IMessage message) { await message.DeleteAsync(); diff --git a/samples/InteractionFramework/Modules/MessageCommandModule.cs b/samples/InteractionFramework/Modules/MessageCommandModule.cs new file mode 100644 index 000000000..d07d276f5 --- /dev/null +++ b/samples/InteractionFramework/Modules/MessageCommandModule.cs @@ -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> + { + // 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!"); + } + } + } +} diff --git a/samples/InteractionFramework/Modules/SlashCommandModule.cs b/samples/InteractionFramework/Modules/SlashCommandModule.cs new file mode 100644 index 000000000..a066ea18c --- /dev/null +++ b/samples/InteractionFramework/Modules/SlashCommandModule.cs @@ -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> + { + // 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}"); + } + } +} diff --git a/samples/InteractionFramework/Modules/UserCommandModule.cs b/samples/InteractionFramework/Modules/UserCommandModule.cs new file mode 100644 index 000000000..60c5246ce --- /dev/null +++ b/samples/InteractionFramework/Modules/UserCommandModule.cs @@ -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> + { + // 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}>!"); + } +} + diff --git a/samples/04_interactions_framework/Program.cs b/samples/InteractionFramework/Program.cs similarity index 96% rename from samples/04_interactions_framework/Program.cs rename to samples/InteractionFramework/Program.cs index 5dedbfae9..49db29714 100644 --- a/samples/04_interactions_framework/Program.cs +++ b/samples/InteractionFramework/Program.cs @@ -4,14 +4,14 @@ using Discord.WebSocket; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using System; -using System.Reflection; using System.Threading; using System.Threading.Tasks; -namespace _04_interactions_framework +namespace InteractionFramework { class Program { + // Entry point of the program. static void Main ( string[] args ) { // 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(); } - 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. using var services = ConfigureServices(configuration); @@ -64,14 +64,12 @@ namespace _04_interactions_framework } static ServiceProvider ConfigureServices ( IConfiguration configuration ) - { - return new ServiceCollection() + => new ServiceCollection() .AddSingleton(configuration) .AddSingleton() .AddSingleton(x => new InteractionService(x.GetRequiredService())) .AddSingleton() .BuildServiceProvider(); - } static bool IsDebug ( ) { diff --git a/samples/04_interactions_framework/04_interactions_framework.csproj b/samples/InteractionFramework/_InteractionFramework.csproj similarity index 94% rename from samples/04_interactions_framework/04_interactions_framework.csproj rename to samples/InteractionFramework/_InteractionFramework.csproj index 780ab69bd..f11c2bd3d 100644 --- a/samples/04_interactions_framework/04_interactions_framework.csproj +++ b/samples/InteractionFramework/_InteractionFramework.csproj @@ -3,7 +3,7 @@ Exe net5.0 - _04_interactions_framework + InteractionFramework diff --git a/samples/ShardedClient/Modules/InteractionModule.cs b/samples/ShardedClient/Modules/InteractionModule.cs new file mode 100644 index 000000000..089328e7d --- /dev/null +++ b/samples/ShardedClient/Modules/InteractionModule.cs @@ -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> + { + [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); + } + } +} diff --git a/samples/03_sharded_client/Modules/PublicModule.cs b/samples/ShardedClient/Modules/PublicModule.cs similarity index 93% rename from samples/03_sharded_client/Modules/PublicModule.cs rename to samples/ShardedClient/Modules/PublicModule.cs index fad2ba98c..25aa88aaf 100644 --- a/samples/03_sharded_client/Modules/PublicModule.cs +++ b/samples/ShardedClient/Modules/PublicModule.cs @@ -1,7 +1,7 @@ -using System.Threading.Tasks; using Discord.Commands; +using System.Threading.Tasks; -namespace _03_sharded_client.Modules +namespace ShardedClient.Modules { // Remember to make your module reference the ShardedCommandContext public class PublicModule : ModuleBase diff --git a/samples/03_sharded_client/Program.cs b/samples/ShardedClient/Program.cs similarity index 83% rename from samples/03_sharded_client/Program.cs rename to samples/ShardedClient/Program.cs index 753f400a1..717ce1d80 100644 --- a/samples/03_sharded_client/Program.cs +++ b/samples/ShardedClient/Program.cs @@ -1,13 +1,14 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using _03_sharded_client.Services; using Discord; using Discord.Commands; +using Discord.Interactions; using Discord.WebSocket; 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 // The provided DiscordShardedClient class simplifies having multiple @@ -15,7 +16,11 @@ namespace _03_sharded_client class Program { static void Main(string[] args) - => new Program().MainAsync().GetAwaiter().GetResult(); + => new Program() + .MainAsync() + .GetAwaiter() + .GetResult(); + public async Task MainAsync() { // 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.Log += LogAsync; + await services.GetRequiredService().InitializeAsync(); await services.GetRequiredService().InitializeAsync(); // Tokens should be considered secret data, and never hard-coded. @@ -51,13 +57,13 @@ namespace _03_sharded_client } private ServiceProvider ConfigureServices(DiscordSocketConfig config) - { - return new ServiceCollection() + => new ServiceCollection() .AddSingleton(new DiscordShardedClient(config)) .AddSingleton() + .AddSingleton(x => new InteractionService(x.GetRequiredService())) .AddSingleton() + .AddSingleton() .BuildServiceProvider(); - } private Task ReadyAsync(DiscordSocketClient shard) diff --git a/samples/03_sharded_client/Services/CommandHandlingService.cs b/samples/ShardedClient/Services/CommandHandlingService.cs similarity index 95% rename from samples/03_sharded_client/Services/CommandHandlingService.cs rename to samples/ShardedClient/Services/CommandHandlingService.cs index adc91b12c..796188050 100644 --- a/samples/03_sharded_client/Services/CommandHandlingService.cs +++ b/samples/ShardedClient/Services/CommandHandlingService.cs @@ -1,12 +1,12 @@ -using System; -using System.Reflection; -using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; using Discord; using Discord.Commands; 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 { @@ -33,7 +33,7 @@ namespace _03_sharded_client.Services public async Task MessageReceivedAsync(SocketMessage rawMessage) { // Ignore system messages, or messages from other bots - if (!(rawMessage is SocketUserMessage message)) + if (rawMessage is not SocketUserMessage message) return; if (message.Source != MessageSource.User) return; @@ -59,7 +59,7 @@ namespace _03_sharded_client.Services return; // 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) diff --git a/samples/ShardedClient/Services/InteractionHandlingService.cs b/samples/ShardedClient/Services/InteractionHandlingService.cs new file mode 100644 index 000000000..59b479361 --- /dev/null +++ b/samples/ShardedClient/Services/InteractionHandlingService.cs @@ -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(); + _client = services.GetRequiredService(); + _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; + } + } +} diff --git a/samples/03_sharded_client/03_sharded_client.csproj b/samples/ShardedClient/_ShardedClient.csproj similarity index 76% rename from samples/03_sharded_client/03_sharded_client.csproj rename to samples/ShardedClient/_ShardedClient.csproj index c4c42516e..69576ea27 100644 --- a/samples/03_sharded_client/03_sharded_client.csproj +++ b/samples/ShardedClient/_ShardedClient.csproj @@ -3,7 +3,7 @@ Exe net5.0 - _03_sharded_client + ShardedClient @@ -12,6 +12,7 @@ + diff --git a/samples/02_commands_framework/Modules/PublicModule.cs b/samples/TextCommandFramework/Modules/PublicModule.cs similarity index 96% rename from samples/02_commands_framework/Modules/PublicModule.cs rename to samples/TextCommandFramework/Modules/PublicModule.cs index 18423f609..68534e826 100644 --- a/samples/02_commands_framework/Modules/PublicModule.cs +++ b/samples/TextCommandFramework/Modules/PublicModule.cs @@ -1,10 +1,10 @@ -using System.IO; -using System.Threading.Tasks; using Discord; 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 public class PublicModule : ModuleBase diff --git a/samples/02_commands_framework/Program.cs b/samples/TextCommandFramework/Program.cs similarity index 97% rename from samples/02_commands_framework/Program.cs rename to samples/TextCommandFramework/Program.cs index 8a2f37dce..8a18daf72 100644 --- a/samples/02_commands_framework/Program.cs +++ b/samples/TextCommandFramework/Program.cs @@ -1,14 +1,14 @@ +using Discord; +using Discord.Commands; +using Discord.WebSocket; +using Microsoft.Extensions.DependencyInjection; using System; using System.Net.Http; using System.Threading; 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 // framework - by no means does it show everything the framework diff --git a/samples/02_commands_framework/Services/CommandHandlingService.cs b/samples/TextCommandFramework/Services/CommandHandlingService.cs similarity index 92% rename from samples/02_commands_framework/Services/CommandHandlingService.cs rename to samples/TextCommandFramework/Services/CommandHandlingService.cs index 5ec496f78..5dd480424 100644 --- a/samples/02_commands_framework/Services/CommandHandlingService.cs +++ b/samples/TextCommandFramework/Services/CommandHandlingService.cs @@ -1,12 +1,12 @@ -using System; -using System.Reflection; -using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; using Discord; using Discord.Commands; 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 { @@ -36,21 +36,24 @@ namespace _02_commands_framework.Services public async Task MessageReceivedAsync(SocketMessage rawMessage) { // 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 var argPos = 0; // Perform prefix check. You may want to replace this with // (!message.HasCharPrefix('!', ref argPos)) // 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); // Perform the execution of the command. In this method, // the command service will perform precondition and parsing check // 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 // we will handle the result in CommandExecutedAsync, } diff --git a/samples/02_commands_framework/Services/PictureService.cs b/samples/TextCommandFramework/Services/PictureService.cs similarity index 91% rename from samples/02_commands_framework/Services/PictureService.cs rename to samples/TextCommandFramework/Services/PictureService.cs index dda818cc3..5c8e1dd89 100644 --- a/samples/02_commands_framework/Services/PictureService.cs +++ b/samples/TextCommandFramework/Services/PictureService.cs @@ -2,7 +2,7 @@ using System.IO; using System.Net.Http; using System.Threading.Tasks; -namespace _02_commands_framework.Services +namespace TextCommandFramework.Services { public class PictureService { diff --git a/samples/02_commands_framework/02_commands_framework.csproj b/samples/TextCommandFramework/_TextCommandFramework.csproj similarity index 90% rename from samples/02_commands_framework/02_commands_framework.csproj rename to samples/TextCommandFramework/_TextCommandFramework.csproj index 30c25e846..ee64205f5 100644 --- a/samples/02_commands_framework/02_commands_framework.csproj +++ b/samples/TextCommandFramework/_TextCommandFramework.csproj @@ -3,6 +3,7 @@ Exe net5.0 + TextCommandFramework diff --git a/samples/04_webhook_client/Program.cs b/samples/WebhookClient/Program.cs similarity index 97% rename from samples/04_webhook_client/Program.cs rename to samples/WebhookClient/Program.cs index f3a50036c..7b2539302 100644 --- a/samples/04_webhook_client/Program.cs +++ b/samples/WebhookClient/Program.cs @@ -2,7 +2,7 @@ using Discord; using Discord.Webhook; using System.Threading.Tasks; -namespace _04_webhook_client +namespace WebHookClient { // 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 diff --git a/samples/04_webhook_client/04_webhook_client.csproj b/samples/WebhookClient/_WebhookClient.csproj similarity index 69% rename from samples/04_webhook_client/04_webhook_client.csproj rename to samples/WebhookClient/_WebhookClient.csproj index c8d0c9ad3..91131894d 100644 --- a/samples/04_webhook_client/04_webhook_client.csproj +++ b/samples/WebhookClient/_WebhookClient.csproj @@ -2,8 +2,8 @@ Exe - netcoreapp2.2 - _04_webhook_client + net5.0 + WebHookClient diff --git a/samples/_idn/Inspector.cs b/samples/_idn/Inspector.cs new file mode 100644 index 000000000..1544c8d07 --- /dev/null +++ b/samples/_idn/Inspector.cs @@ -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().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(); + } + } +} diff --git a/samples/_idn/Program.cs b/samples/_idn/Program.cs new file mode 100644 index 000000000..aab9924f9 --- /dev/null +++ b/samples/_idn/Program.cs @@ -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(); + 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 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; } + } + } +} diff --git a/samples/_idn/idn.csproj b/samples/_idn/idn.csproj new file mode 100644 index 000000000..fafb3df3f --- /dev/null +++ b/samples/_idn/idn.csproj @@ -0,0 +1,16 @@ + + + + Exe + net5.0 + + + + + + + + + + + diff --git a/samples/_idn/logview.ps1 b/samples/_idn/logview.ps1 new file mode 100644 index 000000000..0857475f5 --- /dev/null +++ b/samples/_idn/logview.ps1 @@ -0,0 +1 @@ +Get-Content .\bin\Debug\netcoreapp3.1\idn.log -Tail 3 -Wait \ No newline at end of file diff --git a/samples/idn/Program.cs b/samples/idn/Program.cs index abc315a2d..aab9924f9 100644 --- a/samples/idn/Program.cs +++ b/samples/idn/Program.cs @@ -1,17 +1,17 @@ +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.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.Diagnostics; +using System.Threading; +using System.Threading.Tasks; namespace Idn { diff --git a/src/Discord.Net.Examples/Core/Entities/Channels/IGuildChannel.Examples.cs b/src/Discord.Net.Examples/Core/Entities/Channels/IGuildChannel.Examples.cs index d382ddbf3..8205ad50f 100644 --- a/src/Discord.Net.Examples/Core/Entities/Channels/IGuildChannel.Examples.cs +++ b/src/Discord.Net.Examples/Core/Entities/Channels/IGuildChannel.Examples.cs @@ -1,6 +1,6 @@ +using JetBrains.Annotations; using System; using System.Threading.Tasks; -using JetBrains.Annotations; 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) { - 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 var previousOverwrite = channel.GetPermissionOverwrite(role); @@ -29,8 +31,10 @@ namespace Discord.Net.Examples.Core.Entities.Channels 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 var previousOverwrite = channel.GetPermissionOverwrite(user); diff --git a/src/Discord.Net.Examples/Core/Entities/Channels/IMessageChannel.Examples.cs b/src/Discord.Net.Examples/Core/Entities/Channels/IMessageChannel.Examples.cs index d920e9710..9b4aee53c 100644 --- a/src/Discord.Net.Examples/Core/Entities/Channels/IMessageChannel.Examples.cs +++ b/src/Discord.Net.Examples/Core/Entities/Channels/IMessageChannel.Examples.cs @@ -1,8 +1,8 @@ +using JetBrains.Annotations; using System; using System.Linq; using System.Net.Http; using System.Threading.Tasks; -using JetBrains.Annotations; namespace Discord.Net.Examples.Core.Entities.Channels { @@ -90,7 +90,7 @@ namespace Discord.Net.Examples.Core.Entities.Channels #region SendFileAsync.FilePath.EmbeddedImage await channel.SendFileAsync("b1nzy.jpg", - embed: new EmbedBuilder {ImageUrl = "attachment://b1nzy.jpg"}.Build()); + embed: new EmbedBuilder { ImageUrl = "attachment://b1nzy.jpg" }.Build()); #endregion @@ -99,13 +99,14 @@ namespace Discord.Net.Examples.Core.Entities.Channels using (var b1nzyStream = await httpClient.GetStreamAsync("https://example.com/b1nzy")) await channel.SendFileAsync(b1nzyStream, "b1nzy.jpg", - embed: new EmbedBuilder {ImageUrl = "attachment://b1nzy.jpg"}.Build()); + embed: new EmbedBuilder { ImageUrl = "attachment://b1nzy.jpg" }.Build()); #endregion #region EnterTypingState - using (channel.EnterTypingState()) await LongRunningAsync(); + using (channel.EnterTypingState()) + await LongRunningAsync(); #endregion } diff --git a/src/Discord.Net.Examples/Core/Entities/Users/IUser.Examples.cs b/src/Discord.Net.Examples/Core/Entities/Users/IUser.Examples.cs index 83daedaa0..5a6712901 100644 --- a/src/Discord.Net.Examples/Core/Entities/Users/IUser.Examples.cs +++ b/src/Discord.Net.Examples/Core/Entities/Users/IUser.Examples.cs @@ -1,7 +1,7 @@ +using JetBrains.Annotations; using System; using System.Net; using System.Threading.Tasks; -using JetBrains.Annotations; namespace Discord.Net.Examples.Core.Entities.Users { diff --git a/src/Discord.Net.Examples/WebSocket/BaseSocketClient.Events.Examples.cs b/src/Discord.Net.Examples/WebSocket/BaseSocketClient.Events.Examples.cs index 27d393c07..57c9dcd04 100644 --- a/src/Discord.Net.Examples/WebSocket/BaseSocketClient.Events.Examples.cs +++ b/src/Discord.Net.Examples/WebSocket/BaseSocketClient.Events.Examples.cs @@ -1,8 +1,8 @@ +using Discord.WebSocket; +using JetBrains.Annotations; using System; using System.Linq; using System.Threading.Tasks; -using Discord.WebSocket; -using JetBrains.Annotations; namespace Discord.Net.Examples.WebSocket { @@ -74,7 +74,7 @@ namespace Discord.Net.Examples.WebSocket #region MessageReceived - private readonly ulong[] _targetUserIds = {168693960628371456, 53905483156684800}; + private readonly ulong[] _targetUserIds = { 168693960628371456, 53905483156684800 }; public void HookMessageReceived(BaseSocketClient client) => client.MessageReceived += HandleMessageReceived; @@ -82,9 +82,11 @@ namespace Discord.Net.Examples.WebSocket public Task HandleMessageReceived(SocketMessage message) { // 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 - 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 var targetUsers = userMessage.MentionedUsers.Where(x => _targetUserIds.Contains(x.Id)); foreach (var targetUser in targetUsers) @@ -103,7 +105,8 @@ namespace Discord.Net.Examples.WebSocket public async Task HandleMessageDelete(Cacheable cachedMessage, Cacheable cachedChannel) { // 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 IMessageChannel channel = await cachedChannel.GetOrDownloadAsync(); var message = cachedMessage.Value;