Author | SHA1 | Message | Date |
---|---|---|---|
|
07f74b70b4 |
net: add barebones optional converter
does not support property omission at this time, will need to be added later using a separate converter and base marker class. -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512 "git failing to recognize gpg key, this identity is still valid" -----BEGIN PGP SIGNATURE----- iQIzBAEBCgAdFiEErbDRxgZ77MPT+ajAOrLKmA3cYakFAl4bthEACgkQOrLKmA3c YamuWw/7Bn/Ks0mTRN3tg3Z/voETJ/8JQZXJEiW7wwv8c7nSOemxRNB/Tmzo3kzC N6T5fH7Gep4o4iA7CfJ5CZtx+OY92OpyBwsJgkNvANVpjXWCeDaww0Ci5dyVwFUk fFq21l6p2sbM6PB9sEOCvryeIOrgkqBl915MkAlj+/UtnAQ9qFhomIGNLPPFeYOS eaHWjZF6ArbF5NMaOhboDDCIl2nCf+RGEetDoBP2BRaIf+eOyl0lGyQqiY1mNqkD DX8nmcaY5/Lnxhf3pwmYZbqKBPQt5R2FxmqWTg5ey0R4//izE4TJ54nlhdSnTZpH 7ZligmR9rQFdQ5jbSq6cIclo9i988ELHKBgt8mG3SiC4AT0+SBXRpPRBitkA0CPb O4W8J0HrbSFmILx9Zvuy72KC/Zzo+SOS8257S35ihosrlyupcR4zladVcIviAPWk Ovpy85W4uxPdWc6zkMOZSx9OiYFYkNlK/QdNJBXGg7LLcaLf8p33lj+T8UXa7dyC Sw/pW5RL1FYalh7iXF55ylJrKo+oySBejods+ATnmYG4JMywO+GNCE+XLCcDpoBx 9H2z0qJNb5Dgkc4cRulKwYEoT+LQKUhLFdj4wNEqE8mBw0ZoxUiBBqOD1TiZr2mf 1AFQVS/AeOc03t25OfmhNz026OAGy01bjeHr09deT20dsssEpQY= =n76m -----END PGP SIGNATURE----- |
5 years ago |
|
68f89bf2fc | rest: add webhook model (#1435) | 5 years ago |
|
5e6f977469
|
rest: write out channel model + its dependencies
Optional struct needs work still, + writing the converter for it is going to be a headache |
5 years ago |
|
18438e2dda
|
util: add logging | 5 years ago |
|
0df54c6afa
|
sample: add idn repl (Interactive Discord.Net)
basic enough to test some stuff with fixed some bugs with disposables in the process |
5 years ago |
|
c51bb4cda3
|
net: add token support to rest client | 5 years ago |
|
97ba033c1e
|
api: design rest and core | 5 years ago |
|
f7c212d3c0
|
net: design socket
incomplete, still needs receive handling gateway is yet to be designed |
5 years ago |
|
523da0be75
|
meta: add project structure | 5 years ago |
|
24bcf3b73f
|
meta: destroy repo | 5 years ago |
|
9e0d99106d | meta: wipe everything | 6 years ago |
@@ -206,4 +206,6 @@ docs/api/\.manifest | |||||
\.idea/ | \.idea/ | ||||
# Codealike UID | # Codealike UID | ||||
codealike.json | |||||
codealike.json | |||||
*.ignore |
@@ -1,23 +0,0 @@ | |||||
{ | |||||
"folders": [ | |||||
{ | |||||
"path": "." | |||||
} | |||||
], | |||||
"settings": { | |||||
"editor.rulers": [ | |||||
120 | |||||
], | |||||
"files.exclude": { | |||||
"**/.git": true, | |||||
"**/.svn": true, | |||||
"**/.hg": true, | |||||
"**/CVS": true, | |||||
"**/.DS_Store": true, | |||||
"docs/": true, | |||||
"**/obj": true, | |||||
"**/bin": true, | |||||
"samples/": true, | |||||
} | |||||
} | |||||
} |
@@ -1,36 +1,19 @@ | |||||
| |||||
Microsoft Visual Studio Solution File, Format Version 12.00 | Microsoft Visual Studio Solution File, Format Version 12.00 | ||||
# Visual Studio 15 | # Visual Studio 15 | ||||
VisualStudioVersion = 15.0.27004.2009 | |||||
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}" | |||||
VisualStudioVersion = 15.0.26124.0 | |||||
MinimumVisualStudioVersion = 15.0.26124.0 | |||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{5DAC796B-0B77-4F84-B790-83DB78C6DFFE}" | |||||
EndProject | EndProject | ||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Impls", "Impls", "{288C363D-A636-4EAE-9AC1-4698B641B26E}" | |||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net", "src\Discord.Net\Discord.Net.csproj", "{3194F5DC-C0AF-4459-AAA3-91CB8FB8C370}" | |||||
EndProject | EndProject | ||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Rest", "src\Discord.Net.Rest\Discord.Net.Rest.csproj", "{BFC6DC28-0351-4573-926A-D4124244C04F}" | |||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sample", "sample", "{4795640A-030C-4A9A-A9B0-20C56AF4DA3F}" | |||||
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("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "idn", "sample\idn\idn.csproj", "{5BE5DE89-53B7-4243-AEA8-FD8A6420908A}" | |||||
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("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{68EE1EAC-F487-4BAC-917B-233370B3AEA1}" | |||||
EndProject | EndProject | ||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Providers", "Providers", "{B0657AAE-DCC5-4FBF-8E5D-1FB578CF3012}" | |||||
EndProject | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Providers.WS4Net", "src\Discord.Net.Providers.WS4Net\Discord.Net.Providers.WS4Net.csproj", "{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}" | |||||
EndProject | |||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions", "Extensions", "{CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}" | |||||
EndProject | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Tests", "test\Discord.Net.Tests\Discord.Net.Tests.csproj", "{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}" | |||||
EndProject | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Webhook", "src\Discord.Net.Webhook\Discord.Net.Webhook.csproj", "{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}" | |||||
EndProject | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Analyzers", "src\Discord.Net.Analyzers\Discord.Net.Analyzers.csproj", "{BBA8E7FB-C834-40DC-822F-B112CB7F0140}" | |||||
EndProject | |||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{BB59D5B5-E7B0-4BF4-8F82-D14431B2799B}" | |||||
EndProject | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "01_basic_ping_bot", "samples\01_basic_ping_bot\01_basic_ping_bot.csproj", "{F2FF84FB-F6AD-47E5-9EE5-18206CAE136E}" | |||||
EndProject | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "02_commands_framework", "samples\02_commands_framework\02_commands_framework.csproj", "{4E1F1F40-B1DD-40C9-A4B1-A2046A4C9C76}" | |||||
EndProject | |||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "03_sharded_client", "samples\03_sharded_client\03_sharded_client.csproj", "{9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}" | |||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Tests.Unit", "test\Discord.Tests.Unit\Discord.Tests.Unit.csproj", "{6AD4FF67-D45E-4E7E-8853-990390D35C9F}" | |||||
EndProject | EndProject | ||||
Global | Global | ||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||
@@ -41,158 +24,50 @@ Global | |||||
Release|x64 = Release|x64 | Release|x64 = Release|x64 | ||||
Release|x86 = Release|x86 | Release|x86 = Release|x86 | ||||
EndGlobalSection | EndGlobalSection | ||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | |||||
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Debug|x86.ActiveCfg = Debug|Any CPU | |||||
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Debug|x86.Build.0 = Debug|Any CPU | |||||
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Release|x64.Build.0 = Release|Any CPU | |||||
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Release|x86.ActiveCfg = Release|Any CPU | |||||
{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Release|x86.Build.0 = Release|Any CPU | |||||
{BFC6DC28-0351-4573-926A-D4124244C04F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{BFC6DC28-0351-4573-926A-D4124244C04F}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{BFC6DC28-0351-4573-926A-D4124244C04F}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{BFC6DC28-0351-4573-926A-D4124244C04F}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{BFC6DC28-0351-4573-926A-D4124244C04F}.Debug|x86.ActiveCfg = Debug|Any CPU | |||||
{BFC6DC28-0351-4573-926A-D4124244C04F}.Debug|x86.Build.0 = Debug|Any CPU | |||||
{BFC6DC28-0351-4573-926A-D4124244C04F}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{BFC6DC28-0351-4573-926A-D4124244C04F}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{BFC6DC28-0351-4573-926A-D4124244C04F}.Release|x64.ActiveCfg = Debug|Any CPU | |||||
{BFC6DC28-0351-4573-926A-D4124244C04F}.Release|x64.Build.0 = Debug|Any CPU | |||||
{BFC6DC28-0351-4573-926A-D4124244C04F}.Release|x86.ActiveCfg = Debug|Any CPU | |||||
{BFC6DC28-0351-4573-926A-D4124244C04F}.Release|x86.Build.0 = Debug|Any CPU | |||||
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Debug|x86.ActiveCfg = Debug|Any CPU | |||||
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Debug|x86.Build.0 = Debug|Any CPU | |||||
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Release|x64.ActiveCfg = Debug|Any CPU | |||||
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Release|x64.Build.0 = Debug|Any CPU | |||||
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Release|x86.ActiveCfg = Debug|Any CPU | |||||
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Release|x86.Build.0 = Debug|Any CPU | |||||
{688FD1D8-7F01-4539-B2E9-F473C5D699C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{688FD1D8-7F01-4539-B2E9-F473C5D699C7}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{688FD1D8-7F01-4539-B2E9-F473C5D699C7}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{688FD1D8-7F01-4539-B2E9-F473C5D699C7}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{688FD1D8-7F01-4539-B2E9-F473C5D699C7}.Debug|x86.ActiveCfg = Debug|Any CPU | |||||
{688FD1D8-7F01-4539-B2E9-F473C5D699C7}.Debug|x86.Build.0 = Debug|Any CPU | |||||
{688FD1D8-7F01-4539-B2E9-F473C5D699C7}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{688FD1D8-7F01-4539-B2E9-F473C5D699C7}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{688FD1D8-7F01-4539-B2E9-F473C5D699C7}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{688FD1D8-7F01-4539-B2E9-F473C5D699C7}.Release|x64.Build.0 = Release|Any CPU | |||||
{688FD1D8-7F01-4539-B2E9-F473C5D699C7}.Release|x86.ActiveCfg = Release|Any CPU | |||||
{688FD1D8-7F01-4539-B2E9-F473C5D699C7}.Release|x86.Build.0 = Release|Any CPU | |||||
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Debug|x86.ActiveCfg = Debug|Any CPU | |||||
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Debug|x86.Build.0 = Debug|Any CPU | |||||
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Release|x64.Build.0 = Release|Any CPU | |||||
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Release|x86.ActiveCfg = Release|Any CPU | |||||
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Release|x86.Build.0 = Release|Any CPU | |||||
{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}.Debug|x86.ActiveCfg = Debug|Any CPU | |||||
{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}.Debug|x86.Build.0 = Debug|Any CPU | |||||
{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}.Release|x64.Build.0 = Release|Any CPU | |||||
{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}.Release|x86.ActiveCfg = Release|Any CPU | |||||
{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}.Release|x86.Build.0 = Release|Any CPU | |||||
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Debug|x86.ActiveCfg = Debug|Any CPU | |||||
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Debug|x86.Build.0 = Debug|Any CPU | |||||
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Release|x64.ActiveCfg = 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.Build.0 = Release|Any CPU | |||||
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Debug|x86.ActiveCfg = Debug|Any CPU | |||||
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Debug|x86.Build.0 = Debug|Any CPU | |||||
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Release|x64.Build.0 = Release|Any CPU | |||||
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Release|x86.ActiveCfg = Release|Any CPU | |||||
{BBA8E7FB-C834-40DC-822F-B112CB7F0140}.Release|x86.Build.0 = Release|Any CPU | |||||
{F2FF84FB-F6AD-47E5-9EE5-18206CAE136E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{F2FF84FB-F6AD-47E5-9EE5-18206CAE136E}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{F2FF84FB-F6AD-47E5-9EE5-18206CAE136E}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{F2FF84FB-F6AD-47E5-9EE5-18206CAE136E}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{F2FF84FB-F6AD-47E5-9EE5-18206CAE136E}.Debug|x86.ActiveCfg = Debug|Any CPU | |||||
{F2FF84FB-F6AD-47E5-9EE5-18206CAE136E}.Debug|x86.Build.0 = Debug|Any CPU | |||||
{F2FF84FB-F6AD-47E5-9EE5-18206CAE136E}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{F2FF84FB-F6AD-47E5-9EE5-18206CAE136E}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{F2FF84FB-F6AD-47E5-9EE5-18206CAE136E}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{F2FF84FB-F6AD-47E5-9EE5-18206CAE136E}.Release|x64.Build.0 = Release|Any CPU | |||||
{F2FF84FB-F6AD-47E5-9EE5-18206CAE136E}.Release|x86.ActiveCfg = Release|Any CPU | |||||
{F2FF84FB-F6AD-47E5-9EE5-18206CAE136E}.Release|x86.Build.0 = Release|Any CPU | |||||
{4E1F1F40-B1DD-40C9-A4B1-A2046A4C9C76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{4E1F1F40-B1DD-40C9-A4B1-A2046A4C9C76}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{4E1F1F40-B1DD-40C9-A4B1-A2046A4C9C76}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{4E1F1F40-B1DD-40C9-A4B1-A2046A4C9C76}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{4E1F1F40-B1DD-40C9-A4B1-A2046A4C9C76}.Debug|x86.ActiveCfg = Debug|Any CPU | |||||
{4E1F1F40-B1DD-40C9-A4B1-A2046A4C9C76}.Debug|x86.Build.0 = Debug|Any CPU | |||||
{4E1F1F40-B1DD-40C9-A4B1-A2046A4C9C76}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{4E1F1F40-B1DD-40C9-A4B1-A2046A4C9C76}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{4E1F1F40-B1DD-40C9-A4B1-A2046A4C9C76}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{4E1F1F40-B1DD-40C9-A4B1-A2046A4C9C76}.Release|x64.Build.0 = Release|Any CPU | |||||
{4E1F1F40-B1DD-40C9-A4B1-A2046A4C9C76}.Release|x86.ActiveCfg = Release|Any CPU | |||||
{4E1F1F40-B1DD-40C9-A4B1-A2046A4C9C76}.Release|x86.Build.0 = Release|Any CPU | |||||
{9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}.Debug|x86.ActiveCfg = Debug|Any CPU | |||||
{9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}.Debug|x86.Build.0 = Debug|Any CPU | |||||
{9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}.Release|x64.ActiveCfg = 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.Build.0 = Release|Any CPU | |||||
EndGlobalSection | |||||
GlobalSection(SolutionProperties) = preSolution | GlobalSection(SolutionProperties) = preSolution | ||||
HideSolutionNode = FALSE | HideSolutionNode = FALSE | ||||
EndGlobalSection | EndGlobalSection | ||||
GlobalSection(NestedProjects) = preSolution | |||||
{BFC6DC28-0351-4573-926A-D4124244C04F} = {288C363D-A636-4EAE-9AC1-4698B641B26E} | |||||
{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A} | |||||
{688FD1D8-7F01-4539-B2E9-F473C5D699C7} = {288C363D-A636-4EAE-9AC1-4698B641B26E} | |||||
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7} = {B0657AAE-DCC5-4FBF-8E5D-1FB578CF3012} | |||||
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A} | |||||
{BBA8E7FB-C834-40DC-822F-B112CB7F0140} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A} | |||||
{F2FF84FB-F6AD-47E5-9EE5-18206CAE136E} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B} | |||||
{4E1F1F40-B1DD-40C9-A4B1-A2046A4C9C76} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B} | |||||
{9B4C4AFB-3D15-44C6-9E36-12ED625AAA26} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B} | |||||
EndGlobalSection | |||||
GlobalSection(ExtensibilityGlobals) = postSolution | |||||
SolutionGuid = {D2404771-EEC8-45F2-9D71-F3373F6C1495} | |||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | |||||
{3194F5DC-C0AF-4459-AAA3-91CB8FB8C370}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{3194F5DC-C0AF-4459-AAA3-91CB8FB8C370}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{3194F5DC-C0AF-4459-AAA3-91CB8FB8C370}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{3194F5DC-C0AF-4459-AAA3-91CB8FB8C370}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{3194F5DC-C0AF-4459-AAA3-91CB8FB8C370}.Debug|x86.ActiveCfg = Debug|Any CPU | |||||
{3194F5DC-C0AF-4459-AAA3-91CB8FB8C370}.Debug|x86.Build.0 = Debug|Any CPU | |||||
{3194F5DC-C0AF-4459-AAA3-91CB8FB8C370}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{3194F5DC-C0AF-4459-AAA3-91CB8FB8C370}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{3194F5DC-C0AF-4459-AAA3-91CB8FB8C370}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{3194F5DC-C0AF-4459-AAA3-91CB8FB8C370}.Release|x64.Build.0 = Release|Any CPU | |||||
{3194F5DC-C0AF-4459-AAA3-91CB8FB8C370}.Release|x86.ActiveCfg = Release|Any CPU | |||||
{3194F5DC-C0AF-4459-AAA3-91CB8FB8C370}.Release|x86.Build.0 = Release|Any CPU | |||||
{5BE5DE89-53B7-4243-AEA8-FD8A6420908A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{5BE5DE89-53B7-4243-AEA8-FD8A6420908A}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{5BE5DE89-53B7-4243-AEA8-FD8A6420908A}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{5BE5DE89-53B7-4243-AEA8-FD8A6420908A}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{5BE5DE89-53B7-4243-AEA8-FD8A6420908A}.Debug|x86.ActiveCfg = Debug|Any CPU | |||||
{5BE5DE89-53B7-4243-AEA8-FD8A6420908A}.Debug|x86.Build.0 = Debug|Any CPU | |||||
{5BE5DE89-53B7-4243-AEA8-FD8A6420908A}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{5BE5DE89-53B7-4243-AEA8-FD8A6420908A}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{5BE5DE89-53B7-4243-AEA8-FD8A6420908A}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{5BE5DE89-53B7-4243-AEA8-FD8A6420908A}.Release|x64.Build.0 = Release|Any CPU | |||||
{5BE5DE89-53B7-4243-AEA8-FD8A6420908A}.Release|x86.ActiveCfg = Release|Any CPU | |||||
{5BE5DE89-53B7-4243-AEA8-FD8A6420908A}.Release|x86.Build.0 = Release|Any CPU | |||||
{6AD4FF67-D45E-4E7E-8853-990390D35C9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{6AD4FF67-D45E-4E7E-8853-990390D35C9F}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{6AD4FF67-D45E-4E7E-8853-990390D35C9F}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{6AD4FF67-D45E-4E7E-8853-990390D35C9F}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{6AD4FF67-D45E-4E7E-8853-990390D35C9F}.Debug|x86.ActiveCfg = Debug|Any CPU | |||||
{6AD4FF67-D45E-4E7E-8853-990390D35C9F}.Debug|x86.Build.0 = Debug|Any CPU | |||||
{6AD4FF67-D45E-4E7E-8853-990390D35C9F}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{6AD4FF67-D45E-4E7E-8853-990390D35C9F}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{6AD4FF67-D45E-4E7E-8853-990390D35C9F}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{6AD4FF67-D45E-4E7E-8853-990390D35C9F}.Release|x64.Build.0 = Release|Any CPU | |||||
{6AD4FF67-D45E-4E7E-8853-990390D35C9F}.Release|x86.ActiveCfg = Release|Any CPU | |||||
{6AD4FF67-D45E-4E7E-8853-990390D35C9F}.Release|x86.Build.0 = Release|Any CPU | |||||
EndGlobalSection | EndGlobalSection | ||||
GlobalSection(CodealikeProperties) = postSolution | |||||
SolutionGuid = a45217b4-a401-4dbf-8654-34d2ec034cd9 | |||||
GlobalSection(NestedProjects) = preSolution | |||||
{3194F5DC-C0AF-4459-AAA3-91CB8FB8C370} = {5DAC796B-0B77-4F84-B790-83DB78C6DFFE} | |||||
{5BE5DE89-53B7-4243-AEA8-FD8A6420908A} = {4795640A-030C-4A9A-A9B0-20C56AF4DA3F} | |||||
{6AD4FF67-D45E-4E7E-8853-990390D35C9F} = {68EE1EAC-F487-4BAC-917B-233370B3AEA1} | |||||
EndGlobalSection | EndGlobalSection | ||||
EndGlobal | EndGlobal |
@@ -1,16 +0,0 @@ | |||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> | |||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Cacheable/@EntryIndexedValue">True</s:Boolean> | |||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Downloader/@EntryIndexedValue">True</s:Boolean> | |||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Emoji/@EntryIndexedValue">True</s:Boolean> | |||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=libsodium/@EntryIndexedValue">True</s:Boolean> | |||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=NSFW/@EntryIndexedValue">True</s:Boolean> | |||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Ratelimit/@EntryIndexedValue">True</s:Boolean> | |||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=seeked/@EntryIndexedValue">True</s:Boolean> | |||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=sharded/@EntryIndexedValue">True</s:Boolean> | |||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Spotify/@EntryIndexedValue">True</s:Boolean> | |||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=unban/@EntryIndexedValue">True</s:Boolean> | |||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Uncache/@EntryIndexedValue">True</s:Boolean> | |||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=webhook/@EntryIndexedValue">True</s:Boolean> | |||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=webhooks/@EntryIndexedValue">True</s:Boolean> | |||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=webhook_0027s/@EntryIndexedValue">True</s:Boolean> | |||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=ZWSP/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary> |
@@ -1,26 +0,0 @@ | |||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
<PropertyGroup> | |||||
<VersionPrefix>2.0.2</VersionPrefix> | |||||
<VersionSuffix>dev</VersionSuffix> | |||||
<Authors>RogueException</Authors> | |||||
<PackageTags>discord;discordapp</PackageTags> | |||||
<PackageProjectUrl>https://github.com/RogueException/Discord.Net</PackageProjectUrl> | |||||
<PackageLicenseUrl>http://opensource.org/licenses/MIT</PackageLicenseUrl> | |||||
<PackageIconUrl>https://github.com/RogueException/Discord.Net/raw/dev/docs/marketing/logo/PackageLogo.png</PackageIconUrl> | |||||
<RepositoryType>git</RepositoryType> | |||||
<RepositoryUrl>git://github.com/RogueException/Discord.Net</RepositoryUrl> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(BuildNumber)' == '' "> | |||||
<VersionSuffix Condition=" '$(VersionSuffix)' != ''">$(VersionSuffix)-dev</VersionSuffix> | |||||
<VersionSuffix Condition=" '$(VersionSuffix)' == ''">dev</VersionSuffix> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(BuildNumber)' != '' And $(IsTagBuild) != 'true' "> | |||||
<VersionSuffix Condition=" '$(VersionSuffix)' != '' ">$(VersionSuffix)-$(BuildNumber)</VersionSuffix> | |||||
<VersionSuffix Condition=" '$(VersionSuffix)' == '' ">build-$(BuildNumber)</VersionSuffix> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' "> | |||||
<NoWarn>$(NoWarn);CS1573;CS1591</NoWarn> | |||||
<WarningsAsErrors>true</WarningsAsErrors> | |||||
<GenerateDocumentationFile>true</GenerateDocumentationFile> | |||||
</PropertyGroup> | |||||
</Project> |
@@ -1,6 +1,6 @@ | |||||
The MIT License (MIT) | The MIT License (MIT) | ||||
Copyright (c) 2015-2017 Discord.Net Contributors | |||||
Copyright (c) 2015-2020 Discord.Net Contributors | |||||
Permission is hereby granted, free of charge, to any person obtaining a copy | Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
of this software and associated documentation files (the "Software"), to deal | of this software and associated documentation files (the "Software"), to deal | ||||
@@ -1,40 +1,3 @@ | |||||
# Discord.Net | |||||
[](https://www.nuget.org/packages/Discord.Net) | |||||
[](https://www.myget.org/feed/Packages/discord-net) | |||||
[](https://ci.appveyor.com/project/RogueException/discord-net/branch/dev) | |||||
[](https://discord.gg/jkrBmQR) | |||||
# Discord.Net 2020 | |||||
An unofficial .NET API Wrapper for the Discord client (http://discordapp.com). | |||||
Check out the [documentation](https://discord.foxbot.me/docs/) or join the [Discord API Chat](https://discord.gg/jkrBmQR). | |||||
## Installation | |||||
### Stable (NuGet) | |||||
Our stable builds available from NuGet through the Discord.Net metapackage: | |||||
- [Discord.Net](https://www.nuget.org/packages/Discord.Net/) | |||||
The individual components may also be installed from NuGet: | |||||
- [Discord.Net.Commands](https://www.nuget.org/packages/Discord.Net.Commands/) | |||||
- [Discord.Net.Rest](https://www.nuget.org/packages/Discord.Net.Rest/) | |||||
- [Discord.Net.WebSocket](https://www.nuget.org/packages/Discord.Net.WebSocket/) | |||||
- [Discord.Net.Webhook](https://www.nuget.org/packages/Discord.Net.Webhook/) | |||||
### Unstable (MyGet) | |||||
Nightly builds are available through our MyGet feed (`https://www.myget.org/F/discord-net/api/v3/index.json`). | |||||
## Compiling | |||||
In order to compile Discord.Net, you require the following: | |||||
### Using Visual Studio | |||||
- [Visual Studio 2017](https://www.microsoft.com/net/core#windowsvs2017) | |||||
- [.NET Core SDK](https://www.microsoft.com/net/download/core) | |||||
The .NET Core workload must be selected during Visual Studio installation. | |||||
### Using Command Line | |||||
- [.NET Core SDK](https://www.microsoft.com/net/download/core) | |||||
## Known Issues | |||||
### WebSockets (Win7 and earlier) | |||||
.NET Core 1.1 does not support WebSockets on Win7 and earlier. This issue has been fixed since the release of .NET Core 2.1. It is recommended to target .NET Core 2.1 or above for your project if you wish to run your bot on legacy platforms; alternatively, you may choose to install the [Discord.Net.Providers.WS4Net](https://www.nuget.org/packages/Discord.Net.Providers.WS4Net/) package. | |||||
Rewrite branch, work in progress. |
@@ -0,0 +1,37 @@ | |||||
- REST | |||||
- Models | |||||
- Preconditions | |||||
- Endpoints | |||||
- Channel | |||||
- Emoji | |||||
- Guild | |||||
- Invite | |||||
- User | |||||
- Voice | |||||
- Webhook | |||||
- Ratelimiter with refit | |||||
- Gateway | |||||
- Models | |||||
- Client | |||||
- Socket | |||||
- use token | |||||
* Receive | |||||
* Compression | |||||
- Voice (long) | |||||
- Core | |||||
- CDN | |||||
- Datastore | |||||
- Entities | |||||
- Channel | |||||
- Emoji | |||||
- Guild | |||||
- User | |||||
- Utilities | |||||
- Token Validation (port from @ChrisJ) | |||||
- Tests | |||||
- Unit test Gateway stability / deadlockability? | |||||
- Port ChrisJ's token validator tests | |||||
- Extensions | |||||
- Commands | |||||
? design - use finite's or quahu's | |||||
- Interactivity |
@@ -1,94 +0,0 @@ | |||||
version: build-{build} | |||||
branches: | |||||
only: | |||||
- dev | |||||
image: | |||||
- Visual Studio 2017 | |||||
- Ubuntu | |||||
nuget: | |||||
disable_publish_on_pr: true | |||||
pull_requests: | |||||
do_not_increment_build_number: true | |||||
# Use the default clone_folder | |||||
# Windows: C:\Projects\discord-net | |||||
# Ubuntu: /home/appveyor/projects/discord-net | |||||
cache: test/Discord.Net.Tests/cache.db | |||||
environment: | |||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1 | |||||
DNET_TEST_TOKEN: | |||||
secure: l7h5e7UE7yRd70hAB97kjPiQpPOShwqoBbOzEAYQ+XBd/Pre5OA33IXa3uisdUeQJP/nPFhcOsI+yn7WpuFaoQ== | |||||
DNET_TEST_GUILDID: 273160668180381696 | |||||
init: | |||||
- ps: $Env:BUILD = "$($Env:APPVEYOR_BUILD_NUMBER.PadLeft(5, "0"))" | |||||
build_script: | |||||
- ps: >- | |||||
if ($isLinux) | |||||
{ | |||||
# AppVeyor Linux images do not have appveyor-retry, which retries the commands a few times | |||||
# until the command exits with code 0. | |||||
# So, this is done with a short script. | |||||
$code = 0 | |||||
$counter = 0 | |||||
do | |||||
{ | |||||
dotnet restore Discord.Net.sln -v Minimal /p:BuildNumber="$Env:BUILD" /p:IsTagBuild="$Env:APPVEYOR_REPO_TAG" | |||||
$code = $LASTEXITCODE | |||||
$counter++ | |||||
if ($code -ne 0) | |||||
{ | |||||
# Wait 5s before attempting to run again | |||||
Start-sleep -Seconds 5 | |||||
} | |||||
} | |||||
until ($counter -eq 5 -or $code -eq 0) | |||||
} | |||||
else | |||||
{ | |||||
appveyor-retry dotnet restore Discord.Net.sln -v Minimal /p:BuildNumber="$Env:BUILD" /p:IsTagBuild="$Env:APPVEYOR_REPO_TAG" | |||||
} | |||||
- ps: dotnet build Discord.Net.sln -c "Release" /p:BuildNumber="$Env:BUILD" /p:IsTagBuild="$Env:APPVEYOR_REPO_TAG" | |||||
after_build: | |||||
- ps: if ($isWindows) { dotnet pack "src\Discord.Net.Core\Discord.Net.Core.csproj" -c "Release" -o "../../artifacts" --no-build /p:BuildNumber="$Env:BUILD" /p:IsTagBuild="$Env:APPVEYOR_REPO_TAG" } | |||||
- ps: if ($isWindows) { dotnet pack "src\Discord.Net.Rest\Discord.Net.Rest.csproj" -c "Release" -o "../../artifacts" --no-build /p:BuildNumber="$Env:BUILD" /p:IsTagBuild="$Env:APPVEYOR_REPO_TAG" } | |||||
- ps: if ($isWindows) { dotnet pack "src\Discord.Net.WebSocket\Discord.Net.WebSocket.csproj" -c "Release" -o "../../artifacts" --no-build /p:BuildNumber="$Env:BUILD" /p:IsTagBuild="$Env:APPVEYOR_REPO_TAG" } | |||||
- ps: if ($isWindows) { dotnet pack "src\Discord.Net.Commands\Discord.Net.Commands.csproj" -c "Release" -o "../../artifacts" --no-build /p:BuildNumber="$Env:BUILD" /p:IsTagBuild="$Env:APPVEYOR_REPO_TAG" } | |||||
- ps: if ($isWindows) { dotnet pack "src\Discord.Net.Webhook\Discord.Net.Webhook.csproj" -c "Release" -o "../../artifacts" --no-build /p:BuildNumber="$Env:BUILD" /p:IsTagBuild="$Env:APPVEYOR_REPO_TAG" } | |||||
- ps: if ($isWindows) { dotnet pack "src\Discord.Net.Providers.WS4Net\Discord.Net.Providers.WS4Net.csproj" -c "Release" -o "../../artifacts" --no-build /p:BuildNumber="$Env:BUILD" /p:IsTagBuild="$Env:APPVEYOR_REPO_TAG" } | |||||
- ps: if ($isWindows) { dotnet pack "src\Discord.Net.Analyzers\Discord.Net.Analyzers.csproj" -c "Release" -o "../../artifacts" --no-build /p:BuildNumber="$Env:BUILD" /p:IsTagBuild="$Env:APPVEYOR_REPO_TAG" } | |||||
- ps: >- | |||||
if ($isWindows) | |||||
{ | |||||
if ($Env:APPVEYOR_REPO_TAG -eq "true") { | |||||
nuget pack src/Discord.Net/Discord.Net.nuspec -OutputDirectory "artifacts" -properties suffix="" | |||||
} else { | |||||
nuget pack src/Discord.Net/Discord.Net.nuspec -OutputDirectory "artifacts" -properties suffix="-$Env:BUILD" | |||||
} | |||||
} | |||||
- ps: if ($isWindows) { Get-ChildItem artifacts/*.nupkg | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } } | |||||
test_script: | |||||
- ps: >- | |||||
if ($APPVEYOR_PULL_REQUEST_NUMBER -eq "") { | |||||
dotnet test test/Discord.Net.Tests/Discord.Net.Tests.csproj -c "Release" --no-build /p:BuildNumber="$Env:BUILD" /p:IsTagBuild="$Env:APPVEYOR_REPO_TAG" | |||||
} | |||||
deploy: | |||||
- provider: NuGet | |||||
server: https://www.myget.org/F/discord-net/api/v2/package | |||||
api_key: | |||||
secure: Jl7BXeUjRnkVHDMBuUWSXcEOkrli1PBleW2IiLyUs5j63UNUNp1hcjaUJRujx9lz | |||||
symbol_server: https://www.myget.org/F/discord-net/symbols/api/v2/package | |||||
on: | |||||
branch: dev | |||||
CI_WINDOWS: true | |||||
- provider: NuGet | |||||
server: https://www.myget.org/F/rogueexception/api/v2/package | |||||
api_key: | |||||
secure: D+vW2O2LBf/iJb4f+q8fkyIW2VdIYIGxSYLWNrOD4BHlDBZQlJipDbNarWjUr2Kn | |||||
symbol_server: https://www.myget.org/F/rogueexception/symbols/api/v2/package | |||||
on: | |||||
branch: dev | |||||
CI_WINDOWS: true |
@@ -1,10 +0,0 @@ | |||||
############### | |||||
# folder # | |||||
############### | |||||
/**/DROP/ | |||||
/**/TEMP/ | |||||
/**/packages/ | |||||
/**/bin/ | |||||
/**/obj/ | |||||
_site |
@@ -1,35 +0,0 @@ | |||||
# Contributing to Docs | |||||
## General Guidelines | |||||
We do not have any strict conditions for writing documentation, | |||||
but keep these guidelines in mind: | |||||
* Keep code samples in the `guides/samples` folder | |||||
* When referencing an object in the API, link to its page in the | |||||
API documentation | |||||
* Documentation should be written in an FAQ/Wiki-style format | |||||
* Documentation should be written in clear and proper English* | |||||
\* If anyone is interested in translating documentation into other | |||||
languages, please open an issue or contact me on | |||||
Discord (`foxbot#0282`). | |||||
## Style Consistencies | |||||
* Use a ruler set at 70 characters | |||||
* Links should use long syntax | |||||
* Pages should be short and concise, not broad and long | |||||
Example of long link syntax: | |||||
```md | |||||
Please consult the [API Documentation] for more information. | |||||
[API Documentation]: xref:System.String | |||||
``` | |||||
## Recommended Reads | |||||
* http://docs.microsoft.com | |||||
* http://flask.pocoo.org/docs/0.12/ |
@@ -1,21 +0,0 @@ | |||||
{ | |||||
"folders": [ | |||||
{ | |||||
"path": "." | |||||
} | |||||
], | |||||
"settings": { | |||||
"editor.rulers": [ | |||||
70 | |||||
], | |||||
"files.exclude": { | |||||
"**/.git": true, | |||||
"**/.svn": true, | |||||
"**/.hg": true, | |||||
"**/CVS": true, | |||||
"**/.DS_Store": true, | |||||
"obj/": true, | |||||
"_site/": true, | |||||
} | |||||
} | |||||
} |
@@ -1,15 +0,0 @@ | |||||
# Instructions for Building Documentation | |||||
The documentation for the Discord.Net library uses [DocFX][docfx-main]. | |||||
Instructions for installing this tool can be found [here][docfx-installing]. | |||||
1. Navigate to the root of the repository. | |||||
2. Build the docs using `docfx docs/docfx.json`. Add the `--serve` | |||||
parameter to preview the site locally. Some elements of the page | |||||
may appear incorrectly when hosted offline. | |||||
Please note that if you intend to target a specific version, ensure | |||||
that you have the correct version checked out. | |||||
[docfx-main]: https://dotnet.github.io/docfx/ | |||||
[docfx-installing]: https://dotnet.github.io/docfx/tutorial/docfx_getting_started.html |
@@ -1,31 +0,0 @@ | |||||
--- | |||||
uid: Discord.Commands.CommandException | |||||
remarks: *content | |||||
--- | |||||
This @System.Exception class is typically used when diagnosing | |||||
an error thrown during the execution of a command. You will find the | |||||
thrown exception passed into | |||||
[LogMessage.Exception](xref:Discord.LogMessage.Exception), which is | |||||
sent to your [CommandService.Log](xref:Discord.Commands.CommandService.Log) | |||||
event handler. | |||||
--- | |||||
uid: Discord.Commands.CommandException | |||||
example: [*content] | |||||
--- | |||||
You may use this information to handle runtime exceptions after | |||||
execution. Below is an example of how you may use this: | |||||
```cs | |||||
public Task LogHandlerAsync(LogMessage logMessage) | |||||
{ | |||||
// Note that this casting method requires C#7 and up. | |||||
if (logMessage?.Exception is CommandException cmdEx) | |||||
{ | |||||
Console.WriteLine($"{cmdEx.GetBaseException().GetType()} was thrown while executing {cmdEx.Command.Aliases.First()} in {cmdEx.Context.Channel} by {cmdEx.Context.User}."); | |||||
} | |||||
return Task.CompletedTask; | |||||
} | |||||
``` |
@@ -1,22 +0,0 @@ | |||||
--- | |||||
uid: Discord.Commands.DontAutoLoadAttribute | |||||
remarks: *content | |||||
--- | |||||
The attribute can be applied to a public class that inherits | |||||
@Discord.Commands.ModuleBase. By applying this attribute, | |||||
@Discord.Commands.CommandService.AddModulesAsync* will not discover and | |||||
add the marked module to the CommandService. | |||||
--- | |||||
uid: Discord.Commands.DontAutoLoadAttribute | |||||
example: [*content] | |||||
--- | |||||
```cs | |||||
[DontAutoLoad] | |||||
public class MyModule : ModuleBase<SocketCommandContext> | |||||
{ | |||||
// ... | |||||
} | |||||
``` |
@@ -1,27 +0,0 @@ | |||||
--- | |||||
uid: Discord.Commands.DontInjectAttribute | |||||
remarks: *content | |||||
--- | |||||
The attribute can be applied to a public settable property inside a | |||||
@Discord.Commands.ModuleBase based class. By applying this attribute, | |||||
the marked property will not be automatically injected of the | |||||
dependency. See @Guides.Commands.DI to learn more. | |||||
--- | |||||
uid: Discord.Commands.DontInjectAttribute | |||||
example: [*content] | |||||
--- | |||||
```cs | |||||
public class MyModule : ModuleBase<SocketCommandContext> | |||||
{ | |||||
[DontInject] | |||||
public MyService MyService { get; set; } | |||||
public MyModule() | |||||
{ | |||||
MyService = new MyService(); | |||||
} | |||||
} | |||||
``` |
@@ -1,5 +0,0 @@ | |||||
An example of how this class is used the command system can be seen | |||||
below: | |||||
[!code[Sample module](../../guides/commands/samples/intro/empty-module.cs)] | |||||
[!code[Command handler](../../guides/commands/samples/intro/command_handler.cs)] |
@@ -1,27 +0,0 @@ | |||||
--- | |||||
uid: Discord.Commands.ICommandContext | |||||
example: [*content] | |||||
--- | |||||
[!include[Example Section](ICommandContext.Inclusion.md)] | |||||
--- | |||||
uid: Discord.Commands.CommandContext | |||||
example: [*content] | |||||
--- | |||||
[!include[Example Section](ICommandContext.Inclusion.md)] | |||||
--- | |||||
uid: Discord.Commands.SocketCommandContext | |||||
example: [*content] | |||||
--- | |||||
[!include[Example Section](ICommandContext.Inclusion.md)] | |||||
--- | |||||
uid: Discord.Commands.ShardCommandContext | |||||
example: [*content] | |||||
--- | |||||
[!include[Example Section](ICommandContext.Inclusion.md)] |
@@ -1,103 +0,0 @@ | |||||
--- | |||||
uid: Discord.Commands.PreconditionAttribute | |||||
remarks: *content | |||||
--- | |||||
This precondition attribute can be applied on module-level or | |||||
method-level for a command. | |||||
[!include[Additional Remarks](PreconditionAttribute.Remarks.Inclusion.md)] | |||||
--- | |||||
uid: Discord.Commands.ParameterPreconditionAttribute | |||||
remarks: *content | |||||
--- | |||||
This precondition attribute can be applied on parameter-level for a | |||||
command. | |||||
[!include[Additional Remarks](PreconditionAttribute.Remarks.Inclusion.md)] | |||||
--- | |||||
uid: Discord.Commands.PreconditionAttribute | |||||
example: [*content] | |||||
--- | |||||
The following example creates a precondition to see if the user has | |||||
sufficient role required to access the command. | |||||
```cs | |||||
public class RequireRoleAttribute : PreconditionAttribute | |||||
{ | |||||
private readonly ulong _roleId; | |||||
public RequireRoleAttribute(ulong roleId) | |||||
{ | |||||
_roleId = roleId; | |||||
} | |||||
public override async Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, | |||||
CommandInfo command, IServiceProvider services) | |||||
{ | |||||
var guildUser = context.User as IGuildUser; | |||||
if (guildUser == null) | |||||
return PreconditionResult.FromError("This command cannot be executed outside of a guild."); | |||||
var guild = guildUser.Guild; | |||||
if (guild.Roles.All(r => r.Id != _roleId)) | |||||
return PreconditionResult.FromError( | |||||
$"The guild does not have the role ({_roleId}) required to access this command."); | |||||
return guildUser.RoleIds.Any(rId => rId == _roleId) | |||||
? PreconditionResult.FromSuccess() | |||||
: PreconditionResult.FromError("You do not have the sufficient role required to access this command."); | |||||
} | |||||
} | |||||
``` | |||||
--- | |||||
uid: Discord.Commands.ParameterPreconditionAttribute | |||||
example: [*content] | |||||
--- | |||||
The following example creates a precondition on a parameter-level to | |||||
see if the targeted user has a lower hierarchy than the user who | |||||
executed the command. | |||||
```cs | |||||
public class RequireHierarchyAttribute : ParameterPreconditionAttribute | |||||
{ | |||||
public override async Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, | |||||
ParameterInfo parameter, object value, IServiceProvider services) | |||||
{ | |||||
// Hierarchy is only available under the socket variant of the user. | |||||
if (!(context.User is SocketGuildUser guildUser)) | |||||
return PreconditionResult.FromError("This command cannot be used outside of a guild."); | |||||
SocketGuildUser targetUser; | |||||
switch (value) | |||||
{ | |||||
case SocketGuildUser targetGuildUser: | |||||
targetUser = targetGuildUser; | |||||
break; | |||||
case ulong userId: | |||||
targetUser = await context.Guild.GetUserAsync(userId).ConfigureAwait(false) as SocketGuildUser; | |||||
break; | |||||
default: | |||||
throw new ArgumentOutOfRangeException(); | |||||
} | |||||
if (targetUser == null) | |||||
return PreconditionResult.FromError("Target user not found."); | |||||
if (guildUser.Hierarchy < targetUser.Hierarchy) | |||||
return PreconditionResult.FromError("You cannot target anyone else whose roles are higher than yours."); | |||||
var currentUser = await context.Guild.GetCurrentUserAsync().ConfigureAwait(false) as SocketGuildUser; | |||||
if (currentUser?.Hierarchy < targetUser.Hierarchy) | |||||
return PreconditionResult.FromError("The bot's role is lower than the targeted user."); | |||||
return PreconditionResult.FromSuccess(); | |||||
} | |||||
} | |||||
``` |
@@ -1,6 +0,0 @@ | |||||
A "precondidtion" in the command system is used to determine if a | |||||
condition is met before entering the command task. Using a | |||||
precondidtion may aid in keeping a well-organized command logic. | |||||
The most common use case being whether a user has sufficient | |||||
permission to execute the command. |
@@ -1,68 +0,0 @@ | |||||
--- | |||||
uid: Discord.EmbedBuilder | |||||
seealso: | |||||
- linkId: Discord.EmbedFooterBuilder | |||||
- linkId: Discord.EmbedAuthorBuilder | |||||
- linkId: Discord.EmbedFieldBuilder | |||||
remarks: *content | |||||
--- | |||||
This builder class is used to build an @Discord.Embed (rich embed) | |||||
object that will be ready to be sent via @Discord.IMessageChannel.SendMessageAsync* | |||||
after @Discord.EmbedBuilder.Build* is called. | |||||
--- | |||||
uid: Discord.EmbedBuilder | |||||
example: [*content] | |||||
--- | |||||
#### Basic Usage | |||||
The example below builds an embed and sends it to the chat using the | |||||
command system. | |||||
```cs | |||||
[Command("embed")] | |||||
public async Task SendRichEmbedAsync() | |||||
{ | |||||
var embed = new EmbedBuilder | |||||
{ | |||||
// Embed property can be set within object initializer | |||||
Title = "Hello world!" | |||||
Description = "I am a description set by initializer." | |||||
}; | |||||
// Or with methods | |||||
embed.AddField("Field title", | |||||
"Field value. I also support [hyperlink markdown](https://example.com)!") | |||||
.WithAuthor(Context.Client.CurrentUser) | |||||
.WithFooter(footer => footer.Text = "I am a footer.") | |||||
.WithColor(Color.Blue) | |||||
.WithTitle("I overwrote \"Hello world!\"") | |||||
.WithDescription("I am a description.") | |||||
.WithUrl("https://example.com") | |||||
.WithCurrentTimestamp() | |||||
.Build(); | |||||
await ReplyAsync(embed: embed); | |||||
} | |||||
``` | |||||
 | |||||
#### Usage with Local Images | |||||
The example below sends an image and has the image embedded in the rich | |||||
embed. See @Discord.IMessageChannel.SendFileAsync* for more information | |||||
about uploading a file or image. | |||||
```cs | |||||
[Command("embedimage")] | |||||
public async Task SendEmbedWithImageAsync() | |||||
{ | |||||
var fileName = "image.png"; | |||||
var embed = new EmbedBuilder() | |||||
{ | |||||
ImageUrl = $"attachment://{fileName}" | |||||
}.Build(); | |||||
await Context.Channel.SendFileAsync(fileName, embed: embed); | |||||
} | |||||
``` |
@@ -1,25 +0,0 @@ | |||||
The example will build a rich embed with an author field, a footer | |||||
field, and 2 normal fields using an @Discord.EmbedBuilder: | |||||
```cs | |||||
var exampleAuthor = new EmbedAuthorBuilder() | |||||
.WithName("I am a bot") | |||||
.WithIconUrl("https://discordapp.com/assets/e05ead6e6ebc08df9291738d0aa6986d.png"); | |||||
var exampleFooter = new EmbedFooterBuilder() | |||||
.WithText("I am a nice footer") | |||||
.WithIconUrl("https://discordapp.com/assets/28174a34e77bb5e5310ced9f95cb480b.png"); | |||||
var exampleField = new EmbedFieldBuilder() | |||||
.WithName("Title of Another Field") | |||||
.WithValue("I am an [example](https://example.com).") | |||||
.WithInline(true); | |||||
var otherField = new EmbedFieldBuilder() | |||||
.WithName("Title of a Field") | |||||
.WithValue("Notice how I'm inline with that other field next to me.") | |||||
.WithInline(true); | |||||
var embed = new EmbedBuilder() | |||||
.AddField(exampleField) | |||||
.AddField(otherField) | |||||
.WithAuthor(exampleAuthor) | |||||
.WithFooter(exampleFooter) | |||||
.Build(); | |||||
``` |
@@ -1,20 +0,0 @@ | |||||
--- | |||||
uid: Discord.EmbedAuthorBuilder | |||||
example: [*content] | |||||
--- | |||||
[!include[Embed Object Builder Sample](EmbedObjectBuilder.Inclusion.md)] | |||||
--- | |||||
uid: Discord.EmbedFooterBuilder | |||||
example: [*content] | |||||
--- | |||||
[!include[Embed Object Builder Sample](EmbedObjectBuilder.Inclusion.md)] | |||||
--- | |||||
uid: Discord.EmbedFieldBuilder | |||||
example: [*content] | |||||
--- | |||||
[!include[Embed Object Builder Sample](EmbedObjectBuilder.Inclusion.md)] |
@@ -1,26 +0,0 @@ | |||||
The sample below sends a message and adds an @Discord.Emoji and a custom | |||||
@Discord.Emote to the message. | |||||
```cs | |||||
public async Task SendAndReactAsync(ISocketMessageChannel channel) | |||||
{ | |||||
var message = await channel.SendMessageAsync("I am a message."); | |||||
// Creates a Unicode-based emoji based on the Unicode string. | |||||
// This is effectively the same as new Emoji("💕"). | |||||
var heartEmoji = new Emoji("\U0001f495"); | |||||
// Reacts to the message with the Emoji. | |||||
await message.AddReactionAsync(heartEmoji); | |||||
// Parses a custom emote based on the provided Discord emote format. | |||||
// Please note that this does not guarantee the existence of | |||||
// the emote. | |||||
var emote = Emote.Parse("<:thonkang:282745590985523200>"); | |||||
// Reacts to the message with the Emote. | |||||
await message.AddReactionAsync(emote); | |||||
} | |||||
``` | |||||
#### Result | |||||
 |
@@ -1,81 +0,0 @@ | |||||
--- | |||||
uid: Discord.IEmote | |||||
seealso: | |||||
- linkId: Discord.Emote | |||||
- linkId: Discord.Emoji | |||||
- linkId: Discord.GuildEmote | |||||
- linkId: Discord.IUserMessage | |||||
remarks: *content | |||||
--- | |||||
This interface is often used with reactions. It can represent an | |||||
unicode-based @Discord.Emoji, or a custom @Discord.Emote. | |||||
--- | |||||
uid: Discord.Emote | |||||
seealso: | |||||
- linkId: Discord.IEmote | |||||
- linkId: Discord.GuildEmote | |||||
- linkId: Discord.Emoji | |||||
- linkId: Discord.IUserMessage | |||||
remarks: *content | |||||
--- | |||||
> [!NOTE] | |||||
> A valid @Discord.Emote format is `<:emoteName:emoteId>`. This can be | |||||
> obtained by escaping with a `\` in front of the emote using the | |||||
> Discord chat client. | |||||
This class represents a custom emoji. This type of emoji can be | |||||
created via the @Discord.Emote.Parse* or @Discord.Emote.TryParse* | |||||
method. | |||||
--- | |||||
uid: Discord.Emoji | |||||
seealso: | |||||
- linkId: Discord.Emote | |||||
- linkId: Discord.GuildEmote | |||||
- linkId: Discord.Emoji | |||||
- linkId: Discord.IUserMessage | |||||
remarks: *content | |||||
--- | |||||
> [!NOTE] | |||||
> A valid @Discord.Emoji format is Unicode-based. This means only | |||||
> something like `🙃` or `\U0001f643` would work, instead of | |||||
> `:upside_down:`. | |||||
> | |||||
> A Unicode-based emoji can be obtained by escaping with a `\` in | |||||
> front of the emote using the Discord chat client or by looking up on | |||||
> [Emojipedia](https://emojipedia.org). | |||||
This class represents a standard Unicode-based emoji. This type of emoji | |||||
can be created by passing the Unicode into the constructor. | |||||
--- | |||||
uid: Discord.IEmote | |||||
example: [*content] | |||||
--- | |||||
[!include[Example Section](IEmote.Inclusion.md)] | |||||
--- | |||||
uid: Discord.Emoji | |||||
example: [*content] | |||||
--- | |||||
[!include[Example Section](IEmote.Inclusion.md)] | |||||
--- | |||||
uid: Discord.Emote | |||||
example: [*content] | |||||
--- | |||||
[!include[Example Section](IEmote.Inclusion.md)] | |||||
--- | |||||
uid: Discord.GuildEmote | |||||
example: [*content] | |||||
--- | |||||
[!include[Example Section](IEmote.Inclusion.md)] |
@@ -1,174 +0,0 @@ | |||||
--- | |||||
uid: Discord.GuildChannelProperties | |||||
example: [*content] | |||||
--- | |||||
The following example uses @Discord.IGuildChannel.ModifyAsync* to | |||||
apply changes specified in the properties, | |||||
```cs | |||||
var channel = _client.GetChannel(id) as IGuildChannel; | |||||
if (channel == null) return; | |||||
await channel.ModifyAsync(x => | |||||
{ | |||||
x.Name = "new-name"; | |||||
x.Position = channel.Position - 1; | |||||
}); | |||||
``` | |||||
--- | |||||
uid: Discord.TextChannelProperties | |||||
example: [*content] | |||||
--- | |||||
The following example uses @Discord.ITextChannel.ModifyAsync* to | |||||
apply changes specified in the properties, | |||||
```cs | |||||
var channel = _client.GetChannel(id) as ITextChannel; | |||||
if (channel == null) return; | |||||
await channel.ModifyAsync(x => | |||||
{ | |||||
x.Name = "cool-guys-only"; | |||||
x.Topic = "This channel is only for cool guys and adults!!!"; | |||||
x.Position = channel.Position - 1; | |||||
x.IsNsfw = true; | |||||
}); | |||||
``` | |||||
--- | |||||
uid: Discord.VoiceChannelProperties | |||||
example: [*content] | |||||
--- | |||||
The following example uses @Discord.IVoiceChannel.ModifyAsync* to | |||||
apply changes specified in the properties, | |||||
```cs | |||||
var channel = _client.GetChannel(id) as IVoiceChannel; | |||||
if (channel == null) return; | |||||
await channel.ModifyAsync(x => | |||||
{ | |||||
x.UserLimit = 5; | |||||
}); | |||||
``` | |||||
--- | |||||
uid: Discord.EmoteProperties | |||||
example: [*content] | |||||
--- | |||||
The following example uses @Discord.IGuild.ModifyEmoteAsync* to | |||||
apply changes specified in the properties, | |||||
```cs | |||||
await guild.ModifyEmoteAsync(x => | |||||
{ | |||||
x.Name = "blobo"; | |||||
}); | |||||
``` | |||||
--- | |||||
uid: Discord.MessageProperties | |||||
example: [*content] | |||||
--- | |||||
The following example uses @Discord.IUserMessage.ModifyAsync* to | |||||
apply changes specified in the properties, | |||||
```cs | |||||
var message = await channel.SendMessageAsync("boo"); | |||||
await Task.Delay(TimeSpan.FromSeconds(1)); | |||||
await message.ModifyAsync(x => x.Content = "boi"); | |||||
``` | |||||
--- | |||||
uid: Discord.GuildProperties | |||||
example: [*content] | |||||
--- | |||||
The following example uses @Discord.IGuild.ModifyAsync* to | |||||
apply changes specified in the properties, | |||||
```cs | |||||
var guild = _client.GetGuild(id); | |||||
if (guild == null) return; | |||||
await guild.ModifyAsync(x => | |||||
{ | |||||
x.Name = "VERY Fast Discord Running at Incredible Hihg Speed"; | |||||
}); | |||||
``` | |||||
--- | |||||
uid: Discord.RoleProperties | |||||
example: [*content] | |||||
--- | |||||
The following example uses @Discord.IRole.ModifyAsync* to | |||||
apply changes specified in the properties, | |||||
```cs | |||||
var role = guild.GetRole(id); | |||||
if (role == null) return; | |||||
await role.ModifyAsync(x => | |||||
{ | |||||
x.Name = "cool boi"; | |||||
x.Color = Color.Gold; | |||||
x.Hoist = true; | |||||
x.Mentionable = true; | |||||
}); | |||||
``` | |||||
--- | |||||
uid: Discord.GuildUserProperties | |||||
example: [*content] | |||||
--- | |||||
The following example uses @Discord.IGuildUser.ModifyAsync* to | |||||
apply changes specified in the properties, | |||||
```cs | |||||
var user = guild.GetUser(id); | |||||
if (user == null) return; | |||||
await user.ModifyAsync(x => | |||||
{ | |||||
x.Nickname = "I need healing"; | |||||
}); | |||||
``` | |||||
--- | |||||
uid: Discord.SelfUserProperties | |||||
example: [*content] | |||||
--- | |||||
The following example uses @Discord.ISelfUser.ModifyAsync* to | |||||
apply changes specified in the properties, | |||||
```cs | |||||
await selfUser.ModifyAsync(x => | |||||
{ | |||||
x.Username = "Mercy"; | |||||
}); | |||||
``` | |||||
--- | |||||
uid: Discord.WebhookProperties | |||||
example: [*content] | |||||
--- | |||||
The following example uses @Discord.IWebhook.ModifyAsync* to | |||||
apply changes specified in the properties, | |||||
```cs | |||||
await webhook.ModifyAsync(x => | |||||
{ | |||||
x.Name = "very fast fox"; | |||||
x.ChannelId = newChannelId; | |||||
}); | |||||
``` |
@@ -1,24 +0,0 @@ | |||||
--- | |||||
uid: Discord.Commands.OverrideTypeReaderAttribute | |||||
remarks: *content | |||||
--- | |||||
This attribute is used to override a command parameter's type reading | |||||
behaviour. This may be useful when you have multiple custom | |||||
@Discord.Commands.TypeReader and would like to specify one. | |||||
--- | |||||
uid: Discord.Commands.OverrideTypeReaderAttribute | |||||
examples: [*content] | |||||
--- | |||||
The following example will override the @Discord.Commands.TypeReader | |||||
of @Discord.IUser to `MyUserTypeReader`. | |||||
```cs | |||||
public async Task PrintUserAsync( | |||||
[OverrideTypeReader(typeof(MyUserTypeReader))] IUser user) | |||||
{ | |||||
//... | |||||
} | |||||
``` |
@@ -1,21 +0,0 @@ | |||||
MIT License | |||||
Copyright (c) 2018 Still Hsu | |||||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
of this software and associated documentation files (the "Software"), to deal | |||||
in the Software without restriction, including without limitation the rights | |||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
copies of the Software, and to permit persons to whom the Software is | |||||
furnished to do so, subject to the following conditions: | |||||
The above copyright notice and this permission notice shall be included in all | |||||
copies or substantial portions of the Software. | |||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
SOFTWARE. |
@@ -1,29 +0,0 @@ | |||||
MIT License | |||||
Copyright (c) 2018 Still Hsu | |||||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
of this software and associated documentation files (the "Software"), to deal | |||||
in the Software without restriction, including without limitation the rights | |||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
copies of the Software, and to permit persons to whom the Software is | |||||
furnished to do so, subject to the following conditions: | |||||
The above copyright notice and this permission notice shall be included in all | |||||
copies or substantial portions of the Software. | |||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
SOFTWARE. | |||||
============================================================================== | |||||
Humanizer (https://github.com/Humanizr/Humanizer) | |||||
The MIT License (MIT) | |||||
Copyright (c) .NET Foundation and Contributors | |||||
============================================================================== |
@@ -1,4 +0,0 @@ | |||||
<configuration> | |||||
<dllmap os="linux" cpu="x86-64" wordsize="64" dll="git2-8e0b172" target="lib/linux-x64/libgit2-8e0b172.so" /> | |||||
<dllmap os="osx" cpu="x86,x86-64" dll="git2-8e0b172" target="lib/osx/libgit2-8e0b172.dylib" /> | |||||
</configuration> |
@@ -1,33 +0,0 @@ | |||||
{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}} | |||||
<div class="hidden-sm col-md-2" role="complementary"> | |||||
<div class="sideaffix"> | |||||
<div class="theme-switch-field"> | |||||
<p>Theme</p> | |||||
<select id="theme-switcher"> | |||||
<option value="dark">Dark</option> | |||||
<option value="gray">Gray</option> | |||||
<option value="light">Light</option> | |||||
</select> | |||||
</div> | |||||
{{^_disableContribution}} | |||||
<div class="contribution"> | |||||
<ul class="nav"> | |||||
{{#docurl}} | |||||
<li> | |||||
<a href="{{docurl}}" class="contribution-link">{{__global.improveThisDoc}}</a> | |||||
</li> | |||||
{{/docurl}} | |||||
{{#sourceurl}} | |||||
<li> | |||||
<a href="{{sourceurl}}" class="contribution-link">{{__global.viewSource}}</a> | |||||
</li> | |||||
{{/sourceurl}} | |||||
</ul> | |||||
</div> | |||||
{{/_disableContribution}} | |||||
<nav class="bs-docs-sidebar hidden-print hidden-xs hidden-sm affix" id="affix"> | |||||
<!-- <p><a class="back-to-top" href="#top">Back to top</a><p> --> | |||||
</nav> | |||||
</div> | |||||
</div> |
@@ -1,27 +0,0 @@ | |||||
{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}} | |||||
<head> | |||||
<meta charset="utf-8"> | |||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> | |||||
<title>{{#title}}{{title}}{{/title}}{{^title}}{{>partials/title}}{{/title}} {{#_appTitle}}| {{_appTitle}} {{/_appTitle}}</title> | |||||
<meta name="viewport" content="width=device-width"> | |||||
<meta name="title" content="{{#title}}{{title}}{{/title}}{{^title}}{{>partials/title}}{{/title}} {{#_appTitle}}| {{_appTitle}} {{/_appTitle}}"> | |||||
<meta name="generator" content="docfx {{_docfxVersion}}"> | |||||
{{#_description}}<meta name="description" content="{{_description}}">{{/_description}} | |||||
<link rel="preload" href="{{_rel}}styles/search-worker.js" as="script"> | |||||
<link rel="preload" href="{{_rel}}fonts/glyphicons-halflings-regular.woff2" as="font" type="font/woff2" crossorigin="anonymous"> | |||||
<link rel="shortcut icon" href="{{_rel}}{{{_appFaviconPath}}}{{^_appFaviconPath}}favicon.ico{{/_appFaviconPath}}"> | |||||
<link rel="stylesheet" href="{{_rel}}styles/docfx.vendor.minify.css"> | |||||
<link rel="stylesheet" href="{{_rel}}styles/docfx.css"> | |||||
<link rel="stylesheet" href="{{_rel}}styles/master.css"> | |||||
<link rel="stylesheet" href="{{_rel}}styles/main.css"> | |||||
<link rel="stylesheet" href="{{_rel}}styles/theme-switcher.css"> | |||||
<link href="https://cdn.rawgit.com/noelboss/featherlight/1.7.6/release/featherlight.min.css" type="text/css" rel="stylesheet" /> | |||||
<meta name="theme-color" content="#99AAB5"/> | |||||
<meta property="docfx:navrel" content="{{_navRel}}"> | |||||
<meta property="docfx:tocrel" content="{{_tocRel}}"> | |||||
<meta id="docfx-style:rel" content="{{_rel}}"> | |||||
{{#_noindex}}<meta name="searchOption" content="noindex">{{/_noindex}} | |||||
{{#_enableSearch}}<meta property="docfx:rel" content="{{_rel}}">{{/_enableSearch}} | |||||
{{#_enableNewTab}}<meta property="docfx:newtab" content="true">{{/_enableNewTab}} | |||||
</head> |
@@ -1,10 +0,0 @@ | |||||
{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}} | |||||
<script type="text/javascript" src="{{_rel}}styles/docfx.vendor.js"></script> | |||||
<script type="text/javascript" src="{{_rel}}styles/docfx.js"></script> | |||||
<script type="text/javascript" src="{{_rel}}styles/main.js"></script> | |||||
<script type="text/javascript" src="https://cdn.rawgit.com/noelboss/featherlight/master/release/featherlight.min.js" charset="utf-8"></script> | |||||
<script type="text/javascript" src="{{_rel}}styles/plugin-featherlight.js"></script> | |||||
<script type="text/javascript" src="{{_rel}}styles/styleswitcher.js"></script> | |||||
<script type="text/javascript" src="https://malsup.github.io/jquery.corner.js"></script> | |||||
<script type="text/javascript" src="{{_rel}}styles/cornerify.js"></script> |
@@ -1,3 +0,0 @@ | |||||
window.onload = function (e) { | |||||
$('img').corner(); | |||||
} |
@@ -1,308 +0,0 @@ | |||||
/* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. */ | |||||
@import url('vs2015.css'); | |||||
html, | |||||
body { | |||||
background: #212121; | |||||
color: #C0C0C0; | |||||
} | |||||
button, | |||||
a { | |||||
color: #64B5F6; | |||||
} | |||||
.sidenav{ | |||||
background-color: rgb(30, 30, 30); | |||||
} | |||||
button:hover, | |||||
button:focus, | |||||
a:hover, | |||||
a:focus, | |||||
.btn:focus, | |||||
.btn:hover{ | |||||
color: #2196F3; | |||||
} | |||||
a.disable, | |||||
a.disable:hover { | |||||
color: #EEEEEE; | |||||
} | |||||
.divider { | |||||
color: #37474F; | |||||
} | |||||
hr { | |||||
border-color: #37474F; | |||||
} | |||||
.subnav { | |||||
background: #383838 | |||||
} | |||||
.inheritance h5, | |||||
.inheritedMembers h5 { | |||||
border-bottom: 1px solid #37474F; | |||||
} | |||||
article h4 { | |||||
border-bottom: 1px solid #37474F; | |||||
} | |||||
.docs-search { | |||||
background: #424242; | |||||
} | |||||
.search-results-group-heading { | |||||
color: #424242; | |||||
} | |||||
.search-close { | |||||
color: #424242; | |||||
} | |||||
.sidetoc { | |||||
background-color: #1b1b1b; | |||||
border-left: 0px solid #37474F; | |||||
border-right: 0px solid #37474F; | |||||
} | |||||
.sideaffix { | |||||
overflow: visible; | |||||
} | |||||
.sideaffix>div.contribution>ul>li>a.contribution-link:hover { | |||||
background-color: #333333; | |||||
} | |||||
/* toc */ | |||||
.toc .nav>li>a { | |||||
color: rgb(218, 218, 218); | |||||
} | |||||
.toc .nav>li>a:hover, | |||||
.toc .nav>li>a:focus { | |||||
color: #E0E0E0; | |||||
} | |||||
.toc .nav>li.active>a { | |||||
color: #90CAF9; | |||||
} | |||||
.toc .nav>li.active>a:hover, | |||||
.toc .nav>li.active>a:focus { | |||||
background-color: #37474F; | |||||
color: #4FC3F7; | |||||
} | |||||
.sidefilter { | |||||
background-color: #1b1b1b; | |||||
border-left: 0px solid #37474F; | |||||
border-right: 0px solid #37474F; | |||||
} | |||||
.affix ul>li>a:hover { | |||||
background: none; | |||||
color: #EEEEEE; | |||||
} | |||||
.affix ul>li.active>a, | |||||
.affix ul>li.active>a:before { | |||||
color: #B3E5FC; | |||||
} | |||||
.affix ul>li>a { | |||||
color: #EEEEEE; | |||||
} | |||||
.affix>ul>li.active>a, | |||||
.affix>ul>li.active>a:before { | |||||
color: #B3E5FC; | |||||
} | |||||
.tryspan { | |||||
border-color: #37474F; | |||||
} | |||||
.footer { | |||||
border-top: 1px solid #5F5F5F; | |||||
background: #616161; | |||||
} | |||||
/* alert */ | |||||
.alert-info { | |||||
color: #d9edf7; | |||||
background: #004458; | |||||
border-color: #005873; | |||||
} | |||||
.alert-warning { | |||||
color: #fffaf2; | |||||
background: #80551a; | |||||
border-color: #99661f; | |||||
} | |||||
.alert-danger { | |||||
color: #fff2f2; | |||||
background: #4d0000; | |||||
border-color: #660000; | |||||
} | |||||
/* For tabbed content */ | |||||
.tabGroup { | |||||
margin-top: 1rem; | |||||
} | |||||
.tabGroup ul[role="tablist"] { | |||||
margin: 0; | |||||
padding: 0; | |||||
list-style: none; | |||||
} | |||||
.tabGroup ul[role="tablist"]>li { | |||||
list-style: none; | |||||
display: inline-block; | |||||
} | |||||
.tabGroup a[role="tab"] { | |||||
color: white; | |||||
box-sizing: border-box; | |||||
display: inline-block; | |||||
padding: 5px 7.5px; | |||||
text-decoration: none; | |||||
border-bottom: 2px solid #fff; | |||||
} | |||||
.tabGroup a[role="tab"]:hover, | |||||
.tabGroup a[role="tab"]:focus, | |||||
.tabGroup a[role="tab"][aria-selected="true"] { | |||||
border-bottom: 2px solid #607D8B; | |||||
} | |||||
.tabGroup a[role="tab"][aria-selected="true"] { | |||||
color: #81D4FA; | |||||
} | |||||
.tabGroup a[role="tab"]:hover, | |||||
.tabGroup a[role="tab"]:focus { | |||||
color: #29B6F6; | |||||
} | |||||
.tabGroup a[role="tab"]:focus { | |||||
outline: 1px solid #607D8B; | |||||
outline-offset: -1px; | |||||
} | |||||
@media (min-width: 768px) { | |||||
.tabGroup a[role="tab"] { | |||||
padding: 5px 15px; | |||||
} | |||||
} | |||||
.tabGroup section[role="tabpanel"] { | |||||
border: 1px solid #607D8B; | |||||
padding: 15px; | |||||
margin: 0; | |||||
overflow: hidden; | |||||
} | |||||
.tabGroup section[role="tabpanel"]>.codeHeader, | |||||
.tabGroup section[role="tabpanel"]>pre { | |||||
margin-left: -16px; | |||||
margin-right: -16px; | |||||
} | |||||
.tabGroup section[role="tabpanel"]> :first-child { | |||||
margin-top: 0; | |||||
} | |||||
.tabGroup section[role="tabpanel"]>pre:last-child { | |||||
display: block; | |||||
margin-bottom: -16px; | |||||
} | |||||
.mainContainer[dir='rtl'] main ul[role="tablist"] { | |||||
margin: 0; | |||||
} | |||||
/* code */ | |||||
code { | |||||
color: white; | |||||
background-color: #4a4c52; | |||||
border-radius: 4px; | |||||
padding: 3px 7px; | |||||
} | |||||
pre { | |||||
background-color: #282a36; | |||||
} | |||||
/* table */ | |||||
.table-striped>tbody>tr:nth-of-type(odd) { | |||||
background-color: #333333; | |||||
color: #d3d3d3 | |||||
} | |||||
tbody>tr { | |||||
background-color: #424242; | |||||
color: #c0c0c0 | |||||
} | |||||
.table>tbody+tbody { | |||||
border-top: 2px solid rgb(173, 173, 173) | |||||
} | |||||
/* select */ | |||||
select { | |||||
background-color: #3b3b3b; | |||||
border-color: #2e2e2e; | |||||
} | |||||
/* | |||||
Following code regarding collapse container are fetched | |||||
or modified from the Materialize project. | |||||
The MIT License (MIT) | |||||
Copyright (c) 2014-2018 Materialize | |||||
https://github.com/Dogfalo/materialize | |||||
*/ | |||||
/* all collapse container */ | |||||
.collapse-container.last-modified { | |||||
-webkit-box-shadow: 0 2px 2px 0 rgba(50, 50, 50, 0.64), 0 3px 1px -2px rgba(50, 50, 50, 0.62), 0 1px 5px 0 rgba(50, 50, 50, 0.7); | |||||
box-shadow: 0 2px 2px 0 rgba(50, 50, 50, 0.64), 0 3px 1px -2px rgba(50, 50, 50, 0.62), 0 1px 5px 0 rgba(50, 50, 50, 0.7); | |||||
border-top: 1px solid rgba(96, 96, 96, 0.7); | |||||
border-right: 1px solid rgba(96, 96, 96, 0.7); | |||||
border-left: 1px solid rgba(96, 96, 96, 0.7); | |||||
} | |||||
/* header */ | |||||
.collapse-container.last-modified>:nth-child(odd) { | |||||
background-color: #3f3f3f; | |||||
border-bottom: 1px solid rgba(96, 96, 96, 0.7); | |||||
} | |||||
/* body */ | |||||
.collapse-container.last-modified>:nth-child(even) { | |||||
border-bottom: 1px solid rgba(96, 96, 96, 0.7); | |||||
background-color: inherit; | |||||
} | |||||
span.arrow-d{ | |||||
border-top: 5px solid white | |||||
} | |||||
span.arrow-r{ | |||||
border-left: 5px solid white | |||||
} | |||||
.logo-switcher { | |||||
background: url("/marketing/logo/SVG/Combinationmark White.svg") no-repeat; | |||||
} |
@@ -1,315 +0,0 @@ | |||||
/* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. */ | |||||
@import url('vs2015.css'); | |||||
html, | |||||
body { | |||||
background: #23272A; | |||||
color: #dddddd; | |||||
} | |||||
button, | |||||
a { | |||||
color: #64B5F6; | |||||
} | |||||
.sidenav{ | |||||
background-color: rgb(30, 30, 30); | |||||
} | |||||
button:hover, | |||||
button:focus, | |||||
a:hover, | |||||
a:focus, | |||||
.btn:focus, | |||||
.btn:hover{ | |||||
color: #2196F3; | |||||
} | |||||
a.disable, | |||||
a.disable:hover { | |||||
color: #EEEEEE; | |||||
} | |||||
.divider { | |||||
color: #37474F; | |||||
} | |||||
hr { | |||||
border-color: #37474F; | |||||
} | |||||
/* top navbar */ | |||||
.navbar-inverse[role="navigation"] { | |||||
background-color: #2C2F33; | |||||
} | |||||
/* sub navbar (below top) */ | |||||
.subnav { | |||||
background: #282B2F | |||||
} | |||||
.inheritance h5, | |||||
.inheritedMembers h5 { | |||||
border-bottom: 1px solid #37474F; | |||||
} | |||||
article h4 { | |||||
border-bottom: 1px solid #37474F; | |||||
} | |||||
.docs-search { | |||||
background: #424242; | |||||
} | |||||
.search-results-group-heading { | |||||
color: #424242; | |||||
} | |||||
.search-close { | |||||
color: #424242; | |||||
} | |||||
.sidetoc { | |||||
background-color: #1b1b1b; | |||||
border-left: 0px solid #37474F; | |||||
border-right: 0px solid #37474F; | |||||
} | |||||
.sideaffix { | |||||
overflow: visible; | |||||
} | |||||
.sideaffix>div.contribution>ul>li>a.contribution-link:hover { | |||||
background-color: #333333; | |||||
} | |||||
/* toc */ | |||||
.toc .nav>li>a { | |||||
color: rgb(218, 218, 218); | |||||
} | |||||
.toc .nav>li>a:hover, | |||||
.toc .nav>li>a:focus { | |||||
color: #E0E0E0; | |||||
} | |||||
.toc .nav>li.active>a { | |||||
color: #90CAF9; | |||||
} | |||||
.toc .nav>li.active>a:hover, | |||||
.toc .nav>li.active>a:focus { | |||||
background-color: #37474F; | |||||
color: #4FC3F7; | |||||
} | |||||
.sidefilter { | |||||
background-color: #1b1b1b; | |||||
border-left: 0px solid #37474F; | |||||
border-right: 0px solid #37474F; | |||||
} | |||||
.affix ul>li>a:hover { | |||||
background: none; | |||||
color: #EEEEEE; | |||||
} | |||||
.affix ul>li.active>a, | |||||
.affix ul>li.active>a:before { | |||||
color: #B3E5FC; | |||||
} | |||||
.affix ul>li>a { | |||||
color: #EEEEEE; | |||||
} | |||||
.affix>ul>li.active>a, | |||||
.affix>ul>li.active>a:before { | |||||
color: #B3E5FC; | |||||
} | |||||
.tryspan { | |||||
border-color: #37474F; | |||||
} | |||||
.footer { | |||||
border-top: 1px solid #5F5F5F; | |||||
background: #2C2F33; | |||||
} | |||||
/* alert */ | |||||
.alert-info { | |||||
color: #f3fdff; | |||||
background: #40788A; | |||||
border-color: #2F7A95; | |||||
} | |||||
.alert-warning { | |||||
color: #fffaf2; | |||||
background: #936C36; | |||||
border-color: #AE8443; | |||||
} | |||||
.alert-danger { | |||||
color: #fff4f4; | |||||
background: #834040; | |||||
border-color: #8C2F2F | |||||
} | |||||
/* For tabbed content */ | |||||
.tabGroup { | |||||
margin-top: 1rem; | |||||
} | |||||
.tabGroup ul[role="tablist"] { | |||||
margin: 0; | |||||
padding: 0; | |||||
list-style: none; | |||||
} | |||||
.tabGroup ul[role="tablist"]>li { | |||||
list-style: none; | |||||
display: inline-block; | |||||
} | |||||
.tabGroup a[role="tab"] { | |||||
color: white; | |||||
box-sizing: border-box; | |||||
display: inline-block; | |||||
padding: 5px 7.5px; | |||||
text-decoration: none; | |||||
border-bottom: 2px solid #fff; | |||||
} | |||||
.tabGroup a[role="tab"]:hover, | |||||
.tabGroup a[role="tab"]:focus, | |||||
.tabGroup a[role="tab"][aria-selected="true"] { | |||||
border-bottom: 2px solid #607D8B; | |||||
} | |||||
.tabGroup a[role="tab"][aria-selected="true"] { | |||||
color: #81D4FA; | |||||
} | |||||
.tabGroup a[role="tab"]:hover, | |||||
.tabGroup a[role="tab"]:focus { | |||||
color: #29B6F6; | |||||
} | |||||
.tabGroup a[role="tab"]:focus { | |||||
outline: 1px solid #607D8B; | |||||
outline-offset: -1px; | |||||
} | |||||
@media (min-width: 768px) { | |||||
.tabGroup a[role="tab"] { | |||||
padding: 5px 15px; | |||||
} | |||||
} | |||||
.tabGroup section[role="tabpanel"] { | |||||
border: 1px solid #607D8B; | |||||
padding: 15px; | |||||
margin: 0; | |||||
overflow: hidden; | |||||
} | |||||
.tabGroup section[role="tabpanel"]>.codeHeader, | |||||
.tabGroup section[role="tabpanel"]>pre { | |||||
margin-left: -16px; | |||||
margin-right: -16px; | |||||
} | |||||
.tabGroup section[role="tabpanel"]> :first-child { | |||||
margin-top: 0; | |||||
} | |||||
.tabGroup section[role="tabpanel"]>pre:last-child { | |||||
display: block; | |||||
margin-bottom: -16px; | |||||
} | |||||
.mainContainer[dir='rtl'] main ul[role="tablist"] { | |||||
margin: 0; | |||||
} | |||||
/* code */ | |||||
code { | |||||
color: white; | |||||
background-color: #5B646B; | |||||
border-radius: 4px; | |||||
padding: 3px 7px; | |||||
} | |||||
pre { | |||||
background-color: #282a36; | |||||
} | |||||
/* table */ | |||||
.table-striped>tbody>tr:nth-of-type(odd) { | |||||
background-color: #333333; | |||||
color: #d3d3d3 | |||||
} | |||||
tbody>tr { | |||||
background-color: #424242; | |||||
color: #c0c0c0 | |||||
} | |||||
.table>tbody+tbody { | |||||
border-top: 2px solid rgb(173, 173, 173) | |||||
} | |||||
/* select */ | |||||
select { | |||||
background-color: #3b3b3b; | |||||
border-color: #2e2e2e; | |||||
} | |||||
/* | |||||
Following code regarding collapse container are fetched | |||||
or modified from the Materialize project. | |||||
The MIT License (MIT) | |||||
Copyright (c) 2014-2018 Materialize | |||||
https://github.com/Dogfalo/materialize | |||||
*/ | |||||
/* all collapse container */ | |||||
.collapse-container.last-modified { | |||||
-webkit-box-shadow: 0 2px 2px 0 rgba(50, 50, 50, 0.64), 0 3px 1px -2px rgba(50, 50, 50, 0.62), 0 1px 5px 0 rgba(50, 50, 50, 0.7); | |||||
box-shadow: 0 2px 2px 0 rgba(50, 50, 50, 0.64), 0 3px 1px -2px rgba(50, 50, 50, 0.62), 0 1px 5px 0 rgba(50, 50, 50, 0.7); | |||||
border-top: 1px solid rgba(96, 96, 96, 0.7); | |||||
border-right: 1px solid rgba(96, 96, 96, 0.7); | |||||
border-left: 1px solid rgba(96, 96, 96, 0.7); | |||||
} | |||||
/* header */ | |||||
.collapse-container.last-modified>:nth-child(odd) { | |||||
background-color: #3f3f3f; | |||||
border-bottom: 1px solid rgba(96, 96, 96, 0.7); | |||||
} | |||||
/* body */ | |||||
.collapse-container.last-modified>:nth-child(even) { | |||||
border-bottom: 1px solid rgba(96, 96, 96, 0.7); | |||||
background-color: inherit; | |||||
} | |||||
span.arrow-d{ | |||||
border-top: 5px solid white | |||||
} | |||||
span.arrow-r{ | |||||
border-left: 5px solid white | |||||
} | |||||
.logo-switcher { | |||||
background: url("/marketing/logo/SVG/Combinationmark White.svg") no-repeat; | |||||
} |
@@ -1,117 +0,0 @@ | |||||
/* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. */ | |||||
@import url('tomorrow.css'); | |||||
html, | |||||
body { | |||||
background: #fff; | |||||
color: #000; | |||||
} | |||||
.sideaffix { | |||||
overflow: visible; | |||||
} | |||||
/* links */ | |||||
a:active, a:hover, a:visited { | |||||
color: #0078d7; | |||||
} | |||||
a { | |||||
color: #0050c5; | |||||
cursor: pointer; | |||||
text-decoration: none; | |||||
word-wrap: break-word; | |||||
} | |||||
/* alert */ | |||||
.alert-info { | |||||
color: #165e82; | |||||
background-color: #c1e0ef; | |||||
border-color: #8cbfd8; | |||||
} | |||||
.alert-warning { | |||||
color: #825e16; | |||||
background-color: #efe0c1; | |||||
border-color: #d8bf8c; | |||||
} | |||||
.alert-danger { | |||||
color: #821616; | |||||
background-color: #efc1c1; | |||||
border-color: #d88c8c; | |||||
} | |||||
/* code */ | |||||
code { | |||||
color: #9c3a3f; | |||||
background-color: #ececec; | |||||
border-radius: 4px; | |||||
padding: 3px 7px; | |||||
} | |||||
/* table */ | |||||
.table-striped>tbody>tr:nth-of-type(odd) { | |||||
color: #333333; | |||||
background-color: #d3d3d3 | |||||
} | |||||
tbody>tr { | |||||
color: #424242; | |||||
background-color: #c0c0c0 | |||||
} | |||||
.table>tbody+tbody { | |||||
border-top: 2px solid rgb(173, 173, 173) | |||||
} | |||||
/* select */ | |||||
select { | |||||
background-color: #fcfcfc; | |||||
border-color: #aeb1b5; | |||||
} | |||||
/* | |||||
Following code regarding collapse container are fetched | |||||
or modified from the Materialize project. | |||||
The MIT License (MIT) | |||||
Copyright (c) 2014-2018 Materialize | |||||
https://github.com/Dogfalo/materialize | |||||
*/ | |||||
/* all collapse container */ | |||||
.collapse-container.last-modified { | |||||
-webkit-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.12), 0 1px 5px 0 rgba(0, 0, 0, 0.2); | |||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.12), 0 1px 5px 0 rgba(0, 0, 0, 0.2); | |||||
border-top: 1px solid #ddd; | |||||
border-right: 1px solid #ddd; | |||||
border-left: 1px solid #ddd; | |||||
} | |||||
/* header */ | |||||
.collapse-container.last-modified>:nth-child(odd) { | |||||
background-color: #fff; | |||||
border-bottom: 1px solid #ddd; | |||||
} | |||||
/* body */ | |||||
.collapse-container.last-modified>:nth-child(even) { | |||||
border-bottom: 1px solid #ddd; | |||||
} | |||||
span.arrow-d{ | |||||
border-top: 5px solid black | |||||
} | |||||
span.arrow-r{ | |||||
border-left: 5px solid black | |||||
} | |||||
.logo-switcher { | |||||
background: url("/marketing/logo/SVG/Combinationmark.svg") no-repeat; | |||||
} |
@@ -1,175 +0,0 @@ | |||||
@import url('https://fonts.googleapis.com/css?family=Titillium+Web|Noto+Sans'); | |||||
html, | |||||
body { | |||||
font-family: 'Titillium Web', 'Segoe UI', Tahoma, Helvetica, sans-serif; | |||||
font-display: optional; | |||||
height: 100%; | |||||
font-size: 15px; | |||||
scroll-behavior: smooth; | |||||
} | |||||
#logo | |||||
{ | |||||
max-width: 100px; | |||||
max-height: 100px; | |||||
width: 38pt; | |||||
height: 38pt; | |||||
padding: 8pt; | |||||
} | |||||
p, | |||||
li, | |||||
.toc { | |||||
text-rendering: optimizeLegibility; | |||||
line-height: 160%; | |||||
} | |||||
img { | |||||
box-shadow: 0px 0px 3px 0px rgb(66, 66, 66); | |||||
max-width: 95% !important; | |||||
margin-top: 15px; | |||||
margin-bottom: 15px; | |||||
} | |||||
.big-logo { | |||||
display: block; | |||||
box-shadow: none !important; | |||||
/* Width value was taken from the original size of the combomark svg */ | |||||
width: 951pt; | |||||
/* Height was arbitrarily determined */ | |||||
min-height: 100pt; | |||||
max-width: 90%; | |||||
} | |||||
article.content p{ | |||||
-webkit-transition: all .75s ease-in-out; | |||||
transition: all .75s ease-in-out; | |||||
} | |||||
article.content h1, | |||||
article.content h2, | |||||
article.content h3, | |||||
article.content h4, | |||||
article.content h5, | |||||
article.content h6{ | |||||
-webkit-transition: all .25s ease-in-out; | |||||
transition: all .25s ease-in-out; | |||||
} | |||||
h1, | |||||
h2, | |||||
h3, | |||||
h4, | |||||
h5, | |||||
h6 { | |||||
font-family: 'Noto Sans', Verdana, Geneva, Tahoma, sans-serif; | |||||
line-height: 130%; | |||||
} | |||||
.sideaffix { | |||||
line-height: 140%; | |||||
} | |||||
header .navbar { | |||||
border-width: 0 0 0px; | |||||
border-radius: 0; | |||||
} | |||||
body .toc { | |||||
background-color: inherit; | |||||
overflow: visible; | |||||
} | |||||
select { | |||||
display: inline-block; | |||||
overflow: auto; | |||||
-webkit-box-sizing: border-box; | |||||
box-sizing: border-box; | |||||
margin: 0; | |||||
padding: 0 30px 0 6px; | |||||
vertical-align: middle; | |||||
height: 28px; | |||||
border: 1px solid #e3e3e3; | |||||
line-height: 16px; | |||||
outline: 0; | |||||
text-overflow: ellipsis; | |||||
-webkit-appearance: none; | |||||
-moz-appearance: none; | |||||
cursor: pointer; | |||||
background-image: linear-gradient(45deg, transparent 50%, #707070 0), linear-gradient(135deg, #707070 50%, transparent 0); | |||||
background-position: calc(100% - 13px) 11px, calc(100% - 8px) 11px; | |||||
background-size: 5px 5px, 5px 6px; | |||||
background-repeat: no-repeat; | |||||
} | |||||
/* | |||||
Following code are fetched or modified from | |||||
the Materialize project. | |||||
The MIT License (MIT) | |||||
Copyright (c) 2014-2018 Materialize | |||||
https://github.com/Dogfalo/materialize | |||||
*/ | |||||
/* all collapse container */ | |||||
.collapse-container.last-modified { | |||||
margin: 0.5rem 0 1rem 0; | |||||
} | |||||
/* header */ | |||||
.collapse-container.last-modified>:nth-child(odd):focus { | |||||
outline: 0; | |||||
} | |||||
.collapse-container.last-modified>:nth-child(odd) { | |||||
display: -webkit-box; | |||||
display: -webkit-flex; | |||||
display: -ms-flexbox; | |||||
display: flex; | |||||
cursor: pointer; | |||||
-webkit-tap-highlight-color: transparent; | |||||
line-height: 1.5; | |||||
padding: 0.75rem; | |||||
background-image: none; | |||||
border: 0px; | |||||
} | |||||
/* body */ | |||||
.collapse-container.last-modified>:nth-child(even) { | |||||
display: none; | |||||
-webkit-box-sizing: border-box; | |||||
box-sizing: border-box; | |||||
padding: 1rem; | |||||
border: 0px; | |||||
} | |||||
/* nav bar */ | |||||
.nav { | |||||
margin: 0; | |||||
} | |||||
.nav li { | |||||
-webkit-transition: background-color .3s, color .3s; | |||||
transition: background-color .3s, color .3s; | |||||
} | |||||
.nav a { | |||||
-webkit-transition: background-color .3s, color .3s; | |||||
transition: background-color .3s, color .3s; | |||||
cursor: pointer; | |||||
} | |||||
/* arrow */ | |||||
span.arrow-d{ | |||||
top: 6px; position: relative; | |||||
} | |||||
span.arrow-r{ | |||||
top: 6px; position: relative; | |||||
} |
@@ -1,37 +0,0 @@ | |||||
// MIT License | |||||
// Copyright (c) 2017 Roel Fauconnier | |||||
// Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
// of this software and associated documentation files (the "Software"), to deal | |||||
// in the Software without restriction, including without limitation the rights | |||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
// copies of the Software, and to permit persons to whom the Software is | |||||
// furnished to do so, subject to the following conditions: | |||||
// The above copyright notice and this permission notice shall be included in all | |||||
// copies or substantial portions of the Software. | |||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
// SOFTWARE. | |||||
$(document).ready(function() { | |||||
//find all images, but not the logo, and add the lightbox | |||||
$('img').not('#logo').each(function(){ | |||||
var $img = $(this); | |||||
var filename = $img.attr('src') | |||||
//add cursor | |||||
$img.css('cursor','zoom-in'); | |||||
$img.css('cursor','-moz-zoom-in'); | |||||
$img.css('cursor','-webkit-zoom-in'); | |||||
//add featherlight | |||||
$img.attr('alt', filename); | |||||
$img.featherlight(filename); | |||||
}); | |||||
}); |
@@ -1,26 +0,0 @@ | |||||
const baseUrl = document.getElementById("docfx-style:rel").content; | |||||
function onThemeSelect(event) { | |||||
const theme = event.target.value; | |||||
window.localStorage.setItem("theme", theme); | |||||
window.themeElement.href = getUrl(theme); | |||||
} | |||||
function getUrl(slug) { | |||||
return baseUrl + "styles/" + slug + ".css"; | |||||
} | |||||
const themeElement = document.createElement("link"); | |||||
themeElement.rel = "stylesheet"; | |||||
const theme = window.localStorage.getItem("theme") || "light"; | |||||
themeElement.href = getUrl(theme); | |||||
document.head.appendChild(themeElement); | |||||
window.themeElement = themeElement; | |||||
document.addEventListener("DOMContentLoaded", function() { | |||||
const themeSwitcher = document.getElementById("theme-switcher"); | |||||
themeSwitcher.onchange = onThemeSelect; | |||||
themeSwitcher.value = theme; | |||||
}, false); |
@@ -1,9 +0,0 @@ | |||||
div.theme-switch-field { | |||||
padding-left: 10px; | |||||
padding-bottom: 15px | |||||
} | |||||
div.theme-switch-field > p{ | |||||
font-weight: bold; | |||||
font-size: 1.2em; | |||||
} |
@@ -1,72 +0,0 @@ | |||||
/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ | |||||
/* Tomorrow Comment */ | |||||
.hljs-comment, | |||||
.hljs-quote { | |||||
color: #8e908c; | |||||
} | |||||
/* Tomorrow Red */ | |||||
.hljs-variable, | |||||
.hljs-template-variable, | |||||
.hljs-tag, | |||||
.hljs-name, | |||||
.hljs-selector-id, | |||||
.hljs-selector-class, | |||||
.hljs-regexp, | |||||
.hljs-deletion { | |||||
color: #c82829; | |||||
} | |||||
/* Tomorrow Orange */ | |||||
.hljs-number, | |||||
.hljs-built_in, | |||||
.hljs-builtin-name, | |||||
.hljs-literal, | |||||
.hljs-type, | |||||
.hljs-params, | |||||
.hljs-meta, | |||||
.hljs-link { | |||||
color: #f5871f; | |||||
} | |||||
/* Tomorrow Yellow */ | |||||
.hljs-attribute { | |||||
color: #eab700; | |||||
} | |||||
/* Tomorrow Green */ | |||||
.hljs-string, | |||||
.hljs-symbol, | |||||
.hljs-bullet, | |||||
.hljs-addition { | |||||
color: #718c00; | |||||
} | |||||
/* Tomorrow Blue */ | |||||
.hljs-title, | |||||
.hljs-section { | |||||
color: #4271ae; | |||||
} | |||||
/* Tomorrow Purple */ | |||||
.hljs-keyword, | |||||
.hljs-selector-tag { | |||||
color: #8959a8; | |||||
} | |||||
.hljs { | |||||
display: block; | |||||
overflow-x: auto; | |||||
background: white; | |||||
color: #4d4d4c; | |||||
padding: 0.5em; | |||||
} | |||||
.hljs-emphasis { | |||||
font-style: italic; | |||||
} | |||||
.hljs-strong { | |||||
font-weight: bold; | |||||
} |
@@ -1,115 +0,0 @@ | |||||
/* | |||||
* Visual Studio 2015 dark style | |||||
* Author: Nicolas LLOBERA <nllobera@gmail.com> | |||||
*/ | |||||
.hljs { | |||||
display: block; | |||||
overflow-x: auto; | |||||
padding: 0.5em; | |||||
background: #282a36; | |||||
color: #DCDCDC; | |||||
} | |||||
.hljs-keyword, | |||||
.hljs-literal, | |||||
.hljs-symbol, | |||||
.hljs-name { | |||||
color: #569CD6; | |||||
} | |||||
.hljs-link { | |||||
color: #569CD6; | |||||
text-decoration: underline; | |||||
} | |||||
.hljs-built_in, | |||||
.hljs-type { | |||||
color: #4EC9B0; | |||||
} | |||||
.hljs-number, | |||||
.hljs-class { | |||||
color: #B8D7A3; | |||||
} | |||||
.hljs-string, | |||||
.hljs-meta-string { | |||||
color: #D69D85; | |||||
} | |||||
.hljs-regexp, | |||||
.hljs-template-tag { | |||||
color: #9A5334; | |||||
} | |||||
.hljs-subst, | |||||
.hljs-function, | |||||
.hljs-title, | |||||
.hljs-params, | |||||
.hljs-formula { | |||||
color: #DCDCDC; | |||||
} | |||||
.hljs-comment, | |||||
.hljs-quote { | |||||
color: #57A64A; | |||||
font-style: italic; | |||||
} | |||||
.hljs-doctag { | |||||
color: #608B4E; | |||||
} | |||||
.hljs-meta, | |||||
.hljs-meta-keyword, | |||||
.hljs-tag { | |||||
color: #9B9B9B; | |||||
} | |||||
.hljs-variable, | |||||
.hljs-template-variable { | |||||
color: #BD63C5; | |||||
} | |||||
.hljs-attr, | |||||
.hljs-attribute, | |||||
.hljs-builtin-name { | |||||
color: #9CDCFE; | |||||
} | |||||
.hljs-section { | |||||
color: gold; | |||||
} | |||||
.hljs-emphasis { | |||||
font-style: italic; | |||||
} | |||||
.hljs-strong { | |||||
font-weight: bold; | |||||
} | |||||
/*.hljs-code { | |||||
font-family:'Monospace'; | |||||
}*/ | |||||
.hljs-bullet, | |||||
.hljs-selector-tag, | |||||
.hljs-selector-id, | |||||
.hljs-selector-class, | |||||
.hljs-selector-attr, | |||||
.hljs-selector-pseudo { | |||||
color: #D7BA7D; | |||||
} | |||||
.hljs-addition { | |||||
background-color: #144212; | |||||
display: inline-block; | |||||
width: 100%; | |||||
} | |||||
.hljs-deletion { | |||||
background-color: #600; | |||||
display: inline-block; | |||||
width: 100%; | |||||
} |
@@ -1,6 +0,0 @@ | |||||
############### | |||||
# temp file # | |||||
############### | |||||
*.yml | |||||
.manifest |
@@ -1,16 +0,0 @@ | |||||
--- | |||||
uid: API.Docs | |||||
--- | |||||
# API Documentation | |||||
This is where you will find documentation for all members and objects in Discord.Net. | |||||
# Commonly Used Entities | |||||
* @Discord.WebSocket | |||||
* @Discord.WebSocket.DiscordSocketClient | |||||
* @Discord.WebSocket.SocketGuildChannel | |||||
* @Discord.WebSocket.SocketGuildUser | |||||
* @Discord.WebSocket.SocketMessage | |||||
* @Discord.WebSocket.SocketRole |
@@ -1,62 +0,0 @@ | |||||
{ | |||||
"metadata": [{ | |||||
"src": [{ | |||||
"src": "../src", | |||||
"files": [ | |||||
"**.csproj" | |||||
] | |||||
}], | |||||
"dest": "api", | |||||
"filter": "filterConfig.yml", | |||||
"properties": { | |||||
"TargetFramework": "netstandard1.3" | |||||
} | |||||
}], | |||||
"build": { | |||||
"content": [{ | |||||
"files": ["api/**.yml", "api/index.md"] | |||||
}, | |||||
{ | |||||
"files": ["toc.yml", "index.md"] | |||||
}, | |||||
{ | |||||
"files": ["faq/**.md", "faq/**/toc.yml"] | |||||
}, | |||||
{ | |||||
"files": ["guides/**.md", "guides/**/toc.yml"] | |||||
}, | |||||
{ | |||||
"src": "../", | |||||
"files": [ "CHANGELOG.md" ] | |||||
} | |||||
], | |||||
"resource": [{ | |||||
"files": [ | |||||
"**/images/**", | |||||
"**/samples/**", | |||||
"langwordMapping.yml", | |||||
"marketing/logo/SVG/**.svg", | |||||
"favicon.ico" | |||||
] | |||||
}], | |||||
"dest": "_site", | |||||
"template": [ | |||||
"default", | |||||
"_template/light-dark-theme", | |||||
"_template/last-modified", | |||||
"_template/description-generator" | |||||
], | |||||
"postProcessors": ["ExtractSearchIndex", "LastModifiedPostProcessor", "DescriptionPostProcessor"], | |||||
"overwrite": "_overwrites/**/**.md", | |||||
"globalMetadata": { | |||||
"_appTitle": "Discord.Net Documentation", | |||||
"_appFooter": "Discord.Net (c) 2015-2018 2.0.0-beta", | |||||
"_enableSearch": true, | |||||
"_appLogoPath": "marketing/logo/SVG/Logomark Purple.svg", | |||||
"_appFaviconPath": "favicon.ico" | |||||
}, | |||||
"xrefService": [ | |||||
"https://xref.docs.microsoft.com/query?uid={uid}" | |||||
] | |||||
} | |||||
} |
@@ -1,123 +0,0 @@ | |||||
--- | |||||
uid: FAQ.Basics.BasicOp | |||||
title: Questions about Basic Operations | |||||
--- | |||||
# Basic Operations Questions | |||||
In the following section, you will find commonly asked questions and | |||||
answers regarding basic usage of the library, as well as | |||||
language-specific tips when using this library. | |||||
## How should I safely check a type? | |||||
> [!WARNING] | |||||
> Direct casting (e.g., `(Type)type`) is **the least recommended** | |||||
> way of casting, as it *can* throw an [InvalidCastException] | |||||
> when the object isn't the desired type. | |||||
> | |||||
> Please refer to [this post] for more details. | |||||
In Discord.Net, the idea of polymorphism is used throughout. You may | |||||
need to cast the object as a certain type before you can perform any | |||||
action. | |||||
A good and safe casting example: | |||||
[!code-csharp[Casting](samples/cast.cs)] | |||||
[InvalidCastException]: https://docs.microsoft.com/en-us/dotnet/api/system.invalidcastexception | |||||
[this post]: https://docs.microsoft.com/en-us/dotnet/csharp/how-to/safely-cast-using-pattern-matching-is-and-as-operators | |||||
## How do I send a message? | |||||
> [!TIP] | |||||
> The [GetChannel] method by default returns an [IChannel], allowing | |||||
> channel types such as [IVoiceChannel], [ICategoryChannel] | |||||
> to be returned; consequently, you cannot send a message | |||||
> to channels like those. | |||||
Any implementation of [IMessageChannel] has a [SendMessageAsync] | |||||
method. You can get the channel via [GetChannel] under the client. | |||||
Remember, when using Discord.Net, polymorphism is a common recurring | |||||
theme. This means an object may take in many shapes or form, which | |||||
means casting is your friend. You should attempt to cast the channel | |||||
as an [IMessageChannel] or any other entity that implements it to be | |||||
able to message. | |||||
[SendMessageAsync]: xref:Discord.IMessageChannel.SendMessageAsync* | |||||
[GetChannel]: xref:Discord.WebSocket.DiscordSocketClient.GetChannel* | |||||
## How can I tell if a message is from X, Y, Z channel? | |||||
You may check the message channel type. Visit [Glossary] to see the | |||||
various types of channels. | |||||
[Glossary]: xref:FAQ.Glossary#message-channels | |||||
## How can I get the guild from a message? | |||||
There are 2 ways to do this. You can do either of the following, | |||||
1. Cast the user as an [IGuildUser] and use its [IGuild] property. | |||||
2. Cast the channel as an [IGuildChannel] and use its [IGuild] property. | |||||
## How do I add hyperlink text to an embed? | |||||
Embeds can use standard [markdown] in the description field as well | |||||
as in field values. With that in mind, links can be added with | |||||
`[text](link)`. | |||||
[markdown]: https://support.discordapp.com/hc/en-us/articles/210298617-Markdown-Text-101-Chat-Formatting-Bold-Italic-Underline- | |||||
## How do I add reactions to a message? | |||||
Any entity that implements [IUserMessage] has an [AddReactionAsync] | |||||
method. This method expects an [IEmote] as a parameter. | |||||
In Discord.Net, an Emote represents a custom-image emote, while an | |||||
Emoji is a Unicode emoji (standard emoji). Both [Emoji] and [Emote] | |||||
implement [IEmote] and are valid options. | |||||
# [Adding a reaction to another message](#tab/emoji-others) | |||||
[!code-csharp[Emoji](samples/emoji-others.cs)] | |||||
# [Adding a reaction to a sent message](#tab/emoji-self) | |||||
[!code-csharp[Emoji](samples/emoji-self.cs)] | |||||
*** | |||||
[AddReactionAsync]: xref:Discord.IUserMessage.AddReactionAsync* | |||||
## What is a "preemptive rate limit?" | |||||
A preemptive rate limit is Discord.Net's way of telling you to slow | |||||
down before you get hit by the real rate limit. Hitting a real rate | |||||
limit might prevent your entire client from sending any requests for | |||||
a period of time. This is calculated based on the HTTP header | |||||
returned by a Discord response. | |||||
## Why am I getting so many preemptive rate limits when I try to add more than one reactions? | |||||
This is due to how HTML header works, mistreating | |||||
0.25sec/action to 1sec. This causes the lib to throw preemptive rate | |||||
limit more frequently than it should for methods such as adding | |||||
reactions. | |||||
## Can I opt-out of preemptive rate limits? | |||||
Unfortunately, not at the moment. See [#401](https://github.com/RogueException/Discord.Net/issues/401). | |||||
[IChannel]: xref:Discord.IChannel | |||||
[ICategoryChannel]: xref:Discord.ICategoryChannel | |||||
[IGuildChannel]: xref:Discord.IGuildChannel | |||||
[ITextChannel]: xref:Discord.ITextChannel | |||||
[IGuild]: xref:Discord.IGuild | |||||
[IVoiceChannel]: xref:Discord.IVoiceChannel | |||||
[IGuildUser]: xref:Discord.IGuildUser | |||||
[IMessageChannel]: xref:Discord.IMessageChannel | |||||
[IUserMessage]: xref:Discord.IUserMessage | |||||
[IEmote]: xref:Discord.IEmote | |||||
[Emote]: xref:Discord.Emote | |||||
[Emoji]: xref:Discord.Emoji |
@@ -1,94 +0,0 @@ | |||||
--- | |||||
uid: FAQ.Basics.ClientBasics | |||||
title: Basic Questions about Client | |||||
--- | |||||
# Client Basics Questions | |||||
In the following section, you will find commonly asked questions and | |||||
answers about common issues that you may face when utilizing the | |||||
various clients offered by the library. | |||||
## My client keeps returning 401 upon logging in! | |||||
> [!WARNING] | |||||
> Userbot/selfbot (logging in with a user token) is no | |||||
> longer supported with this library starting from 2.0, as | |||||
> logging in under a user account may result in account termination. | |||||
> | |||||
> For more information, see issue [827] & [958], as well as the official | |||||
> [Discord API Terms of Service]. | |||||
There are few possible reasons why this may occur. | |||||
1. You are not using the appropriate [TokenType]. If you are using a | |||||
bot account created from the Discord Developer portal, you should | |||||
be using `TokenType.Bot`. | |||||
2. You are not using the correct login credentials. Please keep in | |||||
mind that a token is **different** from a *client secret*. | |||||
[TokenType]: xref:Discord.TokenType | |||||
[827]: https://github.com/RogueException/Discord.Net/issues/827 | |||||
[958]: https://github.com/RogueException/Discord.Net/issues/958 | |||||
[Discord API Terms of Service]: https://discordapp.com/developers/docs/legal | |||||
## How do I do X, Y, Z when my bot connects/logs on? Why do I get a `NullReferenceException` upon calling any client methods after connect? | |||||
Your bot should **not** attempt to interact in any way with | |||||
guilds/servers until the [Ready] event fires. When the bot | |||||
connects, it first has to download guild information from | |||||
Discord for you to get access to any server | |||||
information; the client is not ready at this point. | |||||
Technically, the [GuildAvailable] event fires once the data for a | |||||
particular guild has downloaded; however, it is best to wait for all | |||||
guilds to be downloaded. Once all downloads are complete, the [Ready] | |||||
event is triggered, then you can proceed to do whatever you like. | |||||
[Ready]: xref:Discord.WebSocket.DiscordSocketClient.Ready | |||||
[GuildAvailable]: xref:Discord.WebSocket.BaseSocketClient.GuildAvailable | |||||
## How do I get a message's previous content when that message is edited? | |||||
If you need to do anything with messages (e.g., checking Reactions, | |||||
checking the content of edited/deleted messages), you must set the | |||||
[MessageCacheSize] in your [DiscordSocketConfig] settings in order to | |||||
use the cached message entity. Read more about it [here](xref:Guides.Concepts.Events#cacheable). | |||||
1. Message Cache must be enabled. | |||||
2. Hook the MessageUpdated event. This event provides a *before* and | |||||
*after* object. | |||||
3. Only messages received *after* the bot comes online will be | |||||
available in the cache. | |||||
[MessageCacheSize]: xref:Discord.WebSocket.DiscordSocketConfig.MessageCacheSize | |||||
[DiscordSocketConfig]: xref:Discord.WebSocket.DiscordSocketConfig | |||||
[MessageUpdated]: xref:Discord.WebSocket.BaseSocketClient.MessageUpdated | |||||
## What is a shard/sharded client, and how is it different from the `DiscordSocketClient`? | |||||
As your bot grows in popularity, it is recommended that you should section your bot off into separate processes. | |||||
The [DiscordShardedClient] is essentially a class that allows you to easily create and manage multiple [DiscordSocketClient] | |||||
instances, with each one serving a different amount of guilds. | |||||
There are very few differences from the [DiscordSocketClient] class, and it is very straightforward | |||||
to modify your existing code to use a [DiscordShardedClient] when necessary. | |||||
1. You need to specify the total amount of shards, or shard ids, via [DiscordShardedClient]'s constructors. | |||||
2. The [Connected], [Disconnected], [Ready], and [LatencyUpdated] events | |||||
are replaced with [ShardConnected], [ShardDisconnected], [ShardReady], and [ShardLatencyUpdated]. | |||||
3. Every event handler you apply/remove to the [DiscordShardedClient] is applied/removed to each shard. | |||||
If you wish to control a specific shard's events, you can access an individual shard through the `Shards` property. | |||||
If you do not wish to use the [DiscordShardedClient] and instead reuse the same [DiscordSocketClient] code and manually shard them, | |||||
you can do so by specifying the [ShardId] for the [DiscordSocketConfig] and pass that to the [DiscordSocketClient]'s constructor. | |||||
[DiscordSocketClient]: xref:Discord.WebSocket.DiscordSocketClient | |||||
[DiscordShardedClient]: xref:Discord.WebSocket.DiscordShardedClient | |||||
[Connected]: xref:Discord.WebSocket.DiscordSocketClient.Connected | |||||
[Disconnected]: xref:Discord.WebSocket.DiscordSocketClient.Disconnected | |||||
[LatencyUpdated]: xref:Discord.WebSocket.DiscordSocketClient.LatencyUpdated | |||||
[ShardConnected]: xref:Discord.WebSocket.DiscordShardedClient.ShardConnected | |||||
[ShardDisconnected]: xref:Discord.WebSocket.DiscordShardedClient.ShardDisconnected | |||||
[ShardReady]: xref:Discord.WebSocket.DiscordShardedClient.ShardReady | |||||
[ShardLatencyUpdated]: xref:Discord.WebSocket.DiscordShardedClient.ShardLatencyUpdated | |||||
[ShardId]: xref:Discord.WebSocket.DiscordSocketConfig.ShardId |
@@ -1,79 +0,0 @@ | |||||
--- | |||||
uid: FAQ.Basics.GetStarted | |||||
title: Beginner Questions / How to Get Started | |||||
--- | |||||
# Basic Concepts / Getting Started | |||||
In this following section, you will find commonly asked questions and | |||||
answers about how to get started with Discord.Net, as well as basic | |||||
introduction to the Discord API ecosystem. | |||||
## How do I add my bot to my server/guild? | |||||
You can do so by using the [permission calculator] provided | |||||
by [FiniteReality]. | |||||
This tool allows you to set permissions that the bot will be assigned | |||||
with, and invite the bot into your guild. With this method, bots will | |||||
also be assigned a unique role that a regular user cannot use; this | |||||
is what we call a `Managed` role. Because you cannot assign this | |||||
role to any other users, it is much safer than creating a single | |||||
role which, intentionally or not, can be applied to other users | |||||
to escalate their privilege. | |||||
[FiniteReality]: https://github.com/FiniteReality/permissions-calculator | |||||
[permission calculator]: https://finitereality.github.io/permissions-calculator | |||||
## What is a token? | |||||
A token is a credential used to log into an account. This information | |||||
should be kept **private** and for your eyes only. Anyone with your | |||||
token can log into your account. This risk applies to both user | |||||
and bot accounts. That also means that you should **never** hardcode | |||||
your token or add it into source control, as your identity may be | |||||
stolen by scrape bots on the internet that scours through | |||||
constantly to obtain a token. | |||||
## What is a client/user/object ID? | |||||
Each user and object on Discord has its own snowflake ID generated | |||||
based on various conditions. | |||||
 | |||||
Anyone can see the ID; it is public. It is merely used to | |||||
identify an object in the Discord ecosystem. Many things in the | |||||
Discord ecosystem require an ID to retrieve or identify the said | |||||
object. | |||||
There are 2 common ways to obtain the said ID. | |||||
### [Discord Developer Mode](#tab/dev-mode) | |||||
By enabling the developer mode you can right click on most objects | |||||
to obtain their snowflake IDs (please note that this may not apply to | |||||
all objects, such as role IDs, or DM channel IDs). | |||||
 | |||||
### [Escape Character](#tab/escape-char) | |||||
You can escape an object by using `\` in front the object in the | |||||
Discord client. For example, when you do `\@Example#1234` in chat, | |||||
it will return the user ID of the aforementioned user. | |||||
 | |||||
*** | |||||
## How do I get the role ID? | |||||
> [!WARNING] | |||||
> Right-clicking on the role and copying the ID will **not** work. | |||||
> This will only copy the message ID. | |||||
Several common ways to do this: | |||||
1. Make the role mentionable and mention the role, and escape it | |||||
using the `\` character in front. | |||||
2. Inspect the roles collection within the guild via your debugger. |
@@ -1,15 +0,0 @@ | |||||
public async Task MessageReceivedHandler(SocketMessage msg) | |||||
{ | |||||
// Option 1: | |||||
// Using the `as` keyword, which will return `null` if the object isn't the desired type. | |||||
var usermsg = msg as SocketUserMessage; | |||||
// We bail when the message isn't the desired type. | |||||
if (msg == null) return; | |||||
// Option 2: | |||||
// Using the `is` keyword to cast (C#7 or above only) | |||||
if (msg is SocketUserMessage usermsg) | |||||
{ | |||||
// Do things | |||||
} | |||||
} |
@@ -1,18 +0,0 @@ | |||||
// bail if the message is not a user one (system messages cannot have reactions) | |||||
var usermsg = msg as IUserMessage; | |||||
if (usermsg == null) return; | |||||
// standard Unicode emojis | |||||
Emoji emoji = new Emoji("👍"); | |||||
// or | |||||
// Emoji emoji = new Emoji("\uD83D\uDC4D"); | |||||
// custom guild emotes | |||||
Emote emote = Emote.Parse("<:dotnet:232902710280716288>"); | |||||
// using Emote.TryParse may be safer in regards to errors being thrown; | |||||
// please note that the method does not verify if the emote exists, | |||||
// it simply creates the Emote object for you. | |||||
// add the reaction to the message | |||||
await usermsg.AddReactionAsync(emoji); | |||||
await usermsg.AddReactionAsync(emote); |
@@ -1,17 +0,0 @@ | |||||
// capture the message you're sending in a variable | |||||
var msg = await channel.SendMessageAsync("This will have reactions added."); | |||||
// standard Unicode emojis | |||||
Emoji emoji = new Emoji("👍"); | |||||
// or | |||||
// Emoji emoji = new Emoji("\uD83D\uDC4D"); | |||||
// custom guild emotes | |||||
Emote emote = Emote.Parse("<:dotnet:232902710280716288>"); | |||||
// using Emote.TryParse may be safer in regards to errors being thrown; | |||||
// please note that the method does not verify if the emote exists, | |||||
// it simply creates the Emote object for you. | |||||
// add the reaction to the message | |||||
await msg.AddReactionAsync(emoji); | |||||
await msg.AddReactionAsync(emote); |
@@ -1,54 +0,0 @@ | |||||
--- | |||||
uid: FAQ.Commands.DI | |||||
title: Questions about Dependency Injection with Commands | |||||
--- | |||||
# Dependency-injection-related Questions | |||||
In the following section, you will find common questions and answers | |||||
to utilizing dependency injection with @Discord.Commands, as well as | |||||
common troubleshooting steps regarding DI. | |||||
## What is a service? Why does my module not hold any data after execution? | |||||
In Discord.Net, modules are created similarly to ASP.NET, meaning | |||||
that they have a transient nature; modules are spawned whenever a | |||||
request is received, and are killed from memory when the execution | |||||
finishes. In other words, you cannot store persistent | |||||
data inside a module. Consider using a service if you wish to | |||||
workaround this. | |||||
Service is often used to hold data externally so that they persist | |||||
throughout execution. Think of it like a chest that holds | |||||
whatever you throw at it that won't be affected by anything unless | |||||
you want it to. Note that you should also learn Microsoft's | |||||
implementation of [Dependency Injection] \([video]) before proceeding, | |||||
as well as how it works in [Discord.Net](xref:Guides.Commands.DI#usage-in-modules). | |||||
A brief example of service and dependency injection can be seen below. | |||||
[!code-csharp[DI](samples/DI.cs)] | |||||
[Dependency Injection]: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection | |||||
[video]: https://www.youtube.com/watch?v=QtDTfn8YxXg | |||||
## Why is my `CommandService` complaining about a missing dependency? | |||||
If you encounter an error similar to `Failed to create MyModule, | |||||
dependency MyExternalDependency was not found.`, you may have | |||||
forgotten to add the external dependency to the dependency container. | |||||
Starting from Discord.Net 2.0, all dependencies required by each | |||||
module must be present when the module is loaded into the | |||||
[CommandService]. This means when loading the module, you must pass a | |||||
valid [IServiceProvider] with the dependency loaded before the module | |||||
can be successfully registered. | |||||
For example, if your module, `MyModule`, requests a `DatabaseService` | |||||
in its constructor, the `DatabaseService` must be present in the | |||||
[IServiceProvider] when registering `MyModule`. | |||||
[!code-csharp[Missing Dependencies](samples/missing-dep.cs)] | |||||
[IServiceProvider]: xref:System.IServiceProvider | |||||
[CommandService]: xref:Discord.Commands.CommandService |
@@ -1,147 +0,0 @@ | |||||
--- | |||||
uid: FAQ.Commands.General | |||||
title: General Questions about Commands | |||||
--- | |||||
# Command-related Questions | |||||
In the following section, you will find commonly asked questions and | |||||
answered regarding general command usage when using @Discord.Commands. | |||||
## How can I restrict some of my commands so only specific users can execute them? | |||||
Based on how you want to implement the restrictions, you can use the | |||||
built-in [RequireUserPermission] precondition, which allows you to | |||||
restrict the command based on the user's current permissions in the | |||||
guild or channel (*e.g., `GuildPermission.Administrator`, | |||||
`ChannelPermission.ManageMessages`*). | |||||
If, however, you wish to restrict the commands based on the user's | |||||
role, you can either create your custom precondition or use | |||||
Joe4evr's [Preconditions Addons] that provides a few custom | |||||
preconditions that aren't provided in the stock library. | |||||
Its source can also be used as an example for creating your | |||||
custom preconditions. | |||||
[RequireUserPermission]: xref:Discord.Commands.RequireUserPermissionAttribute | |||||
[Preconditions Addons]: https://github.com/Joe4evr/Discord.Addons/tree/master/src/Discord.Addons.Preconditions | |||||
## Why am I getting an error about `Assembly.GetEntryAssembly`? | |||||
You may be confusing @Discord.Commands.CommandService.AddModulesAsync* | |||||
with @Discord.Commands.CommandService.AddModuleAsync*. The former | |||||
is used to add modules via the assembly, while the latter is used to | |||||
add a single module. | |||||
## What does [Remainder] do in the command signature? | |||||
The [RemainderAttribute] leaves the string unparsed, meaning you | |||||
do not have to add quotes around the text for the text to be | |||||
recognized as a single object. Please note that if your method has | |||||
multiple parameters, the remainder attribute can only be applied to | |||||
the last parameter. | |||||
[!code-csharp[Remainder](samples/Remainder.cs)] | |||||
[RemainderAttribute]: xref:Discord.Commands.RemainderAttribute | |||||
## Discord.Net keeps saying that a `MessageReceived` handler is blocking the gateway, what should I do? | |||||
By default, the library warns the user about any long-running event | |||||
handler that persists for **more than 3 seconds**. Any event | |||||
handlers that are run on the same thread as the gateway task, the task | |||||
in charge of keeping the connection alive, may block the processing of | |||||
heartbeat, and thus terminating the connection. | |||||
In this case, the library detects that a `MessageReceived` | |||||
event handler is blocking the gateway thread. This warning is | |||||
typically associated with the command handler as it listens for that | |||||
particular event. If the command handler is blocking the thread, then | |||||
this **might** mean that you have a long-running command. | |||||
> [!NOTE] | |||||
> In rare cases, runtime errors can also cause blockage, usually | |||||
> associated with Mono, which is not supported by this library. | |||||
To prevent a long-running command from blocking the gateway | |||||
thread, a flag called [RunMode] is explicitly designed to resolve | |||||
this issue. | |||||
There are 2 main `RunMode`s. | |||||
1. `RunMode.Sync` | |||||
2. `RunMode.Async` | |||||
`Sync` is the default behavior and makes the command to be run on the | |||||
same thread as the gateway one. `Async` will spin the task off to a | |||||
different thread from the gateway one. | |||||
> [!IMPORTANT] | |||||
> While specifying `RunMode.Async` allows the command to be spun off | |||||
> to a different thread, keep in mind that by doing so, there will be | |||||
> **potentially unwanted consequences**. Before applying this flag, | |||||
> please consider whether it is necessary to do so. | |||||
> | |||||
> Further details regarding `RunMode.Async` can be found below. | |||||
You can set the `RunMode` either by specifying it individually via | |||||
the `CommandAttribute` or by setting the global default with | |||||
the [DefaultRunMode] flag under `CommandServiceConfig`. | |||||
# [CommandAttribute](#tab/cmdattrib) | |||||
[!code-csharp[Command Attribute](samples/runmode-cmdattrib.cs)] | |||||
# [CommandServiceConfig](#tab/cmdconfig) | |||||
[!code-csharp[Command Service Config](samples/runmode-cmdconfig.cs)] | |||||
*** | |||||
*** | |||||
[RunMode]: xref:Discord.Commands.RunMode | |||||
[CommandAttribute]: xref:Discord.Commands.CommandAttribute | |||||
[DefaultRunMode]: xref:Discord.Commands.CommandServiceConfig.DefaultRunMode | |||||
## How does `RunMode.Async` work, and why is Discord.Net *not* using it by default? | |||||
`RunMode.Async` works by spawning a new `Task` with an unawaited | |||||
[Task.Run], essentially making the task that is used to invoke the | |||||
command task to be finished on a different thread. This design means | |||||
that [ExecuteAsync] will be forced to return a successful | |||||
[ExecuteResult] regardless of the actual execution result. | |||||
The following are the known caveats with `RunMode.Async`, | |||||
1. You can potentially introduce a race condition. | |||||
2. Unnecessary overhead caused by the [async state machine]. | |||||
3. [ExecuteAsync] will immediately return [ExecuteResult] instead of | |||||
other result types (this is particularly important for those who wish | |||||
to utilize [RuntimeResult] in 2.0). | |||||
4. Exceptions are swallowed in the `ExecuteAsync` result. | |||||
However, there are ways to remedy some of these. | |||||
For #3, in Discord.Net 2.0, the library introduces a new event called | |||||
[CommandService.CommandExecuted], which is raised whenever the command is executed. | |||||
This event will be raised regardless of | |||||
the `RunMode` type and will return the appropriate execution result | |||||
and the associated @Discord.Commands.CommandInfo if applicable. | |||||
For #4, exceptions are caught in [CommandService.Log] event under | |||||
[LogMessage.Exception] as [CommandException] and in the | |||||
[CommandService.CommandExecuted] event under the [IResult] as | |||||
[ExecuteResult.Exception]. | |||||
[Task.Run]: https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.run | |||||
[async state machine]: https://www.red-gate.com/simple-talk/dotnet/net-tools/c-async-what-is-it-and-how-does-it-work/ | |||||
[ExecuteAsync]: xref:Discord.Commands.CommandService.ExecuteAsync* | |||||
[ExecuteResult]: xref:Discord.Commands.ExecuteResult | |||||
[RuntimeResult]: xref:Discord.Commands.RuntimeResult | |||||
[CommandService.CommandExecuted]: xref:Discord.Commands.CommandService.CommandExecuted | |||||
[CommandService.Log]: xref:Discord.Commands.CommandService.Log | |||||
[LogMessage.Exception]: xref:Discord.LogMessage.Exception* | |||||
[ExecuteResult.Exception]: xref:Discord.Commands.ExecuteResult.Exception* | |||||
[CommandException]: xref:Discord.Commands.CommandException | |||||
[IResult]: xref:Discord.Commands.IResult |
@@ -1,28 +0,0 @@ | |||||
public class MyService | |||||
{ | |||||
public string MyCoolString { get; set; } | |||||
} | |||||
public class Setup | |||||
{ | |||||
public IServiceProvider BuildProvider() => | |||||
new ServiceCollection() | |||||
.AddSingleton<MyService>() | |||||
.BuildServiceProvider(); | |||||
} | |||||
public class MyModule : ModuleBase<SocketCommandContext> | |||||
{ | |||||
// Inject via public settable prop | |||||
public MyService MyService { get; set; } | |||||
// ...or via the module's constructor | |||||
// private readonly MyService _myService; | |||||
// public MyModule (MyService myService) => _myService = myService; | |||||
[Command("string")] | |||||
public Task GetOrSetStringAsync(string input) | |||||
{ | |||||
if (string.IsNullOrEmpty(_myService.MyCoolString)) _myService.MyCoolString = input; | |||||
return ReplyAsync(_myService.MyCoolString); | |||||
} | |||||
} |
@@ -1,20 +0,0 @@ | |||||
// Input: | |||||
// !echo Coffee Cake | |||||
// Output: | |||||
// Coffee Cake | |||||
[Command("echo")] | |||||
public Task EchoRemainderAsync([Remainder]string text) => ReplyAsync(text); | |||||
// Output: | |||||
// CommandError.BadArgCount | |||||
[Command("echo-hassle")] | |||||
public Task EchoAsync(string text) => ReplyAsync(text); | |||||
// The message would be seen as having multiple parameters, | |||||
// while the method only accepts one. | |||||
// Wrapping the message in quotes solves this. | |||||
// This way, the system knows the entire message is to be parsed as a | |||||
// single String. | |||||
// e.g., | |||||
// !echo "Coffee Cake" |
@@ -1,29 +0,0 @@ | |||||
public class MyModule : ModuleBase<SocketCommandContext> | |||||
{ | |||||
private readonly DatabaseService _dbService; | |||||
public MyModule(DatabaseService dbService) | |||||
=> _dbService = dbService; | |||||
} | |||||
public class CommandHandler | |||||
{ | |||||
private readonly CommandService _commands; | |||||
private readonly IServiceProvider _services; | |||||
public CommandHandler(DiscordSocketClient client) | |||||
{ | |||||
_services = new ServiceCollection() | |||||
.AddService<CommandService>() | |||||
.AddService(client) | |||||
// We are missing DatabaseService! | |||||
.BuildServiceProvider(); | |||||
} | |||||
public async Task RegisterCommandsAsync() | |||||
{ | |||||
// ... | |||||
// The method fails here because DatabaseService is a required | |||||
// dependency and cannot be resolved by the dependency | |||||
// injection service at runtime since the service is not | |||||
// registered in this instance of _services. | |||||
await _commands.AddModulesAsync(Assembly.GetEntryAssembly(), _services); | |||||
// ... | |||||
} | |||||
} |
@@ -1,7 +0,0 @@ | |||||
[Command("process", RunMode = RunMode.Async)] | |||||
public async Task ProcessAsync(string input) | |||||
{ | |||||
// Does heavy calculation here. | |||||
await Task.Delay(TimeSpan.FromMinute(1)); | |||||
await ReplyAsync(input); | |||||
} |
@@ -1,10 +0,0 @@ | |||||
public class Setup | |||||
{ | |||||
private readonly CommandService _command; | |||||
public Setup() | |||||
{ | |||||
var config = new CommandServiceConfig{ DefaultRunMode = RunMode.Async }; | |||||
_command = new CommandService(config); | |||||
} | |||||
} |
@@ -1,82 +0,0 @@ | |||||
--- | |||||
uid: FAQ.Glossary | |||||
title: Common Terminologies / Glossary | |||||
--- | |||||
# Glossary | |||||
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. | |||||
## 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) | |||||
[IGuild]: xref:Discord.IGuild | |||||
[IChannel]: xref:Discord.IChannel | |||||
## Channel Types | |||||
### Message Channels | |||||
* A **Text Channel** ([ITextChannel]) is a message channel from a | |||||
Guild. | |||||
* A **DM Channel** ([IDMChannel]) is a message channel from a DM. | |||||
* A **Group Channel** ([IGroupChannel]) is a message channel from a | |||||
Group. | |||||
- This is rarely used due to the bot's inability to join groups. | |||||
* A **Private Channel** ([IPrivateChannel]) is a DM or a Group. | |||||
* A **Message Channel** ([IMessageChannel]) can be any of the above. | |||||
### Misc Channels | |||||
* A **Guild Channel** ([IGuildChannel]) is a guild channel in a guild. | |||||
- This can be any channels that may exist in a guild. | |||||
* A **Voice Channel** ([IVoiceChannel]) is a voice channel in a guild. | |||||
* A **Category Channel** ([ICategoryChannel]) (2.0+) is a category that | |||||
holds one or more sub-channels. | |||||
* A **Nested Channel** ([INestedChannel]) (2.0+) is a channel that can | |||||
exist under a category. | |||||
[INestedChannel]: xref:Discord.INestedChannel | |||||
[IGuildChannel]: xref:Discord.IGuildChannel | |||||
[IMessageChannel]: xref:Discord.IMessageChannel | |||||
[ITextChannel]: xref:Discord.ITextChannel | |||||
[IGroupChannel]: xref:Discord.IGroupChannel | |||||
[IDMChannel]: xref:Discord.IDMChannel | |||||
[IPrivateChannel]: xref:Discord.IPrivateChannel | |||||
[IVoiceChannel]: xref:Discord.IVoiceChannel | |||||
[ICategoryChannel]: xref:Discord.ICategoryChannel | |||||
## Emoji Types | |||||
* An **Emote** ([Emote]) is a custom emote from a guild. | |||||
- Example: `<:dotnet:232902710280716288>` | |||||
* An **Emoji** ([Emoji]) is a Unicode emoji. | |||||
- Example: `👍` | |||||
[Emote]: xref:Discord.Emote | |||||
[Emoji]: xref:Discord.Emoji | |||||
## Activity Types | |||||
* A **Game** ([Game]) refers to a user's game activity. | |||||
* A **Rich Presence** ([RichGame]) refers to a user's detailed | |||||
gameplay status. | |||||
- Visit [Rich Presence Intro] on Discord docs for more info. | |||||
* A **Streaming Status** ([StreamingGame]) refers to user's activity | |||||
for streaming on services such as Twitch. | |||||
* A **Spotify Status** ([SpotifyGame]) (2.0+) refers to a user's | |||||
activity for listening to a song on Spotify. | |||||
[Game]: xref:Discord.Game | |||||
[RichGame]: xref:Discord.RichGame | |||||
[StreamingGame]: xref:Discord.StreamingGame | |||||
[SpotifyGame]: xref:Discord.SpotifyGame | |||||
[Rich Presence Intro]: https://discordapp.com/developers/docs/rich-presence/best-practices |
@@ -1,29 +0,0 @@ | |||||
--- | |||||
uid: FAQ.Legacy | |||||
title: Questions about Legacy Versions | |||||
--- | |||||
# Legacy Questions | |||||
This section refers to legacy library-related questions that do not | |||||
apply to the latest or recent version of the Discord.Net library. | |||||
## X, Y, Z does not work! It doesn't return a valid value anymore. | |||||
If you are currently using an older version of the stable branch, | |||||
please upgrade to the latest pre-release version to ensure maximum | |||||
compatibility. Several features may be broken in older | |||||
versions and will likely not be fixed in the version branch due to | |||||
their breaking nature. | |||||
Visit the repo's [release tag] to see the latest public pre-release. | |||||
[release tag]: https://github.com/RogueException/Discord.Net/releases | |||||
## I came from an earlier version of Discord.Net 1.0, and DependencyMap doesn't seem to exist anymore in the later revision? What happened to it? | |||||
The `DependencyMap` has been replaced with Microsoft's | |||||
[DependencyInjection] Abstractions. An example usage can be seen | |||||
[here](https://github.com/foxbot/DiscordBotBase/blob/csharp/src/DiscordBot/Program.cs#L36). | |||||
[DependencyInjection]: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection |
@@ -1,18 +0,0 @@ | |||||
- name: Basic Concepts | |||||
items: | |||||
- name: Getting Started | |||||
topicUid: FAQ.Basics.GetStarted | |||||
- name: Basic Operations | |||||
topicUid: FAQ.Basics.BasicOp | |||||
- name: Client Basics | |||||
topicUid: FAQ.Basics.ClientBasics | |||||
- name: Commands | |||||
items: | |||||
- name: General | |||||
topicUid: FAQ.Commands.General | |||||
- name: Dependency Injection | |||||
topicUid: FAQ.Commands.DI | |||||
- name: Glossary | |||||
topicUid: FAQ.Glossary | |||||
- name: Legacy or Upgrade | |||||
topicUid: FAQ.Legacy |
@@ -1,7 +0,0 @@ | |||||
apiRules: | |||||
- exclude: | |||||
uidRegex: ^Discord\.Net\..*$ | |||||
type: Namespace | |||||
- exclude: | |||||
uidRegex: ^Discord\.Analyzers$ | |||||
type: Namespace |
@@ -1,47 +0,0 @@ | |||||
--- | |||||
uid: Guides.Commands.DI | |||||
title: Dependency Injection | |||||
--- | |||||
# Dependency Injection | |||||
The Command Service is bundled with a very barebone Dependency | |||||
Injection service for your convenience. It is recommended that you use | |||||
DI when writing your modules. | |||||
## Setup | |||||
1. Create a @Microsoft.Extensions.DependencyInjection.ServiceCollection. | |||||
2. Add the dependencies to the service collection that you wish | |||||
to use in the modules. | |||||
3. Build the service collection into a service provider. | |||||
4. Pass the service collection into @Discord.Commands.CommandService.AddModulesAsync* / @Discord.Commands.CommandService.AddModuleAsync* , @Discord.Commands.CommandService.ExecuteAsync* . | |||||
### Example - Setting up Injection | |||||
[!code-csharp[IServiceProvider Setup](samples/dependency-injection/dependency_map_setup.cs)] | |||||
## Usage in Modules | |||||
In the constructor of your module, any parameters will be filled in by | |||||
the @System.IServiceProvider that you've passed. | |||||
Any publicly settable properties will also be filled in the same | |||||
manner. | |||||
> [!NOTE] | |||||
> Annotating a property with a [DontInjectAttribute] attribute will | |||||
> prevent the property from being injected. | |||||
> [!NOTE] | |||||
> If you accept `CommandService` or `IServiceProvider` as a parameter | |||||
> in your constructor or as an injectable property, these entries will | |||||
> be filled by the `CommandService` that the module is loaded from and | |||||
> the `IServiceProvider` that is passed into it respectively. | |||||
### Example - Injection in Modules | |||||
[!code-csharp[Injection Modules](samples/dependency-injection/dependency_module.cs)] | |||||
[!code-csharp[Disallow Dependency Injection](samples/dependency-injection/dependency_module_noinject.cs)] | |||||
[DontInjectAttribute]: xref:Discord.Commands.DontInjectAttribute |
@@ -1,221 +0,0 @@ | |||||
--- | |||||
uid: Guides.Commands.Intro | |||||
title: Introduction to Command Service | |||||
--- | |||||
# The Command Service | |||||
[Discord.Commands](xref:Discord.Commands) provides an attribute-based | |||||
command parser. | |||||
## Get Started | |||||
To use commands, you must create a [Command Service] and a command | |||||
handler. | |||||
Included below is a barebone command handler. You can extend your | |||||
command handler as much as you like; however, the below is the bare | |||||
minimum. | |||||
> [!NOTE] | |||||
> The `CommandService` will optionally accept a [CommandServiceConfig], | |||||
> which *does* set a few default values for you. It is recommended to | |||||
> look over the properties in [CommandServiceConfig] and their default | |||||
> values. | |||||
[!code-csharp[Command Handler](samples/intro/command_handler.cs)] | |||||
[Command Service]: xref:Discord.Commands.CommandService | |||||
[CommandServiceConfig]: xref:Discord.Commands.CommandServiceConfig | |||||
## With Attributes | |||||
Starting from 1.0, commands can be defined ahead of time with | |||||
attributes, or at runtime with builders. | |||||
For most bots, ahead-of-time commands should be all you need, and this | |||||
is the recommended method of defining commands. | |||||
### Modules | |||||
The first step to creating commands is to create a _module_. | |||||
A module is an organizational pattern that allows you to write your | |||||
commands in different classes and have them automatically loaded. | |||||
Discord.Net's implementation of "modules" is influenced heavily by the | |||||
ASP.NET Core's Controller pattern. This means that the lifetime of a | |||||
module instance is only as long as the command is being invoked. | |||||
Before we create a module, it is **crucial** for you to remember that | |||||
in order to create a module and have it automatically discovered, | |||||
your module must: | |||||
* Be public | |||||
* Inherit [ModuleBase] | |||||
By now, your module should look like this: | |||||
[!code-csharp[Empty Module](samples/intro/empty-module.cs)] | |||||
> [!NOTE] | |||||
> [ModuleBase] is an `abstract` class, meaning that you may extend it | |||||
> or override it as you see fit. Your module may inherit from any | |||||
> extension of ModuleBase. | |||||
[IoC]: https://msdn.microsoft.com/en-us/library/ff921087.aspx | |||||
[Dependency Injection]: https://msdn.microsoft.com/en-us/library/ff921152.aspx | |||||
[ModuleBase]: xref:Discord.Commands.ModuleBase`1 | |||||
### Adding/Creating Commands | |||||
> [!WARNING] | |||||
> **Avoid using long-running code** in your modules wherever possible. | |||||
> You should **not** be implementing very much logic into your | |||||
> modules, instead, outsource to a service for that. | |||||
> | |||||
> If you are unfamiliar with Inversion of Control, it is recommended | |||||
> to read the MSDN article on [IoC] and [Dependency Injection]. | |||||
The next step to creating commands is actually creating the commands. | |||||
For a command to be valid, it **must** have a return type of `Task` | |||||
or `Task<RuntimeResult>`. Typically, you might want to mark this | |||||
method as `async`, although it is not required. | |||||
Then, flag your command with the [CommandAttribute]. Note that you must | |||||
specify a name for this command, except for when it is part of a | |||||
[Module Group](#module-groups). | |||||
### Command Parameters | |||||
Adding parameters to a command is done by adding parameters to the | |||||
parent `Task`. | |||||
For example: | |||||
* To take an integer as an argument from the user, add `int num`. | |||||
* To take a user as an argument from the user, add `IUser user`. | |||||
* ...etc. | |||||
Starting from 1.0, a command can accept nearly any type of argument; | |||||
a full list of types that are parsed by default can | |||||
be found in @Guides.Commands.TypeReaders. | |||||
[CommandAttribute]: xref:Discord.Commands.CommandAttribute | |||||
#### Optional Parameters | |||||
Parameters, by default, are always required. To make a parameter | |||||
optional, give it a default value (i.e., `int num = 0`). | |||||
#### Parameters with Spaces | |||||
To accept a comma-separated list, set the parameter to `params Type[]`. | |||||
Should a parameter include spaces, the parameter **must** be | |||||
wrapped in quotes. For example, for a command with a parameter | |||||
`string food`, you would execute it with | |||||
`!favoritefood "Key Lime Pie"`. | |||||
If you would like a parameter to parse until the end of a command, | |||||
flag the parameter with the [RemainderAttribute]. This will | |||||
allow a user to invoke a command without wrapping a | |||||
parameter in quotes. | |||||
[RemainderAttribute]: xref:Discord.Commands.RemainderAttribute | |||||
### Command Overloads | |||||
You may add overloads to your commands, and the command parser will | |||||
automatically pick up on it. | |||||
If, for whatever reason, you have two commands which are ambiguous to | |||||
each other, you may use the @Discord.Commands.PriorityAttribute to | |||||
specify which should be tested before the other. | |||||
The `Priority` attributes are sorted in ascending order; the higher | |||||
priority will be called first. | |||||
### Command Context | |||||
Every command can access the execution context through the [Context] | |||||
property on [ModuleBase]. `ICommandContext` allows you to access the | |||||
message, channel, guild, user, and the underlying Discord client | |||||
that the command was invoked from. | |||||
Different types of `Context` may be specified using the generic variant | |||||
of [ModuleBase]. When using a [SocketCommandContext], for example, the | |||||
properties on this context will already be Socket entities, so you | |||||
will not need to cast them. | |||||
To reply to messages, you may also invoke [ReplyAsync], instead of | |||||
accessing the channel through the [Context] and sending a message. | |||||
> [!WARNING] | |||||
> Contexts should **NOT** be mixed! You cannot have one module that | |||||
> uses `CommandContext` and another that uses `SocketCommandContext`. | |||||
[Context]: xref:Discord.Commands.ModuleBase`1.Context | |||||
[SocketCommandContext]: xref:Discord.Commands.SocketCommandContext | |||||
[ReplyAsync]: xref:Discord.Commands.ModuleBase`1.ReplyAsync* | |||||
> [!TIP] | |||||
> At this point, your module should look comparable to this example: | |||||
> [!code-csharp[Example Module](samples/intro/module.cs)] | |||||
#### Loading Modules Automatically | |||||
The Command Service can automatically discover all classes in an | |||||
`Assembly` that inherit [ModuleBase] and load them. Invoke | |||||
[CommandService.AddModulesAsync] to discover modules and | |||||
install them. | |||||
To opt a module out of auto-loading, flag it with | |||||
[DontAutoLoadAttribute]. | |||||
[DontAutoLoadAttribute]: xref:Discord.Commands.DontAutoLoadAttribute | |||||
[CommandService.AddModulesAsync]: xref:Discord.Commands.CommandService.AddModulesAsync* | |||||
#### Loading Modules Manually | |||||
To manually load a module, invoke [CommandService.AddModuleAsync] by | |||||
passing in the generic type of your module and optionally, a | |||||
service provider. | |||||
[CommandService.AddModuleAsync]: xref:Discord.Commands.CommandService.AddModuleAsync* | |||||
### Module Constructors | |||||
Modules are constructed using @Guides.Commands.DI. Any parameters | |||||
that are placed in the Module's constructor must be injected into an | |||||
@System.IServiceProvider first. | |||||
> [!TIP] | |||||
> Alternatively, you may accept an | |||||
> `IServiceProvider` as an argument and extract services yourself, | |||||
> although this is discouraged. | |||||
### Module Properties | |||||
Modules with `public` settable properties will have the dependencies | |||||
injected after the construction of the module. See @Guides.Commands.DI | |||||
to learn more. | |||||
### Module Groups | |||||
Module Groups allow you to create a module where commands are | |||||
prefixed. To create a group, flag a module with the | |||||
@Discord.Commands.GroupAttribute. | |||||
Module Groups also allow you to create **nameless Commands**, where | |||||
the [CommandAttribute] is configured with no name. In this case, the | |||||
command will inherit the name of the group it belongs to. | |||||
### Submodules | |||||
Submodules are "modules" that reside within another one. Typically, | |||||
submodules are used to create nested groups (although not required to | |||||
create nested groups). | |||||
[!code-csharp[Groups and Submodules](samples/intro/groups.cs)] |
@@ -1,120 +0,0 @@ | |||||
--- | |||||
uid: Guides.Commands.PostExecution | |||||
title: Post-command Execution Handling | |||||
--- | |||||
# Post-execution Handling for Commands | |||||
When developing commands, you may want to consider building a | |||||
post-execution handling system so you can have finer control | |||||
over commands. Discord.Net offers several post-execution workflows | |||||
for you to work with. | |||||
If you recall, in the [Command Guide], we have shown the following | |||||
example for executing and handling commands, | |||||
[!code[Command Handler](samples/intro/command_handler.cs)] | |||||
You may notice that after we perform [ExecuteAsync], we store the | |||||
result and print it to the chat, essentially creating the most | |||||
fundamental form of a post-execution handler. | |||||
With this in mind, we could start doing things like the following, | |||||
[!code[Basic Command Handler](samples/post-execution/post-execution_basic.cs)] | |||||
However, this may not always be preferred, because you are | |||||
creating your post-execution logic *with* the essential command | |||||
handler. This design could lead to messy code and could potentially | |||||
be a violation of the SRP (Single Responsibility Principle). | |||||
Another major issue is if your command is marked with | |||||
`RunMode.Async`, [ExecuteAsync] will **always** return a successful | |||||
[ExecuteResult] instead of the actual result. You can learn more | |||||
about the impact in @FAQ.Commands.General. | |||||
## CommandExecuted Event | |||||
Enter [CommandExecuted], an event that was introduced in | |||||
Discord.Net 2.0. This event is raised whenever a command is | |||||
executed regardless of its execution status. This means this | |||||
event can be used to streamline your post-execution design, | |||||
is not prone to `RunMode.Async`'s [ExecuteAsync] drawbacks. | |||||
Thus, we can begin working on code such as: | |||||
[!code[CommandExecuted demo](samples/post-execution/command_executed_demo.cs)] | |||||
So now we have a streamlined post-execution pipeline, great! What's | |||||
next? We can take this further by using [RuntimeResult]. | |||||
### RuntimeResult | |||||
`RuntimeResult` was initially introduced in 1.0 to allow | |||||
developers to centralize their command result logic. | |||||
In other words, it is a result type that is designed to be | |||||
returned when the command has finished its execution. | |||||
However, it wasn't widely adopted due to the aforementioned | |||||
[ExecuteAsync] drawback. Since we now have access to a proper | |||||
result-handler via the [CommandExecuted] event, we can start | |||||
making use of this class. | |||||
The best way to make use of it is to create your version of | |||||
`RuntimeResult`. You can achieve this by inheriting the `RuntimeResult` | |||||
class. | |||||
The following creates a bare-minimum required for a sub-class | |||||
of `RuntimeResult`, | |||||
[!code[Base Use](samples/post-execution/customresult_base.cs)] | |||||
The sky is the limit from here. You can add any additional information | |||||
you would like regarding the execution result. | |||||
For example, you may want to add your result type or other | |||||
helpful information regarding the execution, or something | |||||
simple like static methods to help you create return types easily. | |||||
[!code[Extended Use](samples/post-execution/customresult_extended.cs)] | |||||
After you're done creating your [RuntimeResult], you can | |||||
implement it in your command by marking the command return type to | |||||
`Task<RuntimeResult>`. | |||||
> [!NOTE] | |||||
> You must mark the return type as `Task<RuntimeResult>` instead of | |||||
> `Task<MyCustomResult>`. Only the former will be picked up when | |||||
> building the module. | |||||
Here's an example of a command that utilizes such logic: | |||||
[!code[Usage](samples/post-execution/customresult_usage.cs)] | |||||
And now we can check for it in our [CommandExecuted] handler: | |||||
[!code[Usage](samples/post-execution/command_executed_adv_demo.cs)] | |||||
## CommandService.Log Event | |||||
We have so far covered the handling of various result types, but we | |||||
have not talked about what to do if the command enters a catastrophic | |||||
failure (i.e., exceptions). To resolve this, we can make use of the | |||||
[CommandService.Log] event. | |||||
All exceptions thrown during a command execution are caught and sent | |||||
to the Log event under the [LogMessage.Exception] property | |||||
as a [CommandException] type. The [CommandException] class allows | |||||
us to access the exception thrown, as well as the context | |||||
of the command. | |||||
[!code[Logger Sample](samples/post-execution/command_exception_log.cs)] | |||||
[CommandException]: xref:Discord.Commands.CommandException | |||||
[LogMessage.Exception]: xref:Discord.LogMessage.Exception | |||||
[CommandService.Log]: xref:Discord.Commands.CommandService.Log | |||||
[RuntimeResult]: xref:Discord.Commands.RuntimeResult | |||||
[CommandExecuted]: xref:Discord.Commands.CommandService.CommandExecuted | |||||
[ExecuteAsync]: xref:Discord.Commands.CommandService.ExecuteAsync* | |||||
[ExecuteResult]: xref:Discord.Commands.ExecuteResult | |||||
[Command Guide]: xref:Guides.Commands.Intro |
@@ -1,83 +0,0 @@ | |||||
--- | |||||
uid: Guides.Commands.Preconditions | |||||
title: Preconditions | |||||
--- | |||||
# Preconditions | |||||
Preconditions serve as a permissions system for your Commands. Keep in | |||||
mind, however, that they are not limited to _just_ permissions and can | |||||
be as complex as you want them to be. | |||||
There are two types of Preconditions you can use: | |||||
* [PreconditionAttribute] can be applied to Modules, Groups, or Commands. | |||||
* [ParameterPreconditionAttribute] can be applied to Parameters. | |||||
You may visit their respective API documentation to find out more. | |||||
[PreconditionAttribute]: xref:Discord.Commands.PreconditionAttribute | |||||
[ParameterPreconditionAttribute]: xref:Discord.Commands.ParameterPreconditionAttribute | |||||
## Bundled Preconditions | |||||
@Discord.Commands ships with several bundled Preconditions for you | |||||
to use. | |||||
* @Discord.Commands.RequireContextAttribute | |||||
* @Discord.Commands.RequireOwnerAttribute | |||||
* @Discord.Commands.RequireBotPermissionAttribute | |||||
* @Discord.Commands.RequireUserPermissionAttribute | |||||
* @Discord.Commands.RequireNsfwAttribute | |||||
## Using Preconditions | |||||
To use a precondition, simply apply any valid precondition candidate to | |||||
a command method signature as an attribute. | |||||
### Example - Using a Precondition | |||||
[!code-csharp[Precondition usage](samples/preconditions/precondition_usage.cs)] | |||||
## ORing Preconditions | |||||
When writing commands, you may want to allow some of them to be | |||||
executed when only some of the precondition checks are passed. | |||||
This is where the [Group] property of a precondition attribute comes in | |||||
handy. By assigning two or more preconditions to a group, the command | |||||
system will allow the command to be executed when one of the | |||||
precondition passes. | |||||
### Example - ORing Preconditions | |||||
[!code-csharp[OR Precondition](samples/preconditions/group_precondition.cs)] | |||||
[Group]: xref:Discord.Commands.PreconditionAttribute.Group | |||||
## Custom Preconditions | |||||
To write your own Precondition, create a new class that inherits from | |||||
either [PreconditionAttribute] or [ParameterPreconditionAttribute] | |||||
depending on your use. | |||||
In order for your Precondition to function, you will need to override | |||||
the [CheckPermissionsAsync] method. | |||||
If the context meets the required parameters, return | |||||
[PreconditionResult.FromSuccess], otherwise return | |||||
[PreconditionResult.FromError] and include an error message if | |||||
necessary. | |||||
> [!NOTE] | |||||
> Visual Studio can help you implement missing members | |||||
> from the abstract class by using the "Implement Abstract Class" | |||||
> IntelliSense hint. | |||||
### Example - Creating a Custom Precondition | |||||
[!code-csharp[Custom Precondition](samples/preconditions/require_role.cs)] | |||||
[CheckPermissionsAsync]: xref:Discord.Commands.PreconditionAttribute.CheckPermissionsAsync* | |||||
[PreconditionResult.FromSuccess]: xref:Discord.Commands.PreconditionResult.FromSuccess* | |||||
[PreconditionResult.FromError]: xref:Discord.Commands.PreconditionResult.FromError* |
@@ -1,62 +0,0 @@ | |||||
public class Initialize | |||||
{ | |||||
private readonly CommandService _commands; | |||||
private readonly DiscordSocketClient _client; | |||||
public Initialize(CommandService commands = null, DiscordSocketClient client = null) | |||||
{ | |||||
_commands = commands ?? new CommandService(); | |||||
_client = client ?? new DiscordSocketClient(); | |||||
} | |||||
public IServiceProvider BuildServiceProvider() => new ServiceCollection() | |||||
.AddSingleton(_client) | |||||
.AddSingleton(_commands) | |||||
// You can pass in an instance of the desired type | |||||
.AddSingleton(new NotificationService()) | |||||
// ...or by using the generic method. | |||||
// | |||||
// The benefit of using the generic method is that | |||||
// ASP.NET DI will attempt to inject the required | |||||
// dependencies that are specified under the constructor | |||||
// for us. | |||||
.AddSingleton<DatabaseService>() | |||||
.AddSingleton<CommandHandler>() | |||||
.BuildServiceProvider(); | |||||
} | |||||
public class CommandHandler | |||||
{ | |||||
private readonly DiscordSocketClient _client; | |||||
private readonly CommandService _commands; | |||||
private readonly IServiceProvider _services; | |||||
public CommandHandler(IServiceProvider services, CommandService commands, DiscordSocketClient client) | |||||
{ | |||||
_commands = commands; | |||||
_services = services; | |||||
_client = client; | |||||
} | |||||
public async Task InitializeAsync() | |||||
{ | |||||
// Pass the service provider to the second parameter of | |||||
// AddModulesAsync to inject dependencies to all modules | |||||
// that may require them. | |||||
await _commands.AddModulesAsync( | |||||
assembly: Assembly.GetEntryAssembly(), | |||||
services: _services); | |||||
_client.MessageReceived += HandleCommandAsync; | |||||
} | |||||
public async Task HandleCommandAsync(SocketMessage msg) | |||||
{ | |||||
// ... | |||||
// Pass the service provider to the ExecuteAsync method for | |||||
// precondition checks. | |||||
await _commands.ExecuteAsync( | |||||
context: context, | |||||
argPos: argPos, | |||||
services: _services); | |||||
// ... | |||||
} | |||||
} |
@@ -1,37 +0,0 @@ | |||||
// After setting up dependency injection, modules will need to request | |||||
// the dependencies to let the library know to pass | |||||
// them along during execution. | |||||
// Dependency can be injected in two ways with Discord.Net. | |||||
// You may inject any required dependencies via... | |||||
// the module constructor | |||||
// -or- | |||||
// public settable properties | |||||
// Injection via constructor | |||||
public class DatabaseModule : ModuleBase<SocketCommandContext> | |||||
{ | |||||
private readonly DatabaseService _database; | |||||
public DatabaseModule(DatabaseService database) | |||||
{ | |||||
_database = database; | |||||
} | |||||
[Command("read")] | |||||
public async Task ReadFromDbAsync() | |||||
{ | |||||
await ReplyAsync(_database.GetData()); | |||||
} | |||||
} | |||||
// Injection via public settable properties | |||||
public class DatabaseModule : ModuleBase<SocketCommandContext> | |||||
{ | |||||
public DatabaseService DbService { get; set; } | |||||
[Command("read")] | |||||
public async Task ReadFromDbAsync() | |||||
{ | |||||
await ReplyAsync(_database.GetData()); | |||||
} | |||||
} |
@@ -1,29 +0,0 @@ | |||||
// Sometimes injecting dependencies automatically with the provided | |||||
// methods in the prior example may not be desired. | |||||
// You may explicitly tell Discord.Net to **not** inject the properties | |||||
// by either... | |||||
// restricting the access modifier | |||||
// -or- | |||||
// applying DontInjectAttribute to the property | |||||
// Restricting the access modifier of the property | |||||
public class ImageModule : ModuleBase<SocketCommandContext> | |||||
{ | |||||
public ImageService ImageService { get; } | |||||
public ImageModule() | |||||
{ | |||||
ImageService = new ImageService(); | |||||
} | |||||
} | |||||
// Applying DontInjectAttribute | |||||
public class ImageModule : ModuleBase<SocketCommandContext> | |||||
{ | |||||
[DontInject] | |||||
public ImageService ImageService { get; set; } | |||||
public ImageModule() | |||||
{ | |||||
ImageService = new ImageService(); | |||||
} | |||||
} |
@@ -1,64 +0,0 @@ | |||||
public class CommandHandler | |||||
{ | |||||
private readonly DiscordSocketClient _client; | |||||
private readonly CommandService _commands; | |||||
public CommandHandler(DiscordSocketClient client, CommandService commands) | |||||
{ | |||||
_commands = commands; | |||||
_client = client; | |||||
} | |||||
public async Task InstallCommandsAsync() | |||||
{ | |||||
// Hook the MessageReceived event into our command handler | |||||
_client.MessageReceived += HandleCommandAsync; | |||||
// Here we discover all of the command modules in the entry | |||||
// assembly and load them. Starting from Discord.NET 2.0, a | |||||
// service provider is required to be passed into the | |||||
// module registration method to inject the | |||||
// required dependencies. | |||||
// | |||||
// If you do not use Dependency Injection, pass null. | |||||
// See Dependency Injection guide for more information. | |||||
await _commands.AddModulesAsync(assembly: Assembly.GetEntryAssembly(), | |||||
services: null); | |||||
} | |||||
private async Task HandleCommandAsync(SocketMessage messageParam) | |||||
{ | |||||
// Don't process the command if it was a system message | |||||
var message = messageParam as SocketUserMessage; | |||||
if (message == null) return; | |||||
// Create a number to track where the prefix ends and the command begins | |||||
int argPos = 0; | |||||
// Determine if the message is a command based on the prefix and make sure no bots trigger commands | |||||
if (!(message.HasCharPrefix('!', ref argPos) || | |||||
message.HasMentionPrefix(_client.CurrentUser, ref argPos)) || | |||||
message.Author.IsBot) | |||||
return; | |||||
// Create a WebSocket-based command context based on the message | |||||
var context = new SocketCommandContext(_client, message); | |||||
// Execute the command with the command context we just | |||||
// created, along with the service provider for precondition checks. | |||||
// Keep in mind that result does not indicate a return value | |||||
// rather an object stating if the command executed successfully. | |||||
var result = await _commands.ExecuteAsync( | |||||
context: context, | |||||
argPos: argPos, | |||||
services: null); | |||||
// Optionally, we may inform the user if the command fails | |||||
// to be executed; however, this may not always be desired, | |||||
// as it may clog up the request queue should a user spam a | |||||
// command. | |||||
// if (!result.IsSuccess) | |||||
// await context.Channel.SendMessageAsync(result.ErrorReason); | |||||
} | |||||
} |
@@ -1,8 +0,0 @@ | |||||
using Discord.Commands; | |||||
// Keep in mind your module **must** be public and inherit ModuleBase. | |||||
// If it isn't, it will not be discovered by AddModulesAsync! | |||||
public class InfoModule : ModuleBase<SocketCommandContext> | |||||
{ | |||||
} |
@@ -1,25 +0,0 @@ | |||||
[Group("admin")] | |||||
public class AdminModule : ModuleBase<SocketCommandContext> | |||||
{ | |||||
[Group("clean")] | |||||
public class CleanModule : ModuleBase<SocketCommandContext> | |||||
{ | |||||
// ~admin clean | |||||
[Command] | |||||
public async Task DefaultCleanAsync() | |||||
{ | |||||
// ... | |||||
} | |||||
// ~admin clean messages 15 | |||||
[Command("messages")] | |||||
public async Task CleanAsync(int count) | |||||
{ | |||||
// ... | |||||
} | |||||
} | |||||
// ~admin ban foxbot#0282 | |||||
[Command("ban")] | |||||
public Task BanAsync(IGuildUser user) => | |||||
Context.Guild.AddBanAsync(user); | |||||
} |
@@ -1,45 +0,0 @@ | |||||
// Create a module with no prefix | |||||
public class InfoModule : ModuleBase<SocketCommandContext> | |||||
{ | |||||
// ~say hello world -> hello world | |||||
[Command("say")] | |||||
[Summary("Echoes a message.")] | |||||
public Task SayAsync([Remainder] [Summary("The text to echo")] string echo) | |||||
=> ReplyAsync(echo); | |||||
// ReplyAsync is a method on ModuleBase | |||||
} | |||||
// Create a module with the 'sample' prefix | |||||
[Group("sample")] | |||||
public class SampleModule : ModuleBase<SocketCommandContext> | |||||
{ | |||||
// ~sample square 20 -> 400 | |||||
[Command("square")] | |||||
[Summary("Squares a number.")] | |||||
public async Task SquareAsync( | |||||
[Summary("The number to square.")] | |||||
int num) | |||||
{ | |||||
// We can also access the channel from the Command Context. | |||||
await Context.Channel.SendMessageAsync($"{num}^2 = {Math.Pow(num, 2)}"); | |||||
} | |||||
// ~sample userinfo --> foxbot#0282 | |||||
// ~sample userinfo @Khionu --> Khionu#8708 | |||||
// ~sample userinfo Khionu#8708 --> Khionu#8708 | |||||
// ~sample userinfo Khionu --> Khionu#8708 | |||||
// ~sample userinfo 96642168176807936 --> Khionu#8708 | |||||
// ~sample whois 96642168176807936 --> Khionu#8708 | |||||
[Command("userinfo")] | |||||
[Summary | |||||
("Returns info about the current user, or the user parameter, if one passed.")] | |||||
[Alias("user", "whois")] | |||||
public async Task UserInfoAsync( | |||||
[Summary("The (optional) user to get info from")] | |||||
SocketUser user = null) | |||||
{ | |||||
var userInfo = user ?? Context.Client.CurrentUser; | |||||
await ReplyAsync($"{userInfo.Username}#{userInfo.Discriminator}"); | |||||
} | |||||
} |
@@ -1,13 +0,0 @@ | |||||
public async Task LogAsync(LogMessage logMessage) | |||||
{ | |||||
// This casting type requries C#7 | |||||
if (logMessage.Exception is CommandException cmdException) | |||||
{ | |||||
// We can tell the user that something unexpected has happened | |||||
await cmdException.Context.Channel.SendMessageAsync("Something went catastrophically wrong!"); | |||||
// We can also log this incident | |||||
Console.WriteLine($"{cmdException.Context.User} failed to execute '{cmdException.Command.Name}' in {cmdException.Context.Channel}."); | |||||
Console.WriteLine(cmdException.ToString()); | |||||
} | |||||
} |
@@ -1,13 +0,0 @@ | |||||
public async Task OnCommandExecutedAsync(Optional<CommandInfo> command, ICommandContext context, IResult result) | |||||
{ | |||||
switch(result) | |||||
{ | |||||
case MyCustomResult customResult: | |||||
// do something extra with it | |||||
break; | |||||
default: | |||||
if (!string.IsNullOrEmpty(result.ErrorReason)) | |||||
await context.Channel.SendMessageAsync(result.ErrorReason); | |||||
break; | |||||
} | |||||
} |
@@ -1,38 +0,0 @@ | |||||
public async Task SetupAsync() | |||||
{ | |||||
await _command.AddModulesAsync(Assembly.GetEntryAssembly(), _services); | |||||
// Hook the execution event | |||||
_command.CommandExecuted += OnCommandExecutedAsync; | |||||
// Hook the command handler | |||||
_client.MessageReceived += HandleCommandAsync; | |||||
} | |||||
public async Task OnCommandExecutedAsync(Optional<CommandInfo> command, ICommandContext context, IResult result) | |||||
{ | |||||
// We have access to the information of the command executed, | |||||
// the context of the command, and the result returned from the | |||||
// execution in this event. | |||||
// We can tell the user what went wrong | |||||
if (!string.IsNullOrEmpty(result?.ErrorReason)) | |||||
{ | |||||
await context.Channel.SendMessageAsync(result.ErrorReason); | |||||
} | |||||
// ...or even log the result (the method used should fit into | |||||
// your existing log handler) | |||||
var commandName = command.IsSpecified ? command.Value.Name : "A command"; | |||||
await _log.LogAsync(new LogMessage(LogSeverity.Info, | |||||
"CommandExecution", | |||||
$"{commandName} was executed at {DateTime.UtcNow}.")); | |||||
} | |||||
public async Task HandleCommandAsync(SocketMessage msg) | |||||
{ | |||||
var message = messageParam as SocketUserMessage; | |||||
if (message == null) return; | |||||
int argPos = 0; | |||||
if (!(message.HasCharPrefix('!', ref argPos) || | |||||
message.HasMentionPrefix(_client.CurrentUser, ref argPos)) || | |||||
message.Author.IsBot) return; | |||||
var context = new SocketCommandContext(_client, message); | |||||
await _commands.ExecuteAsync(context, argPos, _services); | |||||
} |
@@ -1,6 +0,0 @@ | |||||
public class MyCustomResult : RuntimeResult | |||||
{ | |||||
public MyCustomResult(CommandError? error, string reason) : base(error, reason) | |||||
{ | |||||
} | |||||
} |
@@ -1,10 +0,0 @@ | |||||
public class MyCustomResult : RuntimeResult | |||||
{ | |||||
public MyCustomResult(CommandError? error, string reason) : base(error, reason) | |||||
{ | |||||
} | |||||
public static MyCustomResult FromError(string reason) => | |||||
new MyCustomResult(CommandError.Unsuccessful, reason); | |||||
public static MyCustomResult FromSuccess(string reason = null) => | |||||
new MyCustomResult(null, reason); | |||||
} |
@@ -1,10 +0,0 @@ | |||||
public class MyModule : ModuleBase<SocketCommandContext> | |||||
{ | |||||
[Command("eat")] | |||||
public async Task<RuntimeResult> ChooseAsync(string food) | |||||
{ | |||||
if (food == "salad") | |||||
return MyCustomResult.FromError("No, I don't want that!"); | |||||
return MyCustomResult.FromSuccess($"Give me the {food}!"). | |||||
} | |||||
} |
@@ -1,14 +0,0 @@ | |||||
// Bad code!!! | |||||
var result = await _commands.ExecuteAsync(context, argPos, _services); | |||||
if (result.CommandError != null) | |||||
switch(result.CommandError) | |||||
{ | |||||
case CommandError.BadArgCount: | |||||
await context.Channel.SendMessageAsync( | |||||
"Parameter count does not match any command's."); | |||||
break; | |||||
default: | |||||
await context.Channel.SendMessageAsync( | |||||
$"An error has occurred {result.ErrorReason}"); | |||||
break; | |||||
} |